Как мне кэшировать в gitlab ci при создании образов docker с помощью docker: dind

#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