Код-ревью Senior Dockerfile и multi-stage обновлено

Ревью: multi-stage для Go

Вопрос

Это multi-stage Dockerfile для Go-сервиса. Найди ошибки.

FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN go mod download
RUN go build -o /out/api ./cmd/api

FROM alpine:3.20
COPY --from=build /src /src
COPY --from=build /out/api /api
ENTRYPOINT /api

Коротко

Исправленная версия: Статический бинарник без cgo запускается на любой минимальной базе, в финальном образе нет исходников, shell и root. Ошибка not found при существующем файле это классический признак несовпадения libc между стадиями.

Что должен найти ревьюер

  1. Производительностьстрока 3
    COPY . . до go mod download: кеш модулей сбрасывается при любой правке кода. Сначала COPY go.mod go.sum ./ и go mod download.
  2. Ошибкастрока 5
    Сборка без CGO_ENABLED=0: бинарник может оказаться динамически слинкован с glibc и не запуститься на alpine (musl) с ошибкой not found.
  3. Безопасностьстрока 8
    В финальный образ копируются все исходники /src: лишний размер и утечка кода и, возможно, конфигов. Нужен только бинарник.
  4. Ошибкастрока 10
    Shell-форма ENTRYPOINT: запускается через /bin/sh -c, сигналы не доходят до приложения. Нужно ENTRYPOINT ["/api"].
  5. Безопасность
    Нет USER: процесс работает от root. Добавить непривилегированного пользователя или взять distroless с nonroot.

Разбор

Исправленная версия:

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/api ./cmd/api

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/api /api
USER nonroot
ENTRYPOINT ["/api"]

Статический бинарник без cgo запускается на любой минимальной базе, в финальном образе нет исходников, shell и root. Ошибка not found при существующем файле это классический признак несовпадения libc между стадиями.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.