Ответ
Я занимался контейнеризацией микросервисных приложений на Go и Python, а также монолитных legacy-систем. Основная цель — обеспечить воспроизводимость окружения, упростить деплой и подготовить инфраструктуру для оркестрации.
Пример Dockerfile для Go-сервиса с многоступенчатой сборкой:
# Этап сборки
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 -o /app/service ./cmd/main
# Финальный образ
FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
COPY --from=builder /app/service .
COPY --from=builder /app/configs ./configs
EXPOSE 8080
CMD ["./service"]
Ключевые практики, которые я применял:
- Использование
.dockerignoreдля исключения ненужных файлов (.git,node_modules, логов), что ускоряет сборку и уменьшает размер образа. - Минимизация слоев и размера образа: выбор базовых образов на Alpine, объединение
RUN-команд, очистка кэша пакетных менеджеров. - Безопасность: запуск контейнера от непривилегированного пользователя (инструкция
USER), регулярное обновление базовых образов для устранения уязвимостей. - Логирование: настройка вывода логов в
stdout/stderrдля корректной работы с Docker-драйверами и сборщиками логов (Fluentd, Loki). - Оркестрация: подготовка образов с учетом требований Kubernetes (readiness/liveness probes, корректное завершение по сигналам).
Для управления зависимостями между сервисами в разработке использовал docker-compose, что позволяло локально поднимать весь стек (приложение, БД, кэш, очередь).