Продолжаю эксперименты с контейнеризацией агентов. Решил добавить внутрь контейнера PHP с версиями от 8.1 до 8.5 и необходимыми расширениями. PHP собираю из исходников, поэтому в Dockerfile использую многоэтапную сборку. В итоге Dockerfile вырос до неприличных размеров, читать и поддерживать его в таком виде стало довольно сложно.
Сам по себе Dockerfile не поддерживает разбиение на несколько файлов. Но есть несколько путей, как решить эту задачу.
Генерация Dockerfile — разбиваем Dockerfile на несколько и пишем скрипт, который перед сборкой образа будет собирать один Dockerfile.
Промежуточные образы — разбиваем Dockerfile на несколько по стадиям, а при сборке образа выполняем сборку каждой стадии отдельно, но в нужном порядке.
В обоих вариантах мне не нравится, что нужно писать и поддерживать что-то своё — в первом случае скрипт генерации, а во втором список команд для сборки.
К счастью, есть и третий вариант — Bake. Это команда Docker Buildx для декларативного управления сборками образов через конфигурационный файл в формате JSON или HCL. Мне понравился HCL, выглядит чище, чем JSON. В моём случае файл
docker-bake.hcl получился примерно такой:variable "DEBIAN_VERSION" {
default = "13"
}
group "default" {
targets = ["pi", "claude-code"]
}
target "php-builder" {
dockerfile = "docker/php-builder/Dockerfile"
context = "."
args = {
DEBIAN_VERSION = DEBIAN_VERSION
}
}
target "php-8-1" {
dockerfile = "docker/php-8.1/Dockerfile"
context = "."
contexts = {
php-builder = "target:php-builder"
}
}
# ...
target "base" {
dockerfile = "docker/Dockerfile"
target = "base"
context = "."
contexts = {
php-8-1 = "target:php-8-1"
php-8-2 = "target:php-8-2"
php-8-3 = "target:php-8-3"
php-8-4 = "target:php-8-4"
php-8-5 = "target:php-8-5"
}
args = {
DEBIAN_VERSION = DEBIAN_VERSION
}
}
target "pi" {
inherits = ["base"]
target = "pi"
tags = ["pi-harness:latest"]
}
target "claude-code" {
inherits = ["base"]
target = "claude-code"
tags = ["claude-code-harness:latest"]
}Таким образом я разбил один большой Dockerfile на несколько: каждая стадия — отдельный файл. Конфигурация Bake описывает как и в каком порядке собирать образы. Сама сборка выполняется просто командой:
# Pi Harness image
docker buildx bake -f docker/docker-bake.hcl pi
# Claude Code Harness image
docker buildx bake -f docker/docker-bake.hcl claude-code
Помимо декларативного описания зависимостей Bake умеет в параллельную сборку стадий, что ещё и ускоряет сборку 🚀
Удобная штука 🙂