Как в GitLab CI собрать один Docker-образ с несколькими тегами?

«Как в GitLab CI собрать один Docker-образ с несколькими тегами?» — вопрос из категории CI/CD, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В GitLab CI/CD для сборки одного образа с несколькими тегами используется команда docker build с несколькими флагами -t. Вот пример реализации в .gitlab-ci.yml:

variables:
  # Используем встроенный Container Registry GitLab
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build_and_push:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    # Логинимся в registry GitLab
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    # Собираем образ один раз, но с двумя тегами: по хешу коммита и latest
    - docker build -t $IMAGE_TAG -t $CI_REGISTRY_IMAGE:latest .
    # Пушим оба тега
    - docker push $IMAGE_TAG
    - docker push $CI_REGISTRY_IMAGE:latest
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Ключевые моменты:

  • Одна сборка, несколько тегов: Команда docker build -t image:tag1 -t image:tag2 . создает один образ с идентичными слоями, но разными именами. Это эффективнее, чем несколько сборок.
  • Осмысленные теги: Я использую $CI_COMMIT_SHORT_SHA для уникальной идентификации сборки от конкретного коммита и latest для указания на последнюю стабильную версию.
  • Правила пуша: Тег latest я обновляю только при мерже в основную ветку (main/master), что задается в секции rules. Для feature-веток пушится только тег с хешем.

Альтернативный подход с массивом тегов:

script:
  - TAGS=("$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:latest")
  - docker build $(printf "-t %s " "${TAGS[@]}") .
  - for tag in "${TAGS[@]}"; do docker push "$tag"; done