Ответ
Да, постоянно. Dockerfile — это основа моей работы по упаковке приложений. Я пишу их с учетом безопасности, производительности и воспроизводимости сборок.
Типичный рабочий процесс и лучшие практики, которые я применяю:
- Выбор минимального базового образа: Например,
alpineили-slim-версии, чтобы уменьшить размер и поверхность для атак. - Многоступенчатые сборки (Multi-stage builds): Для отделения среды сборки (со всеми компиляторами и dev-зависимостями) от финального рантайм-образа.
- Правильное копирование и кеширование слоев: Сначала копирую файлы зависимостей (
requirements.txt,package.json), устанавливаю их, а уже потом копирую весь исходный код. Это позволяет использовать кеш Docker при изменении только кода. - Использование
.dockerignore: Исключаю из образа ненужные файлы (логи, временные файлы,.git), что ускоряет сборку и повышает безопасность. - Запуск от непривилегированного пользователя: Создаю и переключаюсь на не-root пользователя внутри контейнера для повышения безопасности.
Пример Dockerfile для Go-приложения с multi-stage build:
# Этап сборки
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /myapp
# Финальный этап
FROM alpine:latest
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /root/
# Копируем только бинарник из этапа сборки
COPY --from=builder /myapp .
# Меняем владельца файла
RUN chown appuser:appgroup /root/myapp
USER appuser
CMD ["./myapp"] Ответ 18+ 🔞
А, Dockerfile? Да постоянно с ними работаю, это ж основа всей этой движухи с контейнерами. Пишу их так, чтобы и безопасно было, и быстро собиралось, и чтобы другой инженер не охренел, когда будет разбираться.
Вот как я обычно действую и на что обращаю внимание, чтобы не накосячить:
- Базовый образ беру по-минималке. Alpine или эти
-slimверсии — чтобы образ не раздувался как пузо после пива и дыр в безопасности было меньше. Зачем тащить в продакшен целый дистрибутив, если нужно только рантайм? - Многоступенчатые сборки — это святое. Одна сцена — для всей возни с компиляцией и зависимостями, а вторая, чистая — только для готового приложения. Получается элегантно и безопасно, как шпион в смокинге.
- Кеширование слоёв — отдельная магия. Сначала копирую файлы с зависимостями (
go.mod,package.json), ставлю их, а уж потом весь остальной код. Так при правке пары строк в коде Docker не будет заново качать все библиотеки из интернета, что экономит кучу времени и нервов. .dockerignore— мой лучший друг. Без него в образ могут пролезть всякие.git, логи и временные файлы. Образ распухает, безопасность летит к чёрту. Настраиваю его одним из первых, чтобы не было потом мучительно больно.- Запускаю от обычного пользователя, а не от root. Это как не ходить по тёмному переулку в ночи — просто базовое правило безопасности. Создаю внутри контейнера своего юзера и переключаюсь на него.
Вот смотри, пример для Go-приложения, где вся эта философия видна как на ладони:
# Этап сборки: тут компилируем
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /myapp
# Финальный этап: тут уже только готовый бинарник
FROM alpine:latest
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /root/
# Копируем только бинарник из этапа сборки
COPY --from=builder /myapp .
# Меняем владельца файла
RUN chown appuser:appgroup /root/myapp
USER appuser
CMD ["./myapp"]
Видишь разницу? В первом образе — весь компилятор и dev-зависимости, а во втором — голый Alpine и один бинарник. Красота, ёпта! Весит в разы меньше, атаковать почти нечего.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶