scratch и distroless
Тема дорожной карты · Golang
Минимальные Docker-образы на базе scratch или Google's distroless — лучшая практика для контейнеризованных Golang-сервисов в продакшене, поскольку Go компилируется в единый статически скомпонованный бинарник без рантайма ОС, делая многоэтапный Dockerfile идеальным паттерном сборки. В многоэтапной сборке компиляция выполняется в golang:1.22-alpine командой CGO_ENABLED=0 go build -ldflags="-s -w" -o /app ./cmd/server, затем COPY --from=builder /app /app в FROM scratch или FROM gcr.io/distroless/static-debian12, создавая образы менее 10 МБ без оболочки, менеджера пакетов и с радикально сниженной площадью атаки. Образы distroless содержат CA-сертификаты и данные о временных зонах, которых нет в scratch, что делает distroless предпочтительным, когда Golang-сервис выполняет исходящие HTTPS-вызовы через net/http или pgx к TLS-PostgreSQL. Минимальные Docker-образы для Golang-сервисов сокращают время запуска Kubernetes-pod'ов, снижают расходы на хранение в реестре и удовлетворяют инструментам сканирования безопасности Trivy или Grype, сообщающим о нулевых CVE для scratch-образа. Использование минимальных Docker-образов — стандартный паттерн в продакшен Golang-развёртываниях наряду с многоэтапными Docker-сборками, liveness/readiness-пробами Kubernetes и инструментацией OpenTelemetry.
Как это работает
scratch и distroless знаменито прост: go build создаёт один статический бинарь, запускаемый на любом хосте с тем же OS+arch. Кросс-компиляция через GOOS=linux GOARCH=amd64 go build. Контейнеризуйте бинарь через FROM scratch или FROM gcr.io/distroless/static (несколько МБ total). go build -ldflags="-s -w" — для удаления debug-символов (меньше бинарь). Health-эндпойнты: /healthz, /readyz. Graceful shutdown через http.Server.Shutdown(ctx).
Когда применять
Multi-stage Dockerfile: builder-образ гонит go build; runner — scratch или distroless с одним бинарём + CA-сертификатами. Всегда graceful SIGTERM — drain in-flight запросы до выхода. Версию встраивайте через -ldflags "-X main.Version=$(git describe)" для вывода myapp version. Запуск под non-root, read-only ФС, минимальные capabilities.
Типичные ошибки
Ловушки scratch и distroless: FROM alpine, но компиляция против glibc (CGO_ENABLED=1 + alpine = мистические крэши — используйте CGO_ENABLED=0); нет CA-сертификатов в scratch-образах (TLS валится x509-ошибками — добавьте ca-certificates); нет graceful shutdown (k8s rolling-деплои дропают in-flight запросы); огромные бинари из-за забытых -w -s-флагов.