Создавал ли собственные Docker-образы?

Ответ

Да, постоянно. Для разных проектов я создаю образы, начиная от базовых (с установленным 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, готовый только исполнять. Красота, а не жизнь.