Ответ
Да, постоянно. Для разных проектов я создаю образы, начиная от базовых (с установленным runtime, например, OpenJDK), заканчивая образами для сборки и деплоя приложений.
Ключевые практики, которые я применяю:
- Использование многоэтапной сборки (multi-stage build): Это позволяет отделить этап сборки (со всеми компиляторами и зависимостями) от финального рантайм-образа, что сильно уменьшает его размер.
- Минимизация слоев: Объединение связанных команд
RUNи очистка кэша пакетного менеджера в одном слое. - Безопасность: Запуск процессов от непривилегированного пользователя (не root).
.dockerignore: Обязательно использую, чтобы не копировать в контекст сборки служебные директории (.git,target/,node_modules).
Пример Dockerfile для Spring Boot приложения:
# Этап сборки
FROM maven:3.8-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
# Финальный образ
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"] Ответ 18+ 🔞
А, ну это же вечная тема, про которую можно говорить до потери пульса. Да, постоянно, блядь, приходится этим заниматься. Для разных проектов я накручиваю образы, начиная от самых простых, где просто рантайм стоит, типа OpenJDK, и заканчивая такими монстрами, где и сборка, и деплой, и всё на свете.
Основные принципы, на которых я собаку съел:
- Многоэтапная сборка (multi-stage build): Это просто святое дело, ёпта. Отделяешь этап, где всё компилируется и пакуется, от финального образа, который уже будет бегать. В итоге получаешь образ, который весит не как паровоз, а как пушинка. Иначе выходит пиздопроебибна — в финале тащишь за собой все компиляторы и библиотеки для разработки, которые на проде нихуя не нужны.
- Слои — не хуй собачий: Стараюсь склеивать связанные команды
RUNв одну, чтобы слоёв было меньше, да и кэш от пакетного менеджера сразу подчищаю в том же слое. А то насобираешь хлама — потом образ раздуется до овердохуища. - Безопасность — не просто слово: Никаких root-пользователей, блядь. Создаю отдельную учётку с минимальными правами и от неё уже всё запускаю. Чтоб, не дай бог, кто умудрится в контейнер влезть, не мог натворить делов.
.dockerignore— мой лучший друг: Обязательно настраиваю, чтобы всякая хуйня вроде.git,target/илиnode_modulesне попала в контекст сборки. А то бывало, собираешь образ, а он полгигабайта лишних файлов тащит, волнение ебать.
Вот, смотри, как обычно для Spring Boot приложения выглядит:
# Этап сборки
FROM maven:3.8-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
# Финальный образ
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Видишь разницу? На первом этапе — вся эта мартышлюшка с Maven'ом и исходниками. А на выходе — чистенький, голенький JRE, готовый только исполнять. Красота, а не жизнь.