В CI билдить приложение можно как в окружении runner, так и в docker in docker.
Если в первом случае мы можем сделать service specific конфигурацию, настроить кеши и т.д. То во втором случае мы будем в меньшей степени зависить от конкретного CI сервиса и не придется для теста билда гонять CI.
Но при билде docker-in-docker возникает вопрос производительности и кеширования.
Универсальный способ - спулить последний образ и использовать его как кеш.
Вот пример из документации gitlab https://docs.gitlab.com/ee/ci/docker/using_docker_build.html
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
Но если Dockerfile содержит несколько stage, то данный вариант не будет работать, так как кешироваться будет только последняя стадия.
К счастью есть способ, который позволяет обойти эту проблему. Нам нужны образы каждой стадии.
Вот пример для образа из двух стадий
variables:
DOCKER_BUILDKIT: 1
.build_script: &build_script
script:
- docker pull $IMAGE_BUILD_TAG || true
- docker build --target build-stage --build-arg BUILDKIT_INLINE_CACHE=1 -t $IMAGE_BUILD_TAG --cache-from $IMAGE_BUILD_TAG .
- docker push $IMAGE_BUILD_TAG
- docker pull $IMAGE_TAG1 || true
- docker build --target deploy-stage --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $IMAGE_BUILD_TAG --cache-from $IMAGE_TAG1 -t $IMAGE_TAG1 -t $IMAGE_TAG2 .
- docker push $IMAGE_TAG1
- docker push $IMAGE_TAG2
Для этого нам понадобится