Ответ
Размер образа критически влияет на скорость деплоя, безопасность (меньше surface для атак) и стоимость хранилища. Вот мой стандартный набор практик:
1. Многоступенчатые сборки (Multi-stage builds) — основной приём:
# Stage 1: Builder - содержит полный toolchain
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/main ./cmd/api
# Stage 2: Runtime - содержит только бинарник
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /
COPY --from=builder --chown=nonroot:nonroot /app/main .
USER nonroot:nonroot
EXPOSE 8080
CMD ["/main"]
Результат: Образ уменьшается с ~1GB (golang:1.21-alpine) до ~5MB (distroless).
2. Выбор минимального базового образа:
scratch— пустой образ, только для статически слинкованных бинарников (Go, Rust).distroless(Google) — содержит только runtime и ваше приложение, нет shell или пакетного менеджера. Идеально для продакшена.alpine— маленький, но имеетapk. Подходит, когда нужен shell для debugging.
3. Оптимизация слоёв (Layer optimization):
# ПЛОХО: Каждая команда — новый слой, кэш apt обновляется отдельно
RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip install --no-cache-dir flask gunicorn
RUN rm -rf /var/lib/apt/lists/*
# ХОРОШО: Всё в одном RUN, очистка в том же слое
RUN apt-get update && apt-get install -y
python3
python3-pip
&& pip install --no-cache-dir flask gunicorn
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
4. Использование .dockerignore:
Файл .dockerignore исключает ненужные файлы из контекста сборки, что ускоряет docker build и предотвращает попадание секретов.
# .dockerignore
.git
.gitignore
**/node_modules
**/*.log
**/*.pyc
.env
Dockerfile
README.md
**/test
**/.DS_Store
5. Сканирование и анализ образа: Перед пушем в registry я анализирую образ инструментами:
# Анализ слоёв образа
docker history my-image:latest
# Поиск уязвимостей (интегрирую в CI/CD)
docker scan my-image:latest
# Использование dive для интерактивного анализа
dive my-image:latest
6. Дополнительные продвинутые техники:
- BuildKit и секреты: Использую
--secretдля безопасной передачи ключей при сборке. - Меньшие альтернативы: Для некоторых задач заменяю
nginxнаnginx:alpineили дажеopenresty.
В нашем CI/CD пайплайне эти практики позволили сократить средний размер образов с ~800MB до ~50-150MB, что ускорило деплой в 3-4 раза.