← Назад к вопросам

Как настроить Pipelines, чтобы один и тот же образ собирался с несколькими тегами

1.7 Middle🔥 211 комментариев
#CI/CD и автоматизация#Docker и контейнеризация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Настройка тегирования образов в CI/CD пайплайнах

Настройка сборки Docker-образов с несколькими тегами — это стандартная практика в DevOps, которая обеспечивает гибкость управления версиями и удобство развертывания. Вот комплексный подход с примерами для популярных CI/CD систем.

Основные принципы тегирования

Перед реализацией определите стратегию тегирования:

  • Стабильные теги: latest, v1.2.3, production
  • Динамические теги: хеш коммита, ветка, timestamp
  • Мета-теги: v1.2, v1 (semantic versioning)

Реализация в GitHub Actions

name: Build and Push Docker Image
on:
  push:
    branches: [ main, develop ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      
      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
      
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Реализация в GitLab CI

stages:
  - build

variables:
  DOCKER_TLS_CERTDIR: "/certs"
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

docker-build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - |
      # Определяем дополнительные теги
      ADDITIONAL_TAGS=""
      
      # Для main ветки добавляем latest
      if [ "$CI_COMMIT_BRANCH" = "main" ]; then
        ADDITIONAL_TAGS="$ADDITIONAL_TAGS,$CI_REGISTRY_IMAGE:latest"
      fi
      
      # Для тегов добавляем semantic versioning
      if [ -n "$CI_COMMIT_TAG" ]; then
        ADDITIONAL_TAGS="$ADDITIONAL_TAGS,$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG"
        # Извлекаем major и minor версии
        VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
        MAJOR=$(echo $VERSION | cut -d. -f1)
        MINOR=$(echo $VERSION | cut -d. -f1-2)
        ADDITIONAL_TAGS="$ADDITIONAL_TAGS,$CI_REGISTRY_IMAGE:$MAJOR,$CI_REGISTRY_IMAGE:$MINOR"
      fi
      
      # Собираем и пушим с несколькими тегами
      docker build -t $IMAGE_TAG .
      
      # Пушим основной тег
      docker push $IMAGE_TAG
      
      # Пушим дополнительные теги
      if [ -n "$ADDITIONAL_TAGS" ]; then
        for tag in $(echo $ADDITIONAL_TAGS | tr ',' ' '); do
          docker tag $IMAGE_TAG $tag
          docker push $tag
        done
      fi
  rules:
    - if: $CI_COMMIT_BRANCH || $CI_COMMIT_TAG

Реализация в Jenkins

pipeline {
    agent any
    
    environment {
        DOCKER_REGISTRY = 'myregistry.com'
        PROJECT_NAME = 'myapp'
        COMMIT_SHORT_SHA = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
    }
    
    stages {
        stage('Build and Tag') {
            steps {
                script {
                    // Собираем список тегов
                    def tags = []
                    
                    // Базовый тег с хешем коммита
                    tags.add("${DOCKER_REGISTRY}/${PROJECT_NAME}:${COMMIT_SHORT_SHA}")
                    
                    // Для master ветки
                    if (env.BRANCH_NAME == 'master') {
                        tags.add("${DOCKER_REGISTRY}/${PROJECT_NAME}:latest")
                        
                        // Читаем версию из package.json или другого файла
                        def version = readJSON(file: 'package.json').version
                        tags.add("${DOCKER_REGISTRY}/${PROJECT_NAME}:${version}")
                        tags.add("${DOCKER_REGISTRY}/${PROJECT_NAME}:v${version.split('\\.')[0]}")
                    }
                    
                    // Для feature веток
                    if (env.BRANCH_NAME.startsWith('feature/')) {
                        def branchTag = env.BRANCH_NAME.replace('feature/', '').replace('/', '-')
                        tags.add("${DOCKER_REGISTRY}/${PROJECT_NAME}:${branchTag}")
                    }
                    
                    // Собираем и тегируем
                    docker.build("${DOCKER_REGISTRY}/${PROJECT_NAME}", "--tag ${tags.join(' --tag ')} .")
                    
                    // Пушим все теги
                    tags.each { tag ->
                        docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                            docker.image(tag).push()
                        }
                    }
                }
            }
        }
    }
}

Лучшие практики

  1. Используйте хеш коммита как базовый тег — обеспечивает точную воспроизводимость сборок
  2. Автоматизируйте semantic versioning — интегрируйте с CHANGELOG и conventional commits
  3. Очищайте старые теги — настройте политику retention policy в registry
  4. Тестируйте перед пушем — запускайте тесты для каждого тегированного образа
  5. Используйте multi-stage builds — уменьшайте размер финального образа

Скрипт для локальной сборки с несколькими тегами

#!/bin/bash
# build-with-tags.sh

IMAGE_NAME="myapp"
REGISTRY="myregistry.com"
VERSION=$(git describe --tags --always)
COMMIT_SHA=$(git rev-parse --short HEAD)

# Сборка образа
docker build -t ${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA} .

# Создание дополнительных тегов
docker tag ${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA} ${REGISTRY}/${IMAGE_NAME}:latest

if [[ $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    MAJOR=$(echo $VERSION | cut -d. -f1)
    MINOR=$(echo $VERSION | cut -d. -f1-2)
    
    docker tag ${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA} ${REGISTRY}/${IMAGE_NAME}:${VERSION}
    docker tag ${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA} ${REGISTRY}/${IMAGE_NAME}:${MINOR}
    docker tag ${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA} ${REGISTRY}/${IMAGE_NAME}:${MAJOR}
fi

# Пуш всех тегов
docker push --all-tags ${REGISTRY}/${IMAGE_NAME}

Оптимизация производительности

Для ускорения процесса используйте:

  • Buildx с кешированием--cache-from, --cache-to
  • Параллельный пуш тегов — если registry поддерживает
  • Артефакты сборки — сохраняйте context между этапами

Такая настройка обеспечивает гибкое тегирование, совместимость с различными окружениями и соответствие принципам semantic versioning, что критически важно для эффективного DevOps-процесса.

Как настроить Pipelines, чтобы один и тот же образ собирался с несколькими тегами | PrepBro