Коротко: GitHub додав entrypoint і command для service containers у GitHub Actions. Якщо ти коли-небудь збирав окремий Docker-образ тільки щоб передати один прапорець базі даних у CI — ця зміна саме для тебе. Частину старих обхідних рішень тепер можна просто вимкнути.
Що саме змінилося
У квітні 2026 року GitHub оновив модель service containers у GitHub Actions: у секції jobs.<job_id>.services з’явилися два нових ключі — entrypoint і command. Вони працюють за моделлю, знайомою кожному, хто писав docker compose: entrypoint заміняє головну команду старту контейнера, а command передає їй аргументи.
Це означає, що для більшості типових сценаріїв — налаштування конфігурації БД, зміна портів, передача спеціальних прапорців — вже не потрібен окремий wrapper-образ чи додатковий крок у workflow.
Який біль це прибирає
Уявімо типову ситуацію: тобі потрібен Postgres у CI з певними налаштуваннями — наприклад, змінити shared_buffers, увімкнути розширення або поставити специфічну кодування. Раніше існувало кілька варіантів, і жоден не був ідеальним.
Варіант перший — зібрати кастомний Docker-образ, в якому в ENTRYPOINT або CMD зашиті потрібні прапорці. Це працює, але це зайва підтримка: образ треба білдити, пушити в registry, слідкувати за оновленнями базового образу Postgres.
Варіант другий — написати shell-скрипт у workflow, який піднімає сервіс руками через docker run. Це дає контроль, але робить workflow бруднішим і менш переносимим.
Варіант третій — покладатися на env і options, сподіваючись, що сервіс зрозуміє те, що ти йому передав. Часто це працює, але не завжди, особливо коли треба змінити саме команду запуску, а не лише змінні середовища.
Тепер усе це закривається двома рядками в YAML. Без wrapper-образів. Без shell-hacks. Без магії.
Приклади: як це виглядає на практиці
Postgres із специфічними прапорцями
Як було — кастомний образ або options:
services:
postgres:
image: my-registry/postgres-custom:16-with-extensions
env:
POSTGRES_PASSWORD: test
ports:
- 5432:5432
Як стало — нативний command:
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports:
- 5432:5432
command: >-
postgres
-c shared_buffers=256MB
-c max_connections=200
Тобі більше не потрібно підтримувати окремий Docker-образ з одним Dockerfile, який лише додає -c у CMD.
MySQL з нестандартним entrypoint
Припустимо, тобі треба, щоб MySQL стартував із певним init-скриптом або з обходом дефолтного entrypoint:
services:
mysql:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: test
ports:
- 3306:3306
entrypoint: ["docker-entrypoint.sh"]
command: ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
Коли entrypoint відрізняється від дефолтного, command передається йому як аргументи — так само, як у Docker Compose.
etcd для distributed-тестів
etcd часто потребує специфічних прапорців при старті, особливо якщо тести перевіряють розподілену логіку:
services:
etcd:
image: bitnami/etcd:latest
env:
ALLOW_NONE_AUTHENTICATION: "yes"
ports:
- 2379:2379
command: ["etcd", "--advertise-client-urls", "http://localhost:2379"]
Без цього раніше доводилося або знаходити спеціальний образ, або городити shell-скрипт.
Redis з кастомним конфігом
services:
redis:
image: redis:7
ports:
- 6379:6379
command: ["redis-server", "--maxmemory", "256mb", "--maxmemory-policy", "noeviction"]
Коли command достатньо, а коли треба міняти entrypoint
Правило просте.
Досить command, якщо:
- сервіс стартує нормально з дефолтного entrypoint;
- тобі треба лише передати аргументи або прапорці;
- ти змінюєш конфігурацію, яка підтримується через командний рядок.
Це покриває 80–90% випадків із базами даних і кешами в CI.
Треба міняти entrypoint, якщо:
- сервіс ігнорує
commandчерез свій Dockerfile (не які все Dockerfile, але буває); - тобі треба запустити wrapper-скрипт перед основним процесом;
- ти міняєш саму команду старту, а не лише її аргументи.
Custom image все ще потрібен, якщо:
- потрібні попередньо встановлені розширення або бібліотеки;
- треба змінити файлову систему контейнера до запуску;
- є складна процедура ініціалізації, яку не можна передати через командний рядок.
Чесні обмеження
Це не революція і не вирішення всіх проблем з CI. Варто тримати в голові кілька моментів:
- Service containers у GitHub Actions працюють тільки на Linux-раннерах. Якщо твій workflow запускається на Windows або macOS runner — це не працюватиме.
entrypointіcommandне замінюютьoptions. Для монтування volume, налаштування мережі або інших Docker-flagів все ще потрібенoptions.- Не всі сервіси добре поводяться зі зміною entrypoint чи command через CI. Деякі офіційні образи мають дуже специфічну логіку в
docker-entrypoint.sh, і її зміна може зламати ініціалізацію. - Це не стосується containerized jobs (де весь job працює в контейнері) — тільки service containers.
Що перевірити у своїх workflows завтра
Пройдися по своїх .github/workflows/ і постав собі кілька простих питань:
- Чи є у мене service containers, які використовують кастомні образи тільки для передачі прапорців?
- Чи є у мене
docker runвсередині workflow, який можна замінити на нативний service container зcommand? - Чи мій wrapper-образ містить лише зміну CMD або ENTRYPOINT? Якщо так — пора його вимкнути.
- Чи перевіряю я тести після зміни? Сервіс може стартувати інакше, і це варто побачити на CI, а не на production.
Якщо знайшов хоча б один випадок, де кастомний образ можна замінити двома рядками YAML — це вже перемога. Менше образів — менше підтримки — менше місць, де щось тихо ламається.
Що не робити
- Не видаляй кастомні образи одразу — спочатку перевір, що новий підхід дає однаковий результат у тестах.
- Не міняй
entrypointбез гострої потреби. Якщо доситьcommand— використовуйcommand. - Не забувай, що
optionsвсе ще потрібен для монтування volume, мережі та інших Docker-налаштувань. - Не припускай, що всі офіційні образи однаково реагують на зміну entrypoint — завжди тестуй.
Практичний висновок
GitHub прибрав один із найбільш дратівливих костилів у CI. Якщо твоя команда тримає інтеграційні тести в GitHub Actions і піднімає там БД або кеш — варто витратити 15 хвилин і перевірити, які wrapper-образи чи shell-hacks тепер можна прибрати без ризику.
Найкраще, що ця зміна не вимагає нічого нового: ти продовжуєш писати YAML, просто без зайвих шарів абстракції навколо сервісів, які й так вміють говорити через командний рядок.