#docker #caching #gitlab-ci #docker-in-docker
# #докер #кэширование #gitlab-ci #докер-в-докере
Вопрос:
У меня есть gitlab-ci.yml
вот такой:
build and push docker image:
stage: publish
variables:
DOCKER_REGISTRY: amazon-registry
AWS_DEFAULT_REGION: ap-south-1
APP_NAME: sample-app
DOCKER_HOST: tcp://docker:2375
image:
name: amazon/aws-cli
entrypoint: [""]
services:
- docker:dind
before_script:
- amazon-linux-extras install docker
script:
- docker build -t $DOCKER_REGISTRY/$APP_NAME:master .
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker push $DOCKER_REGISTRY/$APP_NAME:master
Выполнение этого шага занимает 19=8 минут, поскольку шаги создания образа docker не кэшируются. Я хочу иметь возможность кэшировать before_script amazon-linux-extras install docker
, а также образ docker, который я создаю. Мы работаем на наших собственных бегунах gitlab. Я искал ответы, но нашел решения 4-летней давности. Есть ли способ разобраться в этом? Кроме того, будет ли отказ от docker:dind
помощи?
Ответ №1:
Одна вещь, которую я пробовал, — это использовать слой кэша в сборке docker.
Вы можете извлечь существующий образ из своего реестра, а затем создать с --cache-from
помощью параметра.
Оболочка задания будет выглядеть следующим образом:
variables:
IMAGE_TAG: $DOCKER_REGISTRY/$APP_NAME:master
script:
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker pull $IMAGE_TAG || true
- docker build --cache-from $IMAGE_TAG -t $IMAGE_TAG .
- docker push $IMAGE_TAG
Этот метод также упоминается в официальном документе gitlab-ci.
Комментарии:
1. Спасибо, Карл, я почему-то не понял, что сначала нужно извлечь изображение 😉
2. Я выполнил все вышеперечисленное, но Docker по-прежнему устанавливает зависимости с нуля. Есть ли другой способ?
3. Я не уверен, есть ли другой способ. Может быть, вы могли бы попробовать этот метод в принятом ответе.
Ответ №2:
Кэш CI Gitlab работает не совсем так. Если у вас есть задание, которое устанавливает зависимости npm, например, вы можете кэшировать результирующий node_modules
каталог, чтобы npm install
его не нужно было запускать снова, но это не поможет для таких вещей, как установка системных пакетов.
Что касается docker:dind
службы, вы не сможете запускать команды, подобные docker build...
docker push ...
этой службе или без нее, даже если вы переключили изображение, которое использует ваша работа docker:latest
. Это немного нелогично, но единственный способ выполнить эти команды — использовать службу docker-in-docker .
Однако вам не повезло. Я бы рекомендовал вам переместить шаг на вашем before_script
этапе в свой собственный образ docker, который расширяется amazon/aws-cli
. Пока у вас есть доступ к docker hub, включенный реестр Gitlab (если используется gitlab.com он доступен, в противном случае администратор должен включить / настроить его), реестр Amazon (ECR, я думаю?) Или частный реестр, вы можете создавать свои собственные изображения и использовать их вКонвейеры Gitlab CI.
Вот пример файла Dockerfile:
FROM amazon/aws-cli
RUN amazon-linux-extras install docker
Это все, что вам нужно для расширения существующего amazon/aws-cli
образа и переноса ваших before_script
установок в Docker. Как только файл будет готов, запустите
docker build /path/to/dockerfile-directory -t my_tag:latest
После этого вам нужно будет войти в свой реестр, docker login my.registry.example.com
, и нажать на изображение docker push my_tag:latest
. Если вы не используете реестр Gitlab или общедоступный docker hub, вам необходимо настроить свои задания или исполнители (либо), чтобы они могли проходить аутентификацию в вашем реестре. Вы можете прочитать об этом здесь: https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-an-image-from-a-private-container-registry
Далее вам просто нужно использовать его в своих конвейерах:
build and push docker image:
stage: publish
variables:
DOCKER_REGISTRY: amazon-registry
AWS_DEFAULT_REGION: ap-south-1
APP_NAME: sample-app
DOCKER_HOST: tcp://docker:2375
image:
name: my_tag:latest
entrypoint: [""]
services:
- docker:dind
script:
- docker build -t $DOCKER_REGISTRY/$APP_NAME:master .
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker push $DOCKER_REGISTRY/$APP_NAME:master
Еще одна вещь, которую вы можете сделать, чтобы сэкономить время конвейера (если оно применимо), — это запускать этот шаг только тогда, когда ваш Dockerfile изменился. Таким образом, если этого не произошло, но другие задания полагаются на это, они могут просто повторно использовать последнее созданное изображение. Вы можете сделать это с rules
помощью ключевого слова вместе с changes
:
build and push docker image:
stage: publish
variables:
DOCKER_REGISTRY: amazon-registry
AWS_DEFAULT_REGION: ap-south-1
APP_NAME: sample-app
DOCKER_HOST: tcp://docker:2375
image:
name: my_tag:latest
entrypoint: [""]
services:
- docker:dind
when: never
rules:
- changes:
- Dockerfile
when: always
script:
- docker build -t $DOCKER_REGISTRY/$APP_NAME:master .
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker push $DOCKER_REGISTRY/$APP_NAME:master
Корневой уровень when: never
устанавливает значение по умолчанию для задания, чтобы оно никогда не выполнялось, но rules
раздел проверяет, есть ли изменения в Dockerfile (при необходимости принимает несколько файлов). Если есть изменения, задание всегда будет выполняться.
Вы можете увидеть подробную информацию о rules
ключевом слове здесь: https://docs.gitlab.com/ee/ci/yaml/#rules
Вы можете увидеть подробную информацию о пользовательских образах docker для Gitlab CI здесь: https://docs.gitlab.com/ee/ci/docker/using_docker_images.html