Как Docker облегчает размер приложения
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как Docker облегчает размер приложения
Краткий ответ
Docker облегчает размер приложения несколькими способами:
- Контейнеризация: упаковка только необходимых зависимостей без всей ОС
- Базовые образы: использование минималистичных базовых образов (Alpine, Distroless)
- Multi-stage build: разделение этапов сборки для исключения лишних артефактов
- Кэширование слоев: эффективное использование кэша Docker при сборке
- Удаление временных файлов: очистка во время сборки
Размер в сравнении: 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 |
| Одноэтапный с JRE | 400-500 MB |
| Multi-stage с Alpine | 150-300 MB |
| Distroless образ | 100-200 MB |
| GraalVM Native | 50-100 MB |
Инструменты для анализа размера
# Посмотреть размер образа
docker images
# Анализ слоев
docker history app:latest
# Детальный анализ содержимого
docker run --rm app:latest du -sh /*
Вывод
Docker облегчает размер приложения через:
- Контейнеризацию вместо полной ОС
- Multi-stage builds для исключения зависимостей сборки
- Минимальные базовые образы (Alpine, Distroless)
- Эффективное кэширование слоев
- Удаление временных файлов
Правильный Docker образ может быть в 5-10 раз меньше виртуальной машины при сохранении всех необходимых компонентов.