Интеграция реестра образов с CI/CD пайплайнами: Jenkins, GitLab CI, GitHub Actions | AdminWiki

Интеграция реестра образов с CI/CD пайплайнами: Jenkins, GitLab CI, GitHub Actions

03 августа 2026 9 мин. чтения

Ручная публикация Docker-образов в реестр отнимает время и создает риски. Инженер выполняет команды локально, забывает обновить тег, загружает образ с уязвимостями или использует устаревшие учетные данные. Автоматизация этих шагов в CI/CD-пайплайне устраняет человеческий фактор и делает процесс воспроизводимым.

По данным State of DevOps Report 2025, команды с автоматизированными пайплайнами развертывают код в 208 раз чаще и имеют в 7 раз более низкий уровень отказов. Интеграция реестра образов с Jenkins, GitLab CI или GitHub Actions - это фундамент, с которого начинается надежная доставка контейнеризованных приложений. В этой статье вы получите готовые конфигурации для трех CI/CD-систем, стратегии тегирования, настройку проверки лицензий и автоматическую очистку устаревших образов.

Перед внедрением пайплайнов убедитесь, что понимаете архитектуру контейнерной безопасности. В материале по защите реестра образов разобраны сканирование уязвимостей, RBAC и подписание образов - эти практики дополнят ваш CI/CD.

Почему автоматизация публикации образов - это must-have

Ручной процесс выглядит так: разработчик собирает образ, придумывает тег, выполняет docker login и docker push. На первый взгляд - три команды. На практике возникают проблемы: тег дублируется, образ загружен с локальной машины с нестандартными зависимостями, пароль сохранен в истории shell. При масштабировании до пяти микросервисов и трех окружений этот процесс становится неуправляемым.

Автоматизированный пайплайн решает эти проблемы системно. Сборка запускается по триггеру - коммит, тег, pull request. Окружение чистое и воспроизводимое. Теги присваиваются по заданной стратегии без участия человека. Учетные данные хранятся в защищенном хранилище CI/CD-системы и никогда не попадают в код. Результат: скорость доставки растет, количество инцидентов из-за неправильной версии образа стремится к нулю.

Если вы только начинаете выстраивать CI/CD-конвейер, изучите полное руководство по настройке CI/CD-пайплайнов - там разобрана архитектура от коммита до продакшена с Docker и Kubernetes.

Подготовка реестра и аутентификации

Пайплайну нужен реестр для хранения образов и учетные данные для доступа к нему. Выбор реестра зависит от инфраструктуры: Docker Hub подходит для публичных проектов, GitLab Container Registry встроен в GitLab и не требует дополнительных сервисов, GitHub Container Registry интегрирован с Actions, Harbor дает корпоративные функции вроде RBAC и сканирования уязвимостей.

Независимо от выбранного реестра, используйте токены вместо основного пароля. Токен можно отозвать в любой момент без смены пароля учетной записи. В Docker Hub создайте токен в разделе Account Settings > Security > New Access Token. Сохраните его - значение показывается один раз.

Создание учетных данных для CI/CD

Jenkins хранит секреты через плагин Credentials Binding. Установите плагин, перейдите в Manage Jenkins > Manage Credentials, добавьте запись типа Username with password. Укажите ID, например dockerhub-credentials - он понадобится в Jenkinsfile.

В GitLab переменные задаются в Settings > CI/CD > Variables. Добавьте DOCKER_USERNAME и DOCKER_PASSWORD. Включите флаг Masked - значения будут скрыты в логах сборки. Для приватных проектов включите Protected, чтобы переменные были доступны только в защищенных ветках.

GitHub Actions использует Secrets уровня репозитория: Settings > Secrets and variables > Actions > New repository secret. Создайте DOCKER_USERNAME и DOCKER_TOKEN. Секреты не отображаются в логах и недоступны в форках.

Интеграция с Jenkins: пошаговая настройка

Jenkins требует два плагина: Docker Pipeline для команд docker и Credentials Binding для работы с секретами. Установите их через Manage Jenkins > Plugins. Создайте новый Pipeline-проект, в разделе Pipeline выберите Pipeline script from SCM и укажите репозиторий с Jenkinsfile.

Пример Jenkinsfile для сборки и публикации

pipeline {
    agent any
    environment {
        DOCKER_IMAGE = 'myapp'
        DOCKER_REGISTRY = 'docker.io'
        DOCKER_ORG = 'yourusername'
        DOCKER_CREDS = credentials('dockerhub-credentials')
    }
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Build') {
            steps {
                script {
                    def tag = "${env.BUILD_NUMBER}-${env.GIT_BRANCH.replaceAll('/', '-')}"
                    def fullImage = "${DOCKER_REGISTRY}/${DOCKER_ORG}/${DOCKER_IMAGE}:${tag}"
                    docker.build(fullImage)
                    env.FULL_IMAGE = fullImage
                }
            }
        }
        stage('Push') {
            steps {
                script {
                    docker.withRegistry("https://${DOCKER_REGISTRY}", DOCKER_CREDS) {
                        docker.image(env.FULL_IMAGE).push()
                    }
                }
            }
        }
    }
    post {
        always {
            sh 'docker image prune -f'
        }
        failure {
            echo 'Публикация образа не удалась. Проверьте логи сборки.'
        }
    }
}

Этапы пайплайна: Checkout забирает код, Build собирает образ с тегом из номера сборки и ветки, Push выполняет аутентификацию через docker.withRegistry и загружает образ. Блок post очищает локальные образы после публикации и выводит сообщение при ошибке. Переменная DOCKER_CREDS автоматически подставляет username и password из Credentials Binding.

Интеграция с GitLab CI: конфигурация .gitlab-ci.yml

GitLab CI предлагает встроенный Container Registry для каждого проекта. URL реестра доступен в переменной CI_REGISTRY, временные учетные данные - в CI_REGISTRY_USER и CI_REGISTRY_PASSWORD. Для сборки образов используйте Docker-in-Docker (dind) или kaniko, если привилегированный режим недоступен.

Пример с dind требует runner с привилегированным режимом. Это подходит для собственных раннеров, где вы контролируете безопасность. Для SaaS-раннеров GitLab.com или изолированных сред используйте kaniko.

Сборка и публикация с использованием kaniko

stages:
  - build

build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor
      --context "$CI_PROJECT_DIR"
      --dockerfile "$CI_PROJECT_DIR/Dockerfile"
      --destination "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
      --destination "$CI_REGISTRY_IMAGE:latest"
  only:
    - main

Kaniko собирает образ без демона Docker, что безопаснее в CI-окружении. Конфигурация создает файл config.json с учетными данными, затем выполняет сборку и публикует образ с двумя тегами: короткий SHA коммита и latest. Пайплайн запускается только для ветки main.

Интеграция с GitHub Actions: workflow для Docker

GitHub Actions использует официальные actions от Docker: docker/login-action для аутентификации и docker/build-push-action для сборки и публикации. Workflow-файл размещается в .github/workflows/docker-publish.yml.

Пример workflow с тегированием по веткам и тегам

name: Docker Build and Push

on:
  push:
    branches:
      - main
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: yourusername/myapp
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha,prefix=

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Workflow запускается при push в main и при создании тегов формата v*. docker/metadata-action генерирует теги автоматически: для ветки main - latest, для тега v1.2.3 - 1.2.3 и 1.2, для любого коммита - SHA. Кэширование слоев через GitHub Actions Cache ускоряет повторные сборки в разы.

Стратегии тегирования образов

Тег образа определяет, какую версию приложения получат потребители. Стратегия «только latest» приводит к невоспроизводимым развертываниям: нельзя откатиться на конкретную версию, нельзя понять, какой коммит внутри образа. Минимальная стратегия - два тега: уникальный (SHA коммита) и семантический (1.2.3).

Уникальный тег гарантирует, что каждый образ идентифицируется однозначно. Семантический тег упрощает чтение и выбор версии человеком. Для production-окружений используйте семантические теги, для staging - SHA, для feature-веток - имя ветки.

Автоматическое присвоение тегов в пайплайнах

В Jenkins тег формируется из переменных окружения: BUILD_NUMBER дает уникальность, GIT_BRANCH - контекст. Пример: tag = "${BUILD_NUMBER}-${GIT_BRANCH}". Для семантического тегирования извлекайте версию из файла VERSION или git describe.

GitLab CI предоставляет CI_COMMIT_SHORT_SHA (8 символов хеша), CI_COMMIT_TAG (тег, если сборка запущена по тегу), CI_COMMIT_REF_NAME (имя ветки или тега). Комбинация CI_COMMIT_TAG для релизов и CI_COMMIT_SHORT_SHA для промежуточных сборок покрывает все сценарии.

GitHub Actions через github.sha получает полный SHA коммита, github.ref - полную ссылку (refs/heads/main). docker/metadata-action автоматизирует преобразование этих значений в осмысленные теги и избавляет от ручного написания shell-скриптов.

Проверка лицензий зависимостей в CI/CD

Образ контейнера содержит не только ваше приложение, но и сотни зависимостей с разными лицензиями. Использование пакета с лицензией GPL в проприетарном продукте может привести к юридическим последствиям вплоть до требования открыть исходный код. Автоматическая проверка лицензий в пайплайне предотвращает такие инциденты.

Инструменты для анализа: Syft генерирует Software Bill of Materials (SBOM) в формате SPDX, Trivy проверяет лицензии по этому SBOM, Grype интегрируется с реестрами. Все три инструмента работают в CI/CD без дополнительной инфраструктуры.

Пример интеграции Trivy в GitHub Actions

- name: License check
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'fs'
    scanners: 'license'
    scan-ref: '.'
    exit-code: '1'
    severity: 'CRITICAL'
    license-full: true
- name: Check forbidden licenses
  run: |
    trivy fs --scanners license --license-full . 2>&1 | tee license-report.txt
    if grep -qE 'GPL|AGPL' license-report.txt; then
      echo "Обнаружены запрещенные лицензии"
      exit 1
    fi

Первый шаг выполняет базовое сканирование с падением пайплайна при критических проблемах. Второй шаг целенаправленно ищет GPL и AGPL - наиболее рискованные лицензии для проприетарного ПО. Список запрещенных лицензий настраивается под политику компании.

Автоматическая очистка устаревших образов

Реестр без очистки растет экспоненциально. Каждый коммит в feature-ветку генерирует новый образ, который становится ненужным после слияния. За месяц активной разработки реестр может занять десятки гигабайт, а стоимость хранения в облачных реестрах растет пропорционально объему.

GitLab Container Registry поддерживает политики очистки тегов: Project > Settings > Packages and registries > Cleanup policies. Настройте удаление образов без тегов и образов старше 30 дней. Harbor предоставляет retention policies с гибкими правилами: оставлять последние N версий, удалять образы без загрузок за период.

Скрипт для очистки Docker Hub через API

#!/bin/bash
# Удаление образов старше 90 дней из Docker Hub
TOKEN=$(curl -s -H "Content-Type: application/json" \
  -d "{\"username\":\"$DOCKER_USERNAME\",\"password\":\"$DOCKER_TOKEN\"}" \
  https://hub.docker.com/v2/users/login/ | jq -r .token)

REPO="yourusername/myapp"
CUTOFF_DATE=$(date -d '90 days ago' +%Y-%m-%d)

curl -s -H "Authorization: JWT $TOKEN" \
  "https://hub.docker.com/v2/repositories/$REPO/tags?page_size=100" | \
  jq -r ".results[] | select(.last_updated < \"$CUTOFF_DATE\") | .name" | \
  while read tag; do
    echo "Удаление тега: $tag"
    curl -X DELETE -H "Authorization: JWT $TOKEN" \
      "https://hub.docker.com/v2/repositories/$REPO/tags/$tag/"
  done

Скрипт получает токен API, запрашивает список тегов, фильтрует по дате последнего обновления и удаляет устаревшие. Запускайте его по расписанию в CI/CD - например, через scheduled pipeline в GitLab или cron в GitHub Actions. Для образов, используемых в production, установите более длительный срок хранения или исключите их из очистки по тегу.

Лучшие практики и частые ошибки

Безопасность начинается с секретов. Никогда не коммитьте DOCKER_USERNAME и DOCKER_PASSWORD в репозиторий - даже в закомментированном виде. Используйте встроенные механизмы CI/CD: Jenkins Credentials, GitLab Variables, GitHub Secrets. Для корпоративных сред рассмотрите HashiCorp Vault как единое хранилище секретов с аудитом доступа.

Кэширование слоев сокращает время сборки на 50-80%. В GitLab CI настройте кэш для Docker-слоев через volumes, в GitHub Actions используйте type=gha, в Jenkins сохраняйте образы между запусками через docker.image.withoutRegistry. Многоэтапные сборки (multi-stage builds) уменьшают размер финального образа и ускоряют загрузку.

Типичные ошибки, которых следует избегать: хардкод тега latest в production-манифестах - используйте точную версию или SHA; отсутствие очистки реестра - настройте политики сразу при создании; игнорирование лицензий - добавьте проверку в пайплайн до того, как юристы зададут вопрос. Чек-лист для внедрения: создайте токен реестра, добавьте секреты в CI/CD, скопируйте конфигурацию пайплайна под вашу систему, настройте стратегию тегирования, включите проверку лицензий, запланируйте очистку. Выполнив эти шаги, вы получите воспроизводимый и безопасный процесс публикации образов.

Для углубления в тему CI/CD с Docker изучите руководство по настройке пайплайна от сборки до деплоя, где разобраны этапы тестирования и сканирования уязвимостей внутри контейнера. Если ваша инфраструктура описана кодом, материал по тестированию IaC в CI/CD поможет автоматизировать проверку безопасности до публичного запуска.

Поделиться:
Сохранить гайд? В закладки браузера