Рубрики
Без рубрики

Докеризация Spring Boot <80MB

Я хотел выяснить, насколько я могу уменьшить размер образа Docker с помощью простого приложения Spring Boot

Я хотел выяснить, насколько можно уменьшить размер образа Docker с помощью простого приложения Spring Boot.

Попытка с Alpine

Поэтому давайте воспользуемся базовым образом с Alpine Linux .

Файл Dockerfile:

# use Alpine Linux for build stage
FROM alpine:3.10.1 as build

# install build dependencies
RUN apk --no-cache add openjdk11
RUN apk --no-cache add maven
...

Это позволит получить легкий образ Alpine Linux (~6MB) из Dockerhub и установить OpenJDK 11 и Maven в качестве зависимостей для сборки. После этого мы можем собрать приложение Spring Boot:

...
# fetch maven dependencies
WORKDIR /build
COPY pom.xml pom.xml
RUN mvn dependency:go-offline

# build
COPY src src
RUN mvn clean package
...

Как вы можете видеть, мы делаем это в два этапа. Сначала мы загружаем все зависимости, а затем компилируем код. Если мы построим изображение снова без изменений в pom.xml файл результат будет взят из кэша. Это сэкономит некоторое время, так как код меняется гораздо чаще, чем зависимости.

Наконец, мы создадим второй образ Docker, который будет содержать только необходимые части для выполнения. Docker называет эту функцию “многоступенчатой”, где первые этапы являются предварительными этапами сборки, а последний этап приводит к созданию образа выполнения:

...
# prepare a fresh Alpine Linux with JDK
FROM alpine:3.10.1
RUN apk --no-cache add openjdk11

# get result from build stage
COPY --from=build /build/target/*.jar /app.jar
VOLUME /tmp
EXPOSE 8080
CMD /usr/lib/jvm/default-jvm/bin/java -jar /app.jar

Мы используем аргумент --form=build , чтобы скопировать результат сборки с первого этапа. Все остальные части будут удалены: Maven, байтовый код Java, зависимости,…

Насколько велик результат?

$ docker build -t lazy . && docker image ls | grep lazy
...
lazy    latest    5f63318a3a0b    11 seconds ago    288MB

Я подумал, что 288 МБ – это слишком много. Я вспомнил, что в Java 9 стандартная библиотека была разделена на модули. Существует инструмент link для создания JDK только с необходимыми модулями. Мы добавляем выполнение ссылки непосредственно перед вызовами mvn :

...
# build JDK with less modules
RUN /usr/lib/jvm/default-jvm/bin/jlink \
    --compress=2 \
    --module-path /usr/lib/jvm/default-jvm/jmods \
    --add-modules java.base,java.logging,java.xml,jdk.unsupported, \
        java.sql,java.naming,java.desktop,java.management, \
        java.security.jgss,java.instrument \
    --output /jdk-minimal

# fetch maven dependencies
...

Кроме того, мы должны скопировать минимальный JDK на этапе выполнения:

# prepare a fresh Alpine Linux with JDK
FROM alpine:3.10.1

# get result from build stage
COPY --from=build /jdk-minimal /opt/jdk/
COPY --from=build /build/target/*.jar /app.jar
VOLUME /tmp
EXPOSE 8080
CMD /opt/jdk/bin/java -jar /app.jar

Уменьшает ли это размер?

$ docker build -t lazy . && docker image ls | grep lazy,[object Object],
...,[object Object],
lazy    latest    fbdc64bb6826    20 seconds ago    79.5MB,[object Object],

Мы удалили ~200 МБ ненужных модулей JDK. Мне это нравится. Может быть, размер будет еще меньше, если мы используем Встроенную функцию изображения виртуальной машины Graal ?

Результат: 79,5 МБ

  • Файл JAR размером 16 МБ
  • 55 МБ OpenJDK 11 “связанный”
  • 8,5МБ изображения Alpine Linux + Docker

Исходный код: https://gist.github.com/gofabian/8a0f951bc1edc88b918ce1145ccfbb03

Оригинал: “https://dev.to/gofabian/dockerize-spring-boot-80mb-58m9”