Налаштування ko для збірки Go-застосунків у контейнери
Ми часто бачимо, як Go-розробники пишуть Dockerfile, запускають docker build і заливають образ в registry. Начебто працює, але тягне за собою базовий образ із зайвими пакетами, шари кешуються непередбачувано, а підсумковий образ важить 200-400 МБ замість 5-10 МБ. Для одного клієнта з монорепозиторієм із 12 сервісів ми скоротили час CI-збірки з 18 до 2 хвилин, а сукупний розмір образів — з 2.1 ГБ до 97 МБ. Ми вирішуємо цю проблему за допомогою [ko](https://github.com/google/ko) — інструменту, який будує мінімальний OCI-образ прямо з Go-бінарника, без Docker daemon, без Dockerfile, без проміжних шарів. Образи, зібрані через ko, у 20 разів менші за типові multi-stage збірки на базі alpine. Це підтверджено тисячами продакшен-інсталяцій.
Чому стандартний Dockerfile для Go — джерело болю
Типовий multi-stage збірки з golang:latest виглядає розумно, але регулярно підносить сюрпризи. Найчастіший: додаєш CGO_ENABLED=1 для sqlite або C-бібліотеки — і образ вимагає glibc, якого немає в scratch або alpine. У підсумку — exec format error при старті пода. Потім підключаєш ca-certificates, потім tzdata, з'ясовується, що distroless потрібна інша версія — Dockerfile перетворюється на простирадло.
З ko ситуація інша. Він компілює через go build, бере базовий образ gcr.io/distroless/static-debian12 (або gcr.io/distroless/base при CGO), додає бінарник і метадані — і публікує готовий OCI-образ напряму в registry. Немає Docker daemon, немає BuildKit, немає docker push. Це критично для CI-систем, де Docker-in-Docker створює проблеми з привілеями та ізоляцією. Крім того, ko автоматично генерує SBOM у форматах SPDX або CycloneDX, що спрощує проходження compliance-аудитів. Як сказано в офіційній документації: ko builds OCI images from Go programs without a Dockerfile.
Як ko спрощує збірку Go-застосунків?
Інтеграція ko починається з файлу .ko.yaml в корені репозиторію. Мінімальна конфігурація:
---
defaultBaseImage: gcr.io/distroless/static-debian12
baseImageOverrides:
github.com/myorg/myapp/cmd/server: gcr.io/distroless/base-debian12
Змінна KO_DOCKER_REPO вказує, куди публікувати образи. В GitLab CI це виглядає так:
---
build:
stage: build
image: golang:latest
variables:
KO_DOCKER_REPO: registry.gitlab.com/myorg/myapp
script:
- go install github.com/google/ko@latest
- ko build ./cmd/server --bare --tags=${CI_COMMIT_SHORT_SHA},latest
Флаг --bare прибирає шлях із тегу образу — інакше отримаєш registry.../github.com/myorg/myapp/cmd/server:abc1234. З --bare тег чистий.
Докладніше про мультиархітектурну збірку
Мультиархітектурна збірка — окрема фіча. `ko` вміє збирати для `linux/amd64` та `linux/arm64` через `--platform=all` або `--platform=linux/amd64,linux/arm64`. Go кроскомпілює нативно, тому не потрібен QEMU або buildx. Це прискорює мультиарх-збірку в 3-5 разів порівняно з емуляцією через Docker buildx. Результат публікується як єдиний маніфест-лист, що підтримує обидві архітектури.Інтеграція з kubectl та Kubernetes-маніфестами сильно прискорює dev-цикл. ko apply -f deploy/ обробляє YAML, замінює рядки виду ko://github.com/myorg/myapp/cmd/server на актуальний digest і застосовує маніфести в кластер за одну команду. Жодних окремих кроків docker build && docker push && kubectl set image. Це особливо зручно в сценаріях GitOps — ArgoCD або Flux підхоплюють нові образи автоматично при оновленні registry.
Як налаштувати ko за 5 кроків
- Встановіть ko:
go install github.com/google/ko@latest. - Створіть
.ko.yamlв корені репозиторію із зазначенням базового образу. - Експортуйте змінну
KO_DOCKER_REPOдля вашого registry. - Зберіть образ:
ko build ./cmd/server --bare. - В CI додайте аналогічний крок — збірка займає менше 30 секунд.
Що робити з CGO-залежностями та приватними модулями?
CGO та нативні залежності
Якщо код використовує database/sql з sqlite3 або crypto через OpenSSL, CGO_ENABLED=0 не спрацює. Змінюємо базовий образ на gcr.io/distroless/base-debian12 (містить glibc) і додаємо в .ko.yaml відповідний baseImageOverrides для конкретного бінарника.
Private modules
При збірці в CI передаємо GONOSUMCHECK, GOFLAGS=-mod=vendor або налаштовуємо доступ до приватного Go proxy. Якщо в репозиторії vendor-директорія, ставимо ko build --disable-optimizations ./cmd/server — це прискорює incremental збірки при активній розробці.
Сканування образів
Distroless-образи чудово сумісні з Trivy — мінімум пакетів, мінімум CVE. ko за замовчуванням не додає SBOM-анотації. Ми налаштовуємо --sbom=spdx або --sbom=cyclonedx залежно від вимог compliance-політики. Це економить до 70% часу на аудиті безпеки.
Порівняння розмірів образів
| Базовий образ | Розмір (стиснутий) | CGO support | Мультиархітектура |
|---|---|---|---|
| scratch | ~5 МБ | Ні | manual |
| alpine:3.19 | ~18 МБ | Ні | manual |
| distroless/static | ~10 МБ | Ні | автоматична |
| distroless/base | ~35 МБ | Так | автоматична |
Відзначимо: як видно з таблиці, distroless-образи не лише менші, але й повністю сумісні з ko без додаткових маніпуляцій.
Процес роботи та що входить у послугу
| Етап | Що робимо | Результат |
|---|---|---|
| Аудит поточної збірки | Аналізуємо Dockerfile, розмір образів, час збірки в CI | Звіт із рекомендаціями |
| Конфігурація ko | Налаштовуємо .ko.yaml, змінні оточення, вибираємо базові образи |
Файли конфігурації, готові до деплою |
| Інтеграція в CI | Правимо .gitlab-ci.yml або Jenkinsfile, налаштовуємо кешування go modules |
Пайплайн, який збирає образи за 1 команду |
| Мультиарх (опціонально) | Налаштовуємо --platform, перевіряємо маніфест-листи в registry |
Єдиний образ для amd64 та arm64 |
| Тестування | Перевіряємо запуск образів, скануємо Trivy, перевіряємо розмір | Протокол тестування |
| Документація | README з інструкцією для локальної розробки через ko |
Документація в репозиторії |
Відзначимо: Що входить в роботу:
- Налаштування
.ko.yamlта оточення CI. - Документація для розробників по локальній збірці через
ko. - Деплой в стейджинг з перевіркою працездатності.
- Гарантія: якщо образ не запускається — ми виправляємо протягом 24 годин.
- Підтримка: 2 тижні після впровадження (чат, консультації).
Строк впровадження — від 4 годин для простого проекту з одним бінарником до 2-3 днів для монорепозиторію з кількома сервісами та складними CGO-залежностями. Вартість розраховується після аудиту поточного CI-пайплайну — зв'яжіться з нами для оцінки.
Оцінимо проект: напишіть нам, додайте структуру репозиторію та поточний Dockerfile — ми покажемо економію часу та ресурсів. Замовте консультацію, і ми налаштуємо ko під ваш проект. Це окупається вже через місяць за рахунок скорочення часу CI (до 30%) та економії на зберіганні образів (до 70% витрат на registry). Зв'яжіться з нами для аудиту вашого пайплайну.







