Приходилось ли писать Docker файлы и работать с контейнерами
Что проверяют
Умеете ли вы пользоваться главным преимуществом Go в контейнерах: бинарником, которому не нужен рантайм внутри образа. Ответ показывает, собирали ли вы образ сами или скопировали чужой Dockerfile целиком.
Как отвечать
Основа это многоступенчатая сборка. Первый этап на образе с Go: сначала копируются go.mod и go.sum, выполняется загрузка модулей, и только потом копируется исходный код, чтобы слой с зависимостями переиспользовался. Второй этап это минимальный образ, куда попадает один бинарник.
Что стоит назвать дальше:
CGO_ENABLED=0для статической сборки, если зависимостей от C нет;- флаги
-ldflags="-s -w"и передача версии сборки через-X; - финальная база: distroless или scratch, причём в scratch нужно доложить корневые сертификаты и данные о часовых поясах, иначе запросы по HTTPS и разбор времени отвалятся;
- запуск от непривилегированного пользователя, в scratch это числовой идентификатор;
- монтирование кэша модулей и сборки, если сборщик это умеет.
Отдельно скажите про процессор. Рантайм Go по умолчанию смотрит на число ядер машины, а не на лимит пода, поэтому при лимите в доли ядра он создаёт лишние потоки и упирается в троттлинг. Лечится явной установкой числа процессоров или библиотекой, которая читает cgroup. Для памяти аналогично задаётся мягкий лимит сборщика мусора.
Где спотыкаются
Собирают в образе с Go, не отключая cgo, и копируют бинарник в alpine. Там другая реализация стандартной библиотеки C, и запуск падает с сообщением про отсутствующий файл, хотя файл лежит на месте.
Оставляют плавающие теги базовых образов. Сборка, которая вчера была зелёной, сегодня ломается без единой правки кода, и причину долго ищут в своём коде.
Собирают прямо в финальном образе с полным набором инструментов. Получается образ на сотни мегабайт с компилятором и исходниками внутри: лишняя поверхность атаки и медленный выкат каждой реплики.