Дайджесты новостей
Изометрическая 3D-схема контроллера Portager в кластере Kubernetes, синхронизирующего контейнерные образы между реестрами.

Portager: декларативный перенос и зеркалирование контейнерных образов в Kubernetes

Если ты хоть раз администрировал кластеры Kubernetes в закрытых корпоративных сетях или изолированных контурах (air-gapped), то наверняка знаешь эту боль: рабочим нодам категорически запрещен прямой выход в публичные реестры вроде Docker Hub или GitHub Packages. Политики безопасности требуют, чтобы все контейнерные образы хранились исключительно во внутренних доверенных репозиториях компании — в локальном Harbor, AWS ECR или Nexus.

Обычно эту задачу решают по старинке: пишут громоздкие скрипты на bash в CI/CD пайплайнах, настраивают хрупкие крон-джобы на сервере сборки или пытаются включить облачные pull-through кэши, которые работают только внутри одного конкретного провайдера. Но стоит упасть раннеру или обновиться токену авторизации — и вся доставка артефактов встаёт колом.

Решить эту проблему нативно призван новый открытый Kubernetes-оператор Portager версии v0.5.0. Он переносит логику синхронизации прямо в Control Plane кластера, превращая зеркалирование образов в прозрачный GitOps-процесс.

Анатомия оператора: CRD ImageSync и реконсиляция по расписанию

Название проекта отсылает к историческому термину portage (волок) — практике переноса судов и грузов по суше между реками. В мире контейнеров оператор переносит OCI-артефакты между изолированными реестрами.

Вместо спагетти-скриптов инженеры описывают желаемое состояние через кастомный ресурс (Custom Resource Definition) ImageSync. Контроллер оператора работает по заданному cron-расписанию (например, каждые 6 часов) или реагирует на ручные триггеры через аннотации:

  1. Проверка манифестов без скачивания слоёв: контроллер отправляет легковесный HTTP-запрос HEAD в исходный и целевой реестры и сверяет SHA256-дайджесты манифестов. Если дайджесты совпадают, слои образа даже не скачиваются по сети.
  2. Динамическая фильтрация тегов по SemVer: вместо жесткой фиксации каждого патча (1.27.1, 1.27.2) оператор поддерживает диапазоны версий вида ~1.27.0 или ^22.0.0, автоматически подтягивая свежие обновления безопасности.
  3. Автосоздание репозиториев (createDestinationRepos: true): при синхронизации в AWS ECR или Harbor оператор сам создает целевой репозиторий при его отсутствии, предотвращая ошибки отклонения push.

Все события транслируются в стандартную ленту Kubernetes Events (kubectl describe imagesync), что позволяет мониторить статус зеркалирования без копания в чужих пайплайнах.

Практическая настройка: от Helm-чарта до AWS ECR

Установка оператора в кластер выполняется буквально за пару минут с помощью официального Helm-чарта, опубликованного в открытом OCI-реестре GitHub:

# Установка оператора Portager v0.5.0 из официального OCI-реестра
helm install portager oci://ghcr.io/jarodr47/portager/charts/portager \
  --version 0.5.0 \
  --namespace portager-system \
  --create-namespace

# Проверка готовности пода контроллера
kubectl get pods -n portager-system -l app.kubernetes.io/name=portager

После старта контроллера создаем декларативный манифест синхронизации базовых системных образов:

apiVersion: portager.portager.io/v1alpha1
kind: ImageSync
metadata:
  name: corporate-base-images
  namespace: default
spec:
  schedule: "@every 6h"
  source:
    registry: docker.io/library
  destination:
    registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
    auth:
      method: ecr
    repositoryPrefix: mirror
    createDestinationRepos: true
  images:
    - name: alpine
      tags: ["3.21", "latest"]
    - name: nginx
      tags: ["latest"]
      semver: "~1.27.0"

Применяем ресурс командой kubectl apply -f base-images.yaml. В секции событий describe ты сразу увидишь фазы выполнения: RepoEnsured (целевой репозиторий проверен в ECR), ImageSynced (слои успешно скопированы) и SyncComplete (итоговый отчет о переносе).

Безопасность цепочки поставок и ограничения в продакшене

Главное преимущество запуска прямо в Kubernetes — интеграция с корпоративными политиками безопасности. Для авторизации в приватных реестрах можно использовать стандартные секреты kubernetes.io/dockerconfigjson, а в облаке AWS — привязывать права через IAM Roles for Service Accounts (IRSA) без использования статических паролей.

Кроме того, Portager поддерживает проверку криптографических подписей Cosign перед зеркалированием. Это отлично дополняет практики, о которых мы говорили в материале по контролю целостности образов в Kubernetes через Cosign и Kyverno: образ не просто копируется, а гарантированно верифицируется до попадания в закрытый контур.

Но помни об ограничениях: проект находится в версии v0.5.0 с альфа-версией API v1alpha1. При первой синхронизации десятков тяжелых образов потребуется достаточная пропускная способность сети. А если ты тянешь образы с Docker Hub анонимно, частый cron-опрос быстро упрется в лимиты запросов (rate limits), поэтому авторизационный секрет обязателен.

Для небольших и средних команд Portager закрывает многолетнюю дыру в инфраструктурном тулинге, избавляя от самописных батников и делая доставку образов предсказуемой.