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

Как Docker облегчает размер приложения

2.0 Middle🔥 191 комментариев
#Docker, Kubernetes и DevOps

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

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

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

# Как Docker облегчает размер приложения

Краткий ответ

Docker облегчает размер приложения несколькими способами:

  1. Контейнеризация: упаковка только необходимых зависимостей без всей ОС
  2. Базовые образы: использование минималистичных базовых образов (Alpine, Distroless)
  3. Multi-stage build: разделение этапов сборки для исключения лишних артефактов
  4. Кэширование слоев: эффективное использование кэша Docker при сборке
  5. Удаление временных файлов: очистка во время сборки

Размер в сравнении: VM vs Docker

Виртуальная машина

Приложение (Java)
├── JRE / JDK
├── Dependencies
└── ОС (Linux) - 2-3 GB
   └── Kernel, системные инструменты, библиотеки

Размер образа VM: 2-5 GB

Docker контейнер

Приложение (Java)
├── JRE (минимальный) - 200-500 MB
├── Dependencies
└── Базовый образ (Alpine) - 5-50 MB

Размер образа Docker: 200-800 MB

Стратегии уменьшения размера

1. Выбор базового образа

Плохой вариант:

FROM openjdk:11-jdk
# Размер: ~650 MB (полный JDK)

Хороший вариант:

FROM openjdk:11-jre
# Размер: ~400 MB (только runtime)

Лучший вариант:

FROM openjdk:11-jre-alpine
# Размер: ~150 MB (JRE + Alpine)

Оптимальный вариант:

FROM gcr.io/distroless/java11-debian11
# Размер: ~100-150 MB (только Java + системные библиотеки)

2. Multi-stage build

Проблема: при обычной сборке в образ попадают инструменты компиляции, исходный код, временные файлы.

Решение:

# Этап 1: Сборка
FROM maven:3.8-openjdk-11 as builder
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests

# Этап 2: Runtime (только нужное)
FROM openjdk:11-jre-alpine
COPY --from=builder /app/target/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

В финальном образе остается только JAR файл и JRE, без компилятора и исходного кода.

Результат: образ уменьшается с 1.5 GB до 300-400 MB

3. Слои Docker и кэширование

Каждая инструкция в Dockerfile создает слой. Docker кэширует неизменные слои.

FROM openjdk:11-jre-alpine

# Слой 1: базовый образ (кэшируется)
RUN apk add --no-cache curl wget  # Слой 2 (кэшируется)

COPY pom.xml .  # Слой 3
RUN mvn dependency:resolve  # Слой 4 (кэшируется по pom.xml)

COPY src ./src  # Слой 5
RUN mvn package -DskipTests  # Слой 6

# Если изменился только src, пересчитаются только слои 5-6

Правильный порядок: зависимости → исходный код → сборка

4. Удаление лишних файлов при сборке

FROM openjdk:11-jre-alpine

RUN apk add --no-cache curl && \
    # установка инструментов
    curl https://example.com/tool.tar.gz | tar xz && \
    # удаление временных файлов
    rm -rf /tmp/* /var/cache/apk/*

5. Использование .dockerignore

.dockerignore
node_modules/
.git/
.gradle/
target/
*.md
.env

Исключает ненужные файлы при копировании в образ.

Пример оптимизированного Dockerfile для Java

# Этап 1: Сборка
FROM maven:3.8-openjdk-11-slim as builder
WORKDIR /app
COPY pom.xml .
# Загружаем зависимости отдельно (кэшируется)
RUN mvn dependency:resolve
COPY src ./src
RUN mvn clean package -DskipTests -q

# Этап 2: Извлечение слоев приложения
FROM openjdk:11-jre-alpine as extractor
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
RUN jar xf app.jar && rm app.jar

# Этап 3: Финальный образ
FROM openjdk:11-jre-alpine
WORKDIR /app

# Копируем только необходимое
COPY --from=extractor /app/BOOT-INF/lib /app/lib
COPY --from=extractor /app/META-INF /app/META-INF
COPY --from=extractor /app/BOOT-INF/classes /app

EXPOSE 8080
ENTRYPOINT ["java", "-cp", "/app:/app/lib/*", "com.example.Application"]

Размер слоев:

  • builder: 1.5 GB (не входит в финальный образ)
  • extractor: 600 MB (не входит в финальный образ)
  • финальный: 200-300 MB

Другие стратегии оптимизации

1. Использование Spring Boot Layers

FROM maven:3.8-openjdk-11 as builder
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests
RUN mkdir -p target/dependency
RUN cd target/dependency && jar -xf ../*.jar

FROM openjdk:11-jre-alpine
COPY --from=builder /app/target/dependency/BOOT-INF/lib /app/lib
COPY --from=builder /app/target/dependency/BOOT-INF/classes /app
ENTRYPOINT ["java", "-cp", "/app:/app/lib/*", "com.example.Application"]

2. Использование GraalVM Native Image

Компилирует Java в истинный машинный код:

Обычный JAR: 150-500 MB
Native Image: 50-100 MB (без JVM)

3. Минимизация dependencies

<!-- До: много зависимостей -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- После: только нужное -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

Сравнение размеров

ПодходРазмер образа
Обычный JDK образ650-850 MB
Одноэтапный с JRE400-500 MB
Multi-stage с Alpine150-300 MB
Distroless образ100-200 MB
GraalVM Native50-100 MB

Инструменты для анализа размера

# Посмотреть размер образа
docker images

# Анализ слоев
docker history app:latest

# Детальный анализ содержимого
docker run --rm app:latest du -sh /*

Вывод

Docker облегчает размер приложения через:

  1. Контейнеризацию вместо полной ОС
  2. Multi-stage builds для исключения зависимостей сборки
  3. Минимальные базовые образы (Alpine, Distroless)
  4. Эффективное кэширование слоев
  5. Удаление временных файлов

Правильный Docker образ может быть в 5-10 раз меньше виртуальной машины при сохранении всех необходимых компонентов.