Docker и Java: контейнеризация приложений от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему Docker важен для Java-разработчика?

Современная Java-разработка редко обходится без контейнеризации. Docker позволяет упаковать приложение вместе со всеми зависимостями, JVM и конфигурацией в изолированный контейнер. Это решает проблему «работает на моей машине» и упрощает CI/CD. В этой статье мы разберем полный цикл: от установки Docker до оптимизации образов для продакшена.

1. Основы Docker для Java

1.1 Что такое Docker и зачем он Java-проектам?

Docker — это платформа для создания, доставки и запуска приложений в контейнерах. Для Java это особенно актуально:

  • Изоляция версий JVM — можно использовать Java 11 для одного сервиса и Java 17 для другого на одном хосте.
  • Воспроизводимость — образ содержит точную версию JDK, библиотек и системных утилит.
  • Масштабирование — легко запускать несколько экземпляров через Kubernetes или Docker Swarm.

1.2 Установка Docker

Для начала установите Docker Desktop (Windows/Mac) или Docker Engine (Linux). Проверьте установку:

docker --version
docker info

2. Создание Dockerfile для Java-приложения

Рассмотрим простое Spring Boot приложение. Создадим файл Dockerfile в корне проекта.

2.1 Базовый Dockerfile

# Используем официальный образ OpenJDK
FROM openjdk:17-jdk-alpine

# Устанавливаем рабочую директорию
WORKDIR /app

# Копируем JAR-файл
COPY target/myapp.jar app.jar

# Открываем порт
EXPOSE 8080

# Команда запуска
ENTRYPOINT ["java", "-jar", "app.jar"]

2.2 Сборка и запуск контейнера

# Сборка образа
docker build -t my-java-app .

# Запуск контейнера
docker run -p 8080:8080 my-java-app

После запуска приложение будет доступно по адресу http://localhost:8080.

3. Оптимизация Docker-образов для Java

Большие образы замедляют развертывание. Рассмотрим ключевые техники оптимизации.

3.1 Многоступенчатая сборка (Multi-stage builds)

Позволяет разделить этап сборки и этап выполнения. В итоговый образ попадает только JAR, без Maven/Gradle и исходников.

# Этап сборки
FROM maven:3.8.5-openjdk-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

# Этап выполнения
FROM openjdk:17-jdk-alpine
WORKDIR /app
COPY --from=build /app/target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

3.2 Оптимизация слоев

Docker кэширует слои. Разделите копирование данных: сначала зависимости (меняются редко), потом код (меняется часто).

FROM maven:3.8.5-openjdk-17 AS build
WORKDIR /app
# Копируем только POM и скачиваем зависимости
COPY pom.xml .
RUN mvn dependency:go-offline
# Копируем исходники и собираем
COPY src ./src
RUN mvn package -DskipTests

FROM openjdk:17-jdk-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

3.3 Использование jlink для создания минимальной JRE

Если вы используете Java 9+, можно создать кастомную JRE только с нужными модулями.

FROM openjdk:17-slim AS jre-build
RUN jlink --add-modules java.base,java.logging,java.sql \
          --output /jre \
          --strip-debug \
          --no-man-pages \
          --no-header-files

FROM alpine:latest
COPY --from=jre-build /jre /jre
COPY target/app.jar /app.jar
ENTRYPOINT ["/jre/bin/java", "-jar", "/app.jar"]

Такой образ может весить менее 50 МБ вместо 300+ МБ.

4. Docker Compose для Java-микросервисов

Если у вас несколько сервисов (например, Spring Boot + PostgreSQL), используйте docker-compose.yml.

4.1 Пример docker-compose.yml

version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
      - SPRING_DATASOURCE_USERNAME=user
      - SPRING_DATASOURCE_PASSWORD=pass
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

4.2 Запуск всех сервисов

docker-compose up --build

Это автоматически соберет образ Java-приложения, запустит PostgreSQL и свяжет их через внутреннюю сеть Docker.

5. Best practices для Java-контейнеров

  • Не используйте root-пользователя — добавьте непривилегированного пользователя в Dockerfile:
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
  • Настройте JVM для контейнера — используйте флаги -XX:+UseContainerSupport и -XX:MaxRAMPercentage=75.0 (Java 10+).
  • Добавьте healthcheck:
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1
  • Используйте .dockerignore — исключите target/, .git/, node_modules/.

Заключение

Контейнеризация Java-приложений с Docker — это не просто тренд, а необходимость для современной разработки. Мы рассмотрели

Блоги

Рекомендаций по книгам