Образ в 15 МБ: multi-stage сборка
Компилятор остаётся в первом этапе, в итоговый образ попадает только бинарь.
Образ с компилятором и кэшами зависимостей легко вырастает за гигабайт. Многоэтапная сборка оставляет в итоговом образе только то, что нужно для запуска.
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/app ./cmd/app
FROM gcr.io/distroless/static
COPY --from=build /out/app /app
USER nonroot
ENTRYPOINT ["/app"]
Порядок COPY важен: сначала файлы зависимостей, потом код. Пока зависимости не меняются, слой с go mod download берётся из кэша.
Ещё один простой выигрыш — .dockerignore с .git, логами и локальными артефактами. Контекст сборки уменьшается, и лишнее не попадает в слои случайно.