← Назад к вопросам
Почему в рамках докеризации удобно получать jar?
2.0 Middle🔥 231 комментариев
#Docker, Kubernetes и DevOps
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Почему в докеризации удобно получать JAR
Краткий ответ
JAR файл в Docker удобен потому что:
- Fat JAR/Uber JAR - одного файла всё нужное (зависимости, код, ресурсы)
- Упрощённый Dockerfile - просто копируем и запускаем JAR
- Isolation - JVM изолирована в контейнере, не конфликтует с хостом
- Production-ready - Spring Boot build создаёт готовый к запуску артефакт
- Stateless deployment - легко масштабировать и обновлять
Что такое Fat JAR (Uber JAR)
Обычный JAR:
┌─────────────────────┐
│ my-app-1.0.jar │
├─────────────────────┤
│ com/example/*.class │
│ application.yml │
│ MANIFEST.MF │
└─────────────────────┘
└─ Требует: maven-jar-plugin
└─ ПРОБЛЕМА: зависимости не включены!
└─ ПРОБЛЕМА: нужно добавлять .jar'ы в classpath
Fat JAR (Uber JAR):
┌──────────────────────────────────────┐
│ my-app-1.0-SNAPSHOT.jar │
├──────────────────────────────────────┤
│ com/example/*.class │ (мой код)
│ org/springframework/boot/*.class │ (Spring Boot)
│ org/apache/commons/*.class │ (Apache Commons)
│ com/fasterxml/jackson/*.class │ (Jackson)
│ ... (все зависимости) │
│ BOOT-INF/lib/*.jar │ (JAR зависимостей)
│ BOOT-INF/classes/* │ (ресурсы)
│ META-INF/MANIFEST.MF │ (главный класс)
└──────────────────────────────────────┘
└─ РЕШЕНИЕ: все зависимости внутри!
└─ ВСЁ в одном файле - готово к запуску!
└─ Требует: maven-shade-plugin или spring-boot-maven-plugin
Почему Fat JAR идеален для Docker
1. Простой Dockerfile
# ❌ БЕЗ Fat JAR (сложно)
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y java-17-openjdk
# Копируем исходный код
COPY src /app/src
COPY pom.xml /app/
# Собираем приложение ВНУТРИ контейнера (медленно!)
RUN cd /app && mvn clean package
# Копируем все JAR зависимостей
COPY target/dependency/*.jar /app/lib/
COPY target/my-app.jar /app/
WORKDIR /app
CMD ["java", "-cp", "lib/*:my-app.jar", "com.example.Main"]
# Размер образа: 1+ GB (много слоёв, много файлов)
# ✅ С Fat JAR (просто и быстро)
FROM eclipse-temurin:17-jre-alpine
# Копируем готовый Fat JAR
COPY target/my-app-1.0.jar app.jar
# Запускаем
ENTRYPOINT ["java", "-jar", "app.jar"]
# Размер образа: 200-300 MB (компактный, быстро собирается)
2. Build процесс
# БЕЗ Fat JAR
mvn clean package
# Результат:
# target/my-app-1.0.jar (только мой код)
# target/dependency/*.jar (все зависимости отдельно)
# ~ 50+ файлов в target/
# С Docker:
# Нужно при сборке образа:
# - Копировать все 50+ файлов
# - Собирать classpath с каждым файлом
# - Это медленно и сложно
# С Fat JAR
mvn clean package
# Результат:
# target/my-app-1.0-SNAPSHOT.jar (один файл, всё внутри)
# ~ 50 MB, готов к запуску
# С Docker:
# - Копируем 1 файл
# - Простой ENTRYPOINT
# - Быстро и понятно
Как создать Fat JAR
1. Spring Boot Maven Plugin (рекомендуется)
<!-- pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<mainClass>com.example.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- Создаёт Fat JAR!
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
# Сборка:
mvn clean package
# Результат:
# target/my-app-1.0.jar (Fat JAR!)
# target/my-app-1.0.jar.original (исходный JAR)
2. Maven Shade Plugin (для non-Spring проектов)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
3. Gradle (для Gradle-проектов)
plugins {
id 'org.springframework.boot' version '3.0.0'
}
bootJar {
mainClass = 'com.example.Application'
}
// Сборка:
// gradle bootJar
// Результат:
// build/libs/my-app-1.0.jar (Fat JAR)
Структура Fat JAR
my-app-1.0.jar
├── BOOT-INF/
│ ├── classes/
│ │ ├── com/example/Application.class
│ │ ├── application.yml
│ │ └── ...
│ ├── lib/
│ │ ├── spring-core-6.0.0.jar
│ │ ├── spring-web-6.0.0.jar
│ │ ├── jackson-databind-2.14.0.jar
│ │ ├── commons-lang3-3.12.0.jar
│ │ └── ... (все зависимости)
│ └── classpath.idx
├── META-INF/
│ ├── MANIFEST.MF
│ │ Main-Class: org.springframework.boot.loader.JarLauncher
│ │ Start-Class: com.example.Application
│ │ Implementation-Version: 1.0
│ └── ...
└── org/springframework/boot/loader/
├── JarLauncher.class (Boot loader)
└── ... (классы для запуска)
Fat JAR в Docker: полный пример
# Dockerfile
# Stage 1: Build (сборка приложения)
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
# Собираем Fat JAR
RUN mvn clean package -DskipTests
# Stage 2: Runtime (выполнение)
FROM eclipse-temurin:17-jre-alpine
# Копируем только готовый JAR из Stage 1
COPY --from=builder /build/target/my-app-*.jar app.jar
# Параметры JVM для Docker
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
# Порт
EXPOSE 8080
# Запуск
ENTRYPOINT ["java"]
CMD ["-jar", "app.jar"]
# Сборка образа
docker build -t my-app:1.0 .
# Запуск контейнера
docker run -p 8080:8080 my-app:1.0
# Проверка
curl http://localhost:8080/health
Преимущества Fat JAR в Docker
| Аспект | Плюсы |
|---|---|
| Сборка | Один файл = быстро копируется в образ |
| Размер образа | Компактный (200-300 MB вместо 1+ GB) |
| Скорость запуска | Быстрый (зависимости уже распакованы) |
| Stateless | Легко масштабировать горизонтально |
| Воспроизводимость | Одинаковое поведение везде (dev/staging/prod) |
| Обновления | Просто пересобрать образ с новым JAR |
| Testing | Можно запустить локально: java -jar app.jar |
Недостатки и как их решать
1. Размер JAR может быть большим
# Проблема: Fat JAR 100+ MB
# Решение 1: Multi-stage build (как выше)
# Решение 2: Используйте слои
docker build --target app:1.0 .
# Решение 3: Минимизируйте зависимости
# Проверьте pom.xml на лишние зависимости
2. JVM требует памяти в контейнере
FROM eclipse-temurin:17-jre-alpine
COPY target/my-app-1.0.jar app.jar
# Установите лимит памяти
ENTRYPOINT ["java", "-Xmx256m", "-Xms256m", "-jar", "app.jar"]
3. Native Image (GraalVM) для ещё меньшего размера
<!-- pom.xml для Spring Native -->
<dependency>
<groupId>org.springframework.native</groupId>
<artifactId>spring-native</artifactId>
<version>0.12.1</version>
</dependency>
<!-- Сборка native image -->
mvn clean package -Pnative
# Результат: исполняемый файл (не JAR), ~100 MB образ
Сравнение подходов
┌──────────────┬─────────────┬──────────────┬──────────────┐
│ Подход │ Размер │ Память │ Скорость │
├──────────────┼─────────────┼──────────────┼──────────────┤
│ Fat JAR │ 50-150 MB │ 256-512 MB │ 2-3 сек │
│ War + Tomcat │ 200+ MB │ 512 MB+ │ 3-5 сек │
│ Native Image │ 80-100 MB │ 64-128 MB │ <500 ms │
└──────────────┴─────────────┴──────────────┴──────────────┘
Вывод
Fat JAR идеален для Docker потому что:
- ✅ Один файл = всё нужное внутри
- ✅ Простой Dockerfile
- ✅ Быстрая сборка образа
- ✅ Компактный размер
- ✅ Легко развёртывать и масштабировать
- ✅ Spring Boot делает это по-умолчанию
- ✅ Стателесс deployment = идеально для Kubernetes