Как отвечать: определение → как работает внутри → где ловушка → пример. Отвечайте вслух до чтения ответа — собеседование это устный жанр, и «понимаю про себя» не равно «объясняю словами».
1. Какие флаги go build используют в продакшене и зачем?
Минимальный продакшен-набор: go build -trimpath -ldflags="-s -w" -o app ./cmd/app. Расшифровка: -trimpath убирает локальные пути из бинарника (воспроизводимая сборка, без утечки структуры каталогов); -s -w убирают таблицу символов и DWARF-отладку — бинарник меньше на ~30%; -o задаёт имя. Версию вшивают через -ldflags "-X main.version=v1.2.3" на пакетной переменной. Отдельно -buildvcs=false, если git-метаданные не нужны. На собеседовании ждут понимания, что каждый флаг решает конкретную задачу, а не заученного набора.
go build -trimpath \
-ldflags="-s -w -X main.version=${VERSION}" \
-o app ./cmd/app2. Как работает кросс-компиляция в Go? Что такое GOOS и GOARCH?
Кросс-компиляция — сборка под чужую платформу — делается двумя переменными окружения без тулчейна целевой платформы: GOOS (ОС: linux, windows, darwin) и GOARCH (архитектура: amd64, arm64). Пример: GOOS=linux GOARCH=arm64 go build — бинарник для ARM-сервера соберётся прямо на Mac. Ограничение — CGO: если пакет использует C-код, нужен тулчейн целевой платформы, поэтому для чистой кросс-компиляции ставят CGO_ENABLED=0 (Go-код становится полностью статическим). Проверить платформу бинарника — file app или go version -m app (заодно показывает модули и флаги сборки).
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 ./cmd/app go version -m app # модули, версия Go, настройки сборки
3. CGO_ENABLED=0 — что меняется и когда нельзя отключать CGO?
CGO_ENABLED=0 выключает вызовы C-кода: бинарник становится полностью статическим (запускается где угодно, включая scratch и alpine без libc), кросс-компиляция работает без тулчейнов. Нельзя отключать, если зависимости требуют CGO: драйвер SQLite (mattn/go-sqlite3) — чисто CGO-шный (для него есть чисто-Go альтернатива modernc.org/sqlite), сетевые библиотеки с netgo-префиксами DNS-резолвера, некоторые крипто- и графические пакеты. Вопрос-ловушка: резолвер DNS — со включённым CGO Go может использовать системный libc-резолвер, с CGO_ENABLED=0 — свой чисто-Go; на редких конфигурациях DNS (например, сложный nsswitch) поведение различается.
CGO_ENABLED=0 go build -o app # статический бинарник # не работает с mattn/go-sqlite3 — нужен CGO или modernc.org/sqlite
4. Multi-stage Dockerfile для Go: зачем две стадии и что положить в финальный образ?
Стадия builder компилирует бинарник (с полным Go-тулчейном и кэшем модулей), финальная стадия копирует ТОЛЬКО бинарник в минимальный базовый образ. Зачем: финальный образ без компилятора, исходников и кэша — меньше (десятки МБ вместо гигабайта), меньше поверхность атаки, быстрее деплой. Типовой финальный базовый образ: gcr.io/distroless/static или scratch — для CGO_ENABLED=0 бинарника больше ничего и не нужно (даже libc не требуется); нужен CA-сертификат для исходящих HTTPS (copy ca-certificates из builder или пакет ca-certificates в alpine). Плюс non-root USER и чтение конфигов из env — вопросы безопасности в довесок.
FROM golang:1.24 AS builder WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /app ./cmd/app FROM gcr.io/distroless/static-debian12 COPY --from=builder /app /app COPY --from=builder /etc/ssl/certs /etc/ssl/certs USER nonroot:nonroot ENTRYPOINT ["/app"]
5. Почему бинарник Go большой и как его уменьшить?
В Go в бинарник статически вшивается рантайм: планировщик, GC, reflection, все зависимости. Hello World весит ~2 МБ — это норма, а не баг. Способы уменьшения по убыванию эффекта: (1) -ldflags "-s -w" — минус таблица символов и отладка (~30%); (2) убрать неиспользуемые зависимости — каждая тянет свои пакеты; (3) UPX-сжатие — спорно: образ меньше, но при запуске распаковка в память и возможные срабатывания антивирусов; (4) проверить reflection-тяжёлые пакеты (ORM, крупные SDK). Правильный ответ подтверждает понимание: статический рантайм — это осознанный размен «размер на диск» на «работает везде без зависимостей».
6. Что должно быть в Docker-образе Go-сервиса, кроме бинарника?
Чек-лист для продакшен-образа: (1) CA-сертификаты — без них исходящий HTTPS упадёт с x509-ошибкой (самая частая ошибка первого Dockerfile); (2) часовой пояс — tzdata, если сервис формирует время в зонах (иначе всё в UTC); (3) non-root USER — безопасность; (4) HEALTHCHECK или readiness/liveness-эндпоинты для оркестратора; (5) правильные EXPOSE и обработку SIGTERM (graceful shutdown по сигналу — связка с контекстом). Пароли и секреты — только через env/secrets, не в слоях образа (слои видны history). Каждый пункт — типовой вопрос на собеседовании и типовая ошибка первого деплоя.
# Частая ошибка первого Dockerfile: # нет ca-certificates → https://api.example.com падает с x509 COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ USER 65532:65532 ENTRYPOINT ["/app"]
7. Как встроить версию и метаданные сборки в бинарник?
Через -ldflags -X: она присваивает значение пакетной строковой переменной на этапе линковки: -X main.version=v1.2.3 -X main.commit=$(git rev-parse --short HEAD). Переменная должна быть пакетной (не локальной), типа string, без начального значения в коде (или с ним — перезапишется). Показывать — по флагу version или в /healthz-эндпоинте: сервис, который не может ответить «какая у меня версия», невозможно отлаживать в проде. Развитие вопроса: go version -m app показывает и модули, и build-настройки — удобно для разбора чужого бинарника.
// main.go
var version = "dev"
func main() {
if *showVersion { fmt.Println(version); return }
...
}
// сборка:
go build -ldflags "-X main.version=$(git describe --tags)" -o app ./cmd/appПрокачать тему в самоучителе
Читается быстро, запоминается практикой. Эти курсы закрывают тему с запуском кода прямо на странице:
- Продвинутые возможности языка Go — Продвинутый курс Go: замыкания, defer, горутины, каналы, контекст, интерфейсы, дженерики, рефлексия, тесты и JSON. 25 уроков с практикой в браузере.
- Язык Go с нуля: базовый синтаксис и конструкции — Интерактивный курс базового синтаксиса Go для начинающих: переменные, циклы, срезы, функции, структуры. 25 уроков с кодом в браузере, тестами и первым приложением.