← Назад к вопросам

Какой синтаксис будет у Dockerfile при создании образа проекта?

2.0 Middle🔥 191 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Dockerfile для Java приложения: синтаксис и лучшие практики

Основная структура Dockerfile

Dockerfile — это файл с инструкциями для построения Docker образа. Для Java приложений структура типична:

FROM openjdk:17-slim
WORKDIR /app
COPY . .
RUN mvn clean package
EXPOSE 8080
CMD ["java", "-jar", "target/app.jar"]

Пошаговый разбор

1. FROM — базовый образ

FROM openjdk:17-slim
  • openjdk:17 — образ с установленной Java 17
  • slim — облегчённая версия (без ненужных пакетов)
  • Альтернативы: openjdk:21, eclipse-temurin:17, amazoncorretto:17

2. WORKDIR — рабочая директория

WORKDIR /app
  • Устанавливает директорию, в которой выполняются команды
  • Все последующие операции происходят в /app
  • Если директория не существует, Docker создаст её

3. COPY — копирование файлов из хоста

COPY . .
  • Первая точка . — исходная директория на хосте
  • Вторая точка . — целевая директория в контейнере (/app)
  • COPY . . копирует всё содержимое проекта

4. RUN — выполнение команд

RUN mvn clean package
  • Выполняет Maven сборку
  • Результат: target/app.jar создаётся внутри контейнера
  • Выполняется во время build, не при запуске контейнера

5. EXPOSE — открытие портов

EXPOSE 8080
  • Документирует, какие порты слушает приложение
  • Не открывает порты (только информационное)
  • Для открытия портов используется флаг -p при docker run

6. CMD — команда при запуске контейнера

CMD ["java", "-jar", "target/app.jar"]
  • Выполняется при запуске контейнера
  • JSON формат: ["исполняемый файл", "аргумент1", "аргумент2"]
  • Может быть переопределена при docker run

Полный пример для Spring Boot

# Этап 1: Сборка
FROM maven:3.9-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests

# Этап 2: Runtime
FROM openjdk:17-slim
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

Multi-stage Dockerfile (лучшая практика)

Много-этапная сборка уменьшает размер итогового образа:

# Этап 1: builder — сборка приложения
FROM maven:3.9-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests

# Этап 2: runtime — только нужный JAR
FROM openjdk:17-slim
WORKDIR /app

# Копируем только JAR, без Maven кэша
COPY --from=builder /build/target/myapp.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Преимущества:

  • Образ builder весит ~500MB (с Maven)
  • Финальный образ весит ~200MB (только Java + JAR)
  • Меньше слоёв и кэша

Инструкции Docker

ENTRYPOINT vs CMD

# CMD — можно переопределить
CMD ["java", "-jar", "app.jar"]
# docker run myimage echo "Hello"  # выполнит echo, а не jar

# ENTRYPOINT — основная команда
ENTRYPOINT ["java", "-jar", "app.jar"]
# docker run myimage arg1 arg2  # выполнит: java -jar app.jar arg1 arg2

ENV — переменные окружения

ENV JAVA_OPTS="-Xmx1024m -Xms512m"
ENV SPRING_PROFILES_ACTIVE="production"

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

ARG — аргументы при build

ARG JAVA_VERSION=17
FROM openjdk:${JAVA_VERSION}-slim

ARG APP_VERSION=1.0.0
RUN echo "Building version ${APP_VERSION}"

Использование:

docker build --build-arg JAVA_VERSION=21 .

RUN с несколькими команды

# ❌ Плохо: создаёт несколько слоёв
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✅ Хорошо: один слой
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean

Оптимизированный Dockerfile для Java

# Builder stage
FROM maven:3.9-openjdk-17 AS builder
WORKDIR /src
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests -q

# Runtime stage
FROM openjdk:17-slim
WORKDIR /app

# Не запускать как root
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

# Копируем только JAR
COPY --from=builder --chown=appuser:appuser /src/target/app.jar .

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD java -cp . healthcheck.HealthCheck || exit 1

EXPOSE 8080

ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-jar", "app.jar"]

Примеры для разных build систем

Gradle

FROM gradle:7-jdk17 AS builder
WORKDIR /src
COPY build.gradle settings.gradle .
RUN gradle dependencies
COPY src ./src
RUN gradle build -x test

FROM openjdk:17-slim
WORKDIR /app
COPY --from=builder /src/build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

Buildpacks (облегчённый способ)

# Вместо Dockerfile
pack build myapp --builder paketobuildpacks/builder:base

Сборка и запуск

# Сборка образа
docker build -t myapp:1.0 .
docker build -t myapp:latest .

# Запуск контейнера
docker run -p 8080:8080 myapp:1.0
docker run -e SPRING_PROFILES_ACTIVE=prod -p 8080:8080 myapp:1.0

# С переопределением команды
docker run myapp:1.0 java -Xmx2048m -jar app.jar

Лучшие практики

1. Multi-stage сборка

# ✅ Уменьшает размер образа
FROM maven AS builder
RUN mvn package

FROM openjdk:17-slim
COPY --from=builder /app.jar .

2. Кэширование слоёв

# ✅ Зависимости кэшируются
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package

# ❌ Неэффективно
COPY . .
RUN mvn package

3. Минимизация образа

# ✅ slim версия
FROM openjdk:17-slim

# ❌ Полная версия
FROM openjdk:17

4. Контейнерная поддержка памяти

ENTRYPOINT ["java", 
  "-XX:+UseContainerSupport",
  "-XX:MaxRAMPercentage=75.0",
  "-jar", "app.jar"]

5. Безопасность

# Не запускать как root
RUN useradd -m appuser
USER appuser

# Только необходимые портов
EXPOSE 8080

.dockerignore — исключение файлов

# .dockerignore
target/
.git/
.gitignore
README.md
*.log
.env

Предотвращает копирование ненужных файлов в образ.

Резюме

Типичный Dockerfile для Java:

FROM maven:3.9-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests

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

Это многоуровневая сборка, которая:

  • Компилирует код в первом образе
  • Копирует только JAR во второй образ
  • Минимизирует финальный размер образа