CI/CD и GitOps-доставка приложения в Nova
Данная статья описывает демонстрационный сценарий сборки и доставки приложения в кластер Nova. Nova предоставляет платформенные контроллеры, маршрутизацию, выпуск сертификатов и встроенные механизмы GitOps-доставки на базе FluxCD.
GitLab и Harbor в этом сценарии используются как внешние вспомогательные системы: GitLab хранит исходный код и запускает CI-пайплайн, а Harbor выступает контейнерным registry для собранных образов. Они не являются частью платформы Nova, но нужны для демонстрации полного цикла CI/CD.
1. Ожидаемый результат
В результате настройки будет реализован следующий процесс:
-
Разработчик публикует исходный код приложения в GitLab.
-
GitLab Runner, запущенный в кластере Nova, получает задание из GitLab CI.
-
CI-пайплайн собирает контейнерные образы приложения и публикует их в Harbor.
-
FluxCD, встроенный в Nova, отслеживает GitOps-репозиторий и применяет Kubernetes-манифесты в кластер.
-
FluxCD Image Automation отслеживает новые теги образов в Harbor, обновляет GitOps-репозиторий и инициирует обновление приложения в кластере.
2. Архитектура решения
В демонстрации участвуют четыре логических компонента:
| Компонент | Роль в сценарии | Статус относительно Nova |
|---|---|---|
GitLab |
Хранение исходного кода, GitOps-репозитория и запуск CI/CD-пайплайнов |
Внешний сервис |
GitLab Runner |
Исполнитель CI-задач, запускающий job-Pod в Nova |
Внешний CI-агент, установленный в кластер |
Harbor |
Контейнерный registry для хранения собранных образов |
Внешний сервис |
FluxCD |
GitOps-доставка, синхронизация манифестов и автоматизация обновления образов |
Встроенный компонент платформы Nova |
Nova не заменяет GitLab или Harbor, но предоставляет среду выполнения и встроенный GitOps-механизм, через который приложение доставляется в кластер.
3. Теория
3.1. Continuous Integration
Continuous Integration (CI) — практика автоматической проверки и сборки кода после его изменения. В этом сценарии CI отвечает за сборку контейнерных образов приложения. GitLab запускает CI-пайплайн, а GitLab Runner выполняет задания внутри кластера Nova.
Для сборки образов используется подход, при котором каждая job запускается в отдельном Pod. Runner не требует отдельного выделенного сервера и использует ресурсы кластера Nova.
3.2. Continuous Delivery и GitOps
Continuous Delivery (CD) отвечает за доставку приложения в целевую среду. В платформенных Kubernetes-сценариях часто используется GitOps-подход: желаемое состояние приложения хранится в Git-репозитории, а контроллер в кластере регулярно сверяет фактическое состояние с описанным в Git.
В Nova роль GitOps-контроллера выполняет FluxCD. Он читает ресурс GitRepository, применяет ресурс Kustomization и поддерживает состояние приложения в соответствии с манифестами.
3.3. Почему GitOps удобен для платформы
GitOps делает доставку приложения управляемой и воспроизводимой:
-
история изменений хранится в Git;
-
любое изменение можно проверить через commit diff;
-
откат выполняется возвратом к предыдущей версии манифестов;
-
кластер сам подтягивает изменения из репозитория;
-
доступ к кластеру можно ограничить, оставив разработчикам работу через Git.
3.4. Роль Harbor в демонстрации
Harbor используется как registry для хранения контейнерных образов. CI-пайплайн публикует туда новые версии сервисов, а FluxCD Image Reflector сканирует Harbor и определяет, какие теги доступны для обновления.
В продуктивной среде вместо Harbor может использоваться другой совместимый registry. Для Nova важно, чтобы узлы кластера могли доверять TLS-сертификату registry и скачивать из него образы.
4. Демонстрационное приложение ORIONSHOP
В сценарии используется демонстрационное приложение ORIONSHOP. Приложение состоит из 12 микросервисов, написанных на разных языках программирования, и подходит для демонстрации платформенной доставки микросервисного приложения в Nova.
Исходный код демонстрационного приложения можно скачать или клонировать из публичного репозитория:
git clone https://gitlab-nova.orionsoft.ru/nova-public/nova-demo-app.git
Этот репозиторий можно использовать двумя способами:
-
как исходный код приложения для CI-сценария: код копируется в пользовательский проект GitLab, после чего CI-пайплайн собирает образы и публикует их в Harbor;
-
как GitOps-репозиторий для быстрой демонстрации CD: встроенный в Nova FluxCD читает манифесты напрямую из репозитория и применяет их в кластер.
Для полного сценария CI/CD с ImageUpdateAutomation рекомендуется использовать собственную копию репозитория в GitLab, потому что FluxCD должен иметь право записывать изменения тегов обратно в GitOps-репозиторий.
Если вы используете собственный Git-репозиторий и теги для полного сценария, в файле kustomize/kustomization.yaml раскомментируйте строки:
- components/container-images-tag
- components/container-images-registry
Если ваш registry является приватным и требует авторизации для скачивания образов, дополнительно раскомментируйте строку:
- components/image-pull-secret
5. Предварительные требования
Перед началом настройки должны быть доступны:
-
кластер Nova
-
доступ к
kubectlиhelm -
внешний GitLab
-
внешний Harbor
-
исходный код демонстрационного приложения
-
сетевой доступ к сервисам, которые используются в сценарии: GitLab, Harbor, Nova, registry с базовыми образами и репозиториям с Helm-чартами, если они не перенесены во внутренний контур
В примерах ниже используются плейсхолдеры:
| Группа | Плейсхолдер | Что заменить |
|---|---|---|
Общие |
|
логин пользователя или namespace в GitLab, например |
Общие |
|
путь до рабочей директории |
GitLab |
|
URL GitLab со схемой, например |
GitLab |
|
hostname GitLab без схемы, например |
GitLab |
|
имя проекта приложения в GitLab, например |
GitLab |
|
registration token GitLab Runner |
GitLab |
|
имя GitLab access token |
GitLab |
|
GitLab access token для FluxCD automation |
Harbor |
|
hostname Harbor без схемы, например |
Harbor |
|
проект Harbor для образов приложения, например |
Harbor |
|
имя robot account в Harbor для публикации образов |
Harbor |
|
secret robot account в Harbor для публикации образов |
Harbor |
|
учётная запись Harbor для скачивания образов |
Harbor |
|
пароль или token учётной записи Harbor для скачивания образов |
Если для демонстрации используется одинаковое имя проекта в GitLab и проекта в Harbor, для <gitlab_project_name> и <harbor_project> можно указать одно значение, например nova-demo-app.
6. Принцип выдачи прав в демонстрации
В примерах ниже для упрощения демонстрации могут использоваться расширенные права, роль Owner, полный доступ robot account, бессрочные токены или учётная запись администратора. Это сделано только для демонстрационного стенда, чтобы показать полный CI/CD-цикл без дополнительных ограничений.
В реальной эксплуатации необходимо выдавать только минимально необходимые права для конкретной задачи: отдельно на чтение и запись в Git-репозиторий, публикацию или скачивание образов из registry, создание объектов в namespace и выполнение GitOps-операций. Выбор конкретных ролей, сроков действия токенов, границ доступа и соответствие требованиям безопасности остаются ответственностью администратора кластера.
7. Настройка Continuous Integration
7.1. Создание репозитория приложения в GitLab
Создайте новый проект в GitLab. В примерах ниже его имя обозначено как <gitlab_project_name>, например nova-demo-app.
После создания проекта инициализируйте локальный репозиторий и отправьте исходный код в GitLab:
cd <gitlab_project_name>
git init --initial-branch=main
git remote add origin <gitlab_url>/<user_login>/<gitlab_project_name>.git
git add .
git commit -m "Initial commit"
git push --set-upstream origin main
После отправки кода проект должен появиться в GitLab.
7.2. Создание GitLab Runner для проекта
GitLab Runner — компонент, который забирает задания из GitLab CI и выполняет их. В этом сценарии runner будет установлен в Nova и будет запускать CI job в виде Pod.
В GitLab откройте проект и перейдите в раздел Settings → CI/CD → Runners → New project runner.
В поле Tag укажите тег runner, например:
nova-demo-app-runner
В качестве платформы выберите Linux. GitLab покажет registration token. Скопируйте его сразу: обычно он отображается только один раз.
В дальнейшем этот токен будет использован в gitlab-runner-values.yaml:
runnerRegistrationToken: <runner_registration_token>
7.3. Создание namespace для GitLab Runner
Создайте namespace gitlab-runner и добавьте метку, чтобы Nova могла передать в него доверенный CA bundle:
kubectl create namespace gitlab-runner
kubectl label namespace gitlab-runner nova-platform.io/trusted-ca-bundle=enabled
Если GitLab использует внутренний или самоподписанный сертификат, добавьте сертификат GitLab в namespace runner как ConfigMap:
kubectl -n gitlab-runner create configmap gitlab-ca \
--from-file=<workdir>/<gitlab_host>.crt
kubectl -n gitlab-runner get configmap gitlab-ca -o yaml
Это нужно, чтобы job-Pod runner доверяли TLS-сертификату GitLab. Иначе подключение к GitLab может завершаться ошибками проверки сертификата.
7.4. Подготовка values-файла для GitLab Runner
Создайте файл gitlab-runner-values.yaml:
touch <workdir>/gitlab-runner-values.yaml
Добавьте в него настройки runner:
runnerRegistrationToken: <runner_registration_token>
gitlabUrl: "<gitlab_url>"
concurrent: 3
image:
registry: hub-nova.orionsoft.ru
image: library/gitlab-runner
tag: alpine-v18.2.1
runners:
config: |
[[runners]]
[runners.kubernetes]
helper_image = "hub-nova.orionsoft.ru/library/gitlab-runner-helper:x86_64-v18.2.1"
[[runners.kubernetes.volumes.config_map]]
name = "trusted-ca-bundle"
mount_path = "/certs"
[runners.kubernetes.volumes.config_map.items]
"ca-certificates.pem" = "./ca.crt"
volumes:
- name: gitlab-ca
configMap:
name: gitlab-ca
- name: trusted-ca
configMap:
name: trusted-ca-bundle
volumeMounts:
- name: gitlab-ca
mountPath: "/etc/ssl/certs/<gitlab_host>.crt"
subPath: "<gitlab_host>.crt"
- name: trusted-ca
mountPath: "/certs/ca.crt"
subPath: "ca-certificates.pem"
Параметр concurrent ограничивает количество одновременно выполняемых job.
7.5. Установка GitLab Runner в Nova
Если стенд имеет доступ к публичному Helm-репозиторию, добавьте Helm-репозиторий GitLab и установите runner:
helm repo add gitlab https://charts.gitlab.io
helm upgrade --install \
--namespace gitlab-runner \
gitlab-runner \
-f gitlab-runner-values.yaml \
gitlab/gitlab-runner
В закрытом контуре используйте внутренний Helm-репозиторий или локальный архив чарта, как описано в разделе Доступ в интернет и работа в закрытом контуре.
Проверьте, что Pod runner запущен:
kubectl -n gitlab-runner get pods
NAME READY STATUS RESTARTS AGE
gitlab-runner-77dc5bd648-m9djl 1/1 Running 0 111s
7.6. Предоставление прав GitLab Runner
Чтобы runner мог создавать job-Pod и работать с объектами в namespace gitlab-runner, настройте RBAC:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gitlab-runner-role
namespace: gitlab-runner
rules:
- apiGroups:
- ''
resources:
- '*'
verbs:
- '*'
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: gitlab-runner-rb
namespace: gitlab-runner
subjects:
- kind: ServiceAccount
name: default
namespace: gitlab-runner
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: gitlab-runner-role
Примените манифест:
kubectl apply -f gitlab-runner-rbac.yaml
|
В демонстрации runner получает расширенные права внутри namespace |
После настройки runner должен отображаться в GitLab как Online.
8. Настройка Harbor
8.1. Создание проекта в Harbor
Harbor будет использоваться как registry, куда CI-пайплайн отправит собранные контейнерные образы.
Откройте Harbor:
https://<harbor_host>/
Авторизуйтесь и создайте новый проект. В качестве имени проекта используйте значение <harbor_project> (в примерах — nova-demo-app) или измените логику .gitlab-ci.yml под свой стенд.
Для демонстрационного стенда можно указать Project quota limits = -1.
8.2. Создание robot account
В демонстрации для публикации образов из CI создаётся robot account в проекте Harbor:
Project -> Robot Accounts -> New Robot Account
Параметры, используемые в демонстрации:
-
имя:
<harbor_robot_user>; -
expiration time:
never; -
права: полный доступ к проекту.
|
Для реальной эксплуатации нужно выдать этой учётной записи только минимально необходимые права, например только публикацию образов в конкретный проект Harbor. Срок действия robot account и набор разрешений администратор определяет самостоятельно. |
Сохраните Name и Secret. Они понадобятся для переменных GitLab CI.
9. Настройка GitLab CI для публикации образов
9.1. Добавление переменных CI/CD
В проекте GitLab откройте Settings → CI/CD → Variables → Add variable.
Добавьте переменные:
| Key | Value |
|---|---|
|
|
|
|
|
|
|
|
|
В демонстрации эти переменные используются без флага В реальной эксплуатации параметры |
9.2. Запуск сборки по тегу
Создайте Git-тег, например v1.0.0:
Code -> Tags -> New tag
Если .gitlab-ci.yml публикует Docker-тег без префикса v, в Harbor появится тег 1.0.0. В примерах FluxCD ниже используется формат тегов без префикса v.
После создания тега GitLab запустит CI-пайплайн.
9.3. Проверка pipeline
Откройте раздел Build → Pipelines.
Если runner настроен корректно, pipeline перейдёт в состояние Running.
Можно открыть каждую job и посмотреть лог выполнения.
Параллельность выполнения job зависит от параметра concurrent в values-файле runner. Например, при concurrent: 3 одновременно могут выполняться три задания.
9.4. Проверка job-Pod в Nova
Во время выполнения pipeline в namespace gitlab-runner появятся job-Pod runner:
kubectl get pods -n gitlab-runner | egrep runner
runner-t3lfvbsx-project-7-concurrent-0-24k5uhic 0/2 Init:0/1 0 7m24s
runner-t3lfvbsx-project-7-concurrent-0-o72ypxme 2/2 Running 0 61s
runner-t3lfvbsx-project-7-concurrent-1-hwdu4vly 0/2 Init:0/1 0 6m54s
runner-t3lfvbsx-project-7-concurrent-1-yknaqnwp 2/2 Running 0 60s
10. Настройка Continuous Delivery через FluxCD
10.1. Общая логика CD
В Nova FluxCD уже входит в платформу. Поэтому в этом разделе не устанавливается FluxCD как отдельный продукт, а создаются ресурсы, которыми встроенный FluxCD будет управлять:
-
GitRepository— источник манифестов в Git; -
Kustomization— описание того, что и как применять в кластер; -
ImageRepository— источник тегов образов в registry; -
ImagePolicy— правило выбора подходящего тега; -
ImageUpdateAutomation— автоматическое изменение тегов в GitOps-репозитории.
10.2. Подготовка Kustomize-компонентов
В GitLab-проекте обновите файлы:
kustomize/components/container-images-registry/kustomization.yaml
kustomize/components/container-images-tag/kustomization.yaml
Замените значения MY_CONTAINER_REGISTRY и CONTAINER_IMAGES_TAG на адрес Harbor и тег образа, который был собран в pipeline.
10.3. Создание namespace приложения
Создайте namespace для приложения:
kubectl create namespace orion-shop
10.4. RBAC для kustomize-controller
FluxCD применяет манифесты в namespace приложения от имени service account. Создайте service account и выдайте ему права на управление нужными объектами:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kustomize-controller-sa
namespace: orion-shop
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kustomize-controller-role
namespace: orion-shop
rules:
- apiGroups: ["apps", ""]
resources: ["deployments", "services", "configmaps", "secrets", "serviceaccounts", "replicasets", "pods", "namespaces"]
verbs: ["get", "list", "create", "update", "delete", "patch"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings"]
verbs: ["get", "list", "create", "update", "delete", "patch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "create", "update", "delete", "patch"]
- apiGroups: ["kustomize.toolkit.fluxcd.io"]
resources: ["kustomizations"]
verbs: ["get", "list", "watch"]
- apiGroups: ["source.toolkit.fluxcd.io"]
resources: ["gitrepositories"]
verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: ["metrics.k8s.io"]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kustomize-controller-binding
namespace: orion-shop
subjects:
- kind: ServiceAccount
name: kustomize-controller-sa
namespace: orion-shop
roleRef:
kind: Role
name: kustomize-controller-role
apiGroup: rbac.authorization.k8s.io
Примените манифест:
kubectl apply -f rbac.yaml
|
В демонстрации сервисной учётной записи выдаётся набор прав, достаточный для применения всех объектов приложения. В реальной эксплуатации права service account должны быть ограничены минимально необходимыми ресурсами и действиями. |
10.5. Секрет для доступа FluxCD к GitLab
FluxCD должен иметь возможность читать GitOps-репозиторий. Если используется ImageUpdateAutomation, ему также понадобится право записывать изменения обратно в репозиторий.
В GitLab создайте access token:
Settings -> Access tokens -> Add new token
Параметры, используемые в демонстрации:
-
role:
Owner; -
scopes:
read_repository,write_repository.
|
В реальной эксплуатации токену нужно выдавать только минимально необходимые права: чтение репозитория для |
Получите CA-сертификат GitLab, если он нужен для проверки TLS:
openssl s_client -showcerts \
-connect <gitlab_host>:443 \
-servername <gitlab_host> < /dev/null 2>/dev/null \
| openssl x509 -outform PEM \
> <workdir>/<gitlab_host>.crt
Создайте Kubernetes Secret в namespace orion-shop. В примере используется stringData: значения указываются в открытом виде в манифесте, а Kubernetes сохранит их в Secret в Base64.
apiVersion: v1
kind: Secret
metadata:
name: gitrepo-secret
namespace: orion-shop
type: Opaque
stringData:
username: <gitlab_token_name>
password: <gitlab_access_token>
ca.crt: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
В поле ca.crt вставьте содержимое файла <workdir>/<gitlab_host>.crt. Если GitLab использует сертификат, которому FluxCD уже доверяет, поле ca.crt можно не добавлять.
Примените secret:
kubectl apply -f flux-gitops-repo-secret.yaml
10.6. Создание GitRepository
Создайте ресурс GitRepository, чтобы FluxCD мог получать манифесты из GitLab:
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: gitops-repo
namespace: orion-shop
spec:
interval: 5m0s
url: <gitlab_url>/<user_login>/<gitlab_project_name>.git
ref:
branch: main
secretRef:
name: gitrepo-secret
Примените манифест:
kubectl apply -f gitops-repo.yaml
Проверьте состояние репозитория:
kubectl -n orion-shop get gitrepo
NAME URL AGE READY STATUS
gitops-repo https://gitlab.mycompany.local/<user_login>/<gitlab_project_name>.git 8s True stored artifact for revision 'main@sha1:...'
Для диагностики можно использовать:
kubectl -n orion-shop describe gitrepo gitops-repo
11. Подключение приложения к Harbor
11.1. Создание imagePullSecret
Чтобы Pod приложения могли скачивать приватные образы из Harbor, создайте docker-registry secret:
kubectl create secret docker-registry regcred -n orion-shop \
--docker-server=<harbor_host> \
--docker-username=<harbor_read_user> \
--docker-password=<harbor_read_password> \
--docker-email=<user_login>@mycompany.local
|
В демонстрации для |
Для скачивания образов из Harbor worker-узлы должны доверять TLS-сертификату registry. Даже если сертификат Harbor доверен внутри Kubernetes-кластера, containerd выполняет pull образов на уровне ОС worker-узла и использует системное хранилище доверенных CA. Поэтому сертификат необходимо добавить в доверенные сертификаты каждого worker-узла и обновить системное хранилище сертификатов.
Пример:
cp harbor-ca.pem /etc/pki/ca-trust/source/anchors/
update-ca-trust enable
update-ca-trust extract
systemctl restart containerd-nova.service
12. Деплой приложения через FluxCD
12.1. Создание Kustomization
Kustomization указывает FluxCD, какие манифесты применять и как подставлять переменные окружения для конкретного стенда.
Убедитесь, что spec.sourceRef.name совпадает с именем ресурса GitRepository.
Укажите imagepullsecretname, если используется приватный registry.
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: orion-shop
namespace: orion-shop
spec:
serviceAccountName: kustomize-controller-sa
commonMetadata:
labels:
app.kubernetes.io/managed-by: Nova
interval: 10m
retryInterval: 30s
timeout: 5m
prune: true
sourceRef:
kind: GitRepository
name: gitops-repo
path: ./kustomize
postBuild:
substitute:
frontendURL: "frontend.apps.<user_login>.mycompany.local"
loadgeneratorURL: "loadgenerator.apps.<user_login>.mycompany.local"
certManagerClusterIssuer: "nova-dynamic-internal-cluster-issuer"
imagepullsecretname: regcred
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: loadgenerator
namespace: orion-shop
Примените манифест:
kubectl apply -f flux-deploy.yaml
Параметр prune: true означает, что FluxCD будет удалять из кластера объекты, которые больше не описаны в GitOps-репозитории. Это помогает поддерживать соответствие фактического состояния кластера желаемому состоянию в Git.
12.2. Проверка запуска приложения
Дождитесь запуска Pod в namespace orion-shop:
kubectl get pods -n orion-shop
NAME READY STATUS RESTARTS AGE
adservice-76bdd69666-ckc5j 1/1 Running 0 2m58s
cartservice-66d497c6b7-dp5jr 1/1 Running 0 2m59s
checkoutservice-666c784bd6-4jd22 1/1 Running 0 3m1s
currencyservice-5d5d496984-4jmd7 1/1 Running 0 2m59s
emailservice-667457d9d6-75jcq 1/1 Running 0 3m2s
frontend-6b8d69b9fb-wjqdg 1/1 Running 0 3m1s
loadgenerator-665b5cd444-gwqdq 1/1 Running 0 3m
paymentservice-68596d6dd6-bf6bv 1/1 Running 0 3m
productcatalogservice-557d474574-888kr 1/1 Running 0 3m
recommendationservice-69c56b74d4-7z8r5 1/1 Running 0 3m1s
redis-cart-5f59546cdd-5jnqf 1/1 Running 0 2m58s
shippingservice-6ccc89f8fd-v686r 1/1 Running 0 2m58s
Проверьте объект Kustomization:
kubectl get ks orion-shop -n orion-shop
Получите адрес ingress:
kubectl get ing frontend-ingress -n orion-shop | awk '{print $3}'
Откройте приложение в браузере, например:
https://frontend.apps.<user_login>.mycompany.local/
13. Автоматическое обновление образов через FluxCD
13.1. Назначение ImageRepository и ImagePolicy
FluxCD может не только применять манифесты из Git, но и отслеживать новые версии контейнерных образов.
Для этого используются два ресурса:
-
ImageRepository— сканирует registry и получает список доступных тегов; -
ImagePolicy— выбирает подходящий тег по заданному правилу, например по SemVer-диапазону.
13.2. Создание ImageRepository и ImagePolicy
Пример для сервиса adservice:
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: adservice
namespace: orion-shop
spec:
image: <harbor_host>/<harbor_project>/adservice
interval: 5m
secretRef:
name: regcred
certSecretRef:
name: default-ingress-certificate
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: adservice
namespace: orion-shop
spec:
imageRepositoryRef:
name: adservice
policy:
semver:
range: 1.x.x
Примените манифест:
kubectl apply -f flux-image-policy.yaml
Проверьте, что FluxCD нашёл теги в Harbor:
kubectl -n orion-shop describe imagerepository adservice
Status:
Canonical Image Name: <harbor_host>/<harbor_project>/adservice
Conditions:
Message: successful scan: found 1 tags
Reason: Succeeded
Status: True
Type: Ready
Last Scan Result:
Latest Tags:
1.0.0
Tag Count: 1
13.3. Создание ImageUpdateAutomation
ImageUpdateAutomation изменяет GitOps-репозиторий: FluxCD находит новый тег, обновляет файл с манифестами и делает commit обратно в Git.
---
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: image-update-app
namespace: orion-shop
spec:
interval: 2m
sourceRef:
kind: GitRepository
name: gitops-repo
git:
checkout:
ref:
branch: main
commit:
author:
email: fluxcdbot@users.noreply.github.com
name: fluxcdbot
messageTemplate: '{{range .Updated.Images}}{{println .}}{{end}}'
push:
branch: main
update:
path: ./
strategy: Setters
Примените манифест:
kubectl apply -f flux-image-update-automation.yaml
14. Подготовка GitOps-репозитория к автоматическому обновлению
Чтобы FluxCD знал, какой тег можно обновлять, добавьте setter-комментарий рядом с тегом образа в файле kustomize/components/container-images-tag/kustomization.yaml.
Пример:
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
images:
- name: <harbor_host>/<harbor_project>/adservice
newTag: 1.0.0 # {"$imagepolicy": "orion-shop:adservice:tag"}
- name: hub-nova.orionsoft.ru/orion-shop/cartservice
Этот комментарий связывает поле newTag с ImagePolicy orion-shop:adservice. Когда FluxCD найдёт новый подходящий тег, он изменит это поле и отправит commit в GitLab.
15. Проверка автоматического обновления
15.1. Сборка новой версии образа
Внесите изменение в код сервиса adservice и создайте новый Git-тег, например v1.0.1.
После успешного завершения CI-пайплайна в Harbor должны появиться новые образы. Если .gitlab-ci.yml удаляет префикс v, новый Docker-тег будет выглядеть как 1.0.1.
15.2. Проверка обнаружения нового тега
Проверьте ImageRepository:
kubectl -n orion-shop describe imagerepository adservice
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Succeeded 21m image-reflector-controller successful scan: found 1 tags
Normal Succeeded 6m27s (x3 over 16m) image-reflector-controller no new tags found, next scan in 5m0s
Normal Succeeded 86s image-reflector-controller successful scan: found 2 tags
15.3. Проверка выбранного тега
Проверьте ImagePolicy:
kubectl describe imagepolicy adservice -n orion-shop
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning DependencyNotReady 23m (x2 over 23m) image-reflector-controller referenced ImageRepository has not been scanned yet
Normal Succeeded 3m15s (x12 over 23m) image-reflector-controller Latest image tag for '<harbor_host>/<harbor_project>/adservice' resolved to 1.0.0
Normal Succeeded 3m14s (x2 over 3m14s) image-reflector-controller Latest image tag for '<harbor_host>/<harbor_project>/adservice' updated from 1.0.0 to 1.0.1
15.4. Проверка обновления Pod
Проверьте, что приложение запускается из нового образа:
kubectl -n orion-shop describe pod <adservice_pod_name>
Normal Pulling 4m46s kubelet Pulling image "<harbor_host>/<harbor_project>/adservice:1.0.1"
15.5. Проверка commit в GitLab
В GitLab откройте GitOps-репозиторий и проверьте, что FluxCD изменил тег образа в файле Kustomize.
Это подтверждает полный GitOps-цикл:
-
CI собрал новый образ.
-
Образ был опубликован в Harbor.
-
FluxCD обнаружил новый тег.
-
FluxCD обновил GitOps-репозиторий.
-
Nova применила обновлённое состояние приложения.
16. Диагностика типовых проблем
16.1. Runner не появляется в GitLab как Online
Проверьте:
kubectl -n gitlab-runner get pods
kubectl -n gitlab-runner logs deploy/gitlab-runner
Частые причины:
-
неверный
runnerRegistrationToken; -
runner не доверяет сертификату GitLab;
-
GitLab недоступен из кластера;
-
неверно указан
gitlabUrl.
16.2. Pipeline зависает в Pending
Проверьте, что runner имеет нужный tag и что .gitlab-ci.yml использует этот tag. Также убедитесь, что runner не отключён в настройках проекта.
16.3. Образы не публикуются в Harbor
Проверьте переменные GitLab CI:
-
CI_REGISTRY; -
REGISTRY_RW_USER; -
REGISTRY_RW_PASSWORD; -
HARBOR_REPO.
Также проверьте права robot account в Harbor.
16.4. Pod не может скачать образ из Harbor
Проверьте:
kubectl -n orion-shop describe pod <pod_name>
Типовые причины:
-
отсутствует или неверно указан
imagePullSecret; -
worker-узел не доверяет сертификату Harbor;
-
образ или тег отсутствует в Harbor;
-
у robot account нет прав на чтение проекта Harbor.
16.5. GitRepository не переходит в Ready
Проверьте:
kubectl -n orion-shop describe gitrepo gitops-repo
Типовые причины:
-
неверный URL репозитория;
-
неверный secret с access token;
-
FluxCD не доверяет сертификату GitLab;
-
токен не имеет прав на чтение репозитория.
16.6. ImageUpdateAutomation не делает commit
Проверьте:
kubectl -n orion-shop describe imageupdateautomation image-update-app
kubectl -n orion-shop describe imagepolicy adservice
kubectl -n orion-shop describe imagerepository adservice
Частые причины:
-
в GitOps-файле не добавлен setter-комментарий
{"$imagepolicy": …}; -
access token не имеет права
write_repository; -
новая версия образа не подходит под SemVer policy;
-
ImageRepositoryне может прочитать теги из Harbor.
17. Результат
После выполнения настройки получается демонстрационный CI/CD-контур для Nova:
-
GitLab хранит исходный код и запускает CI pipeline;
-
GitLab Runner выполняет сборку внутри Nova;
-
Harbor хранит контейнерные образы;
-
FluxCD, встроенный в Nova, доставляет приложение в кластер по GitOps-модели;
-
Image Automation обновляет версии образов через commit в GitOps-репозиторий.
Такой сценарий демонстрирует GitOps: разработчик работает с Git и pipeline, а Nova обеспечивает безопасное выполнение рабочей нагрузки, применение манифестов, маршрутизацию, сертификаты и поддержание желаемого состояния приложения.
18. Доступ в интернет и работа в закрытом контуре
Демонстрационный сценарий может выполняться как в среде с доступом к внешним ресурсам, так и в закрытом контуре. Под закрытым контуром понимается среда, где кластер Nova, GitLab, Harbor, рабочие станции администраторов и CI/CD-процессы не имеют прямого выхода в интернет, а все необходимые зависимости заранее размещаются во внутренних репозиториях и registry.
GitLab и Harbor в этой статье называются внешними сервисами относительно платформы Nova, но это не означает, что они обязательно должны находиться в интернете. В закрытом контуре они обычно размещаются внутри периметра организации и доступны только по внутренним DNS-именам и маршрутам.
18.1. Что подготовить для закрытого контура
Для реализации этого же сценария без прямого доступа в интернет необходимо заранее перенести во внутренний контур все зависимости, которые используются при установке, сборке и запуске приложения.
В этом разделе дополнительно используются плейсхолдеры:
| Плейсхолдер | Что заменить |
|---|---|
|
URL внутреннего Helm-репозитория |
|
версия Helm-чарта GitLab Runner |
Минимально нужно подготовить:
| Что подготовить | Где должно быть размещено | Зачем нужно |
|---|---|---|
GitLab |
внутри закрытого контура |
хранение исходного кода, GitOps-репозитория и запуск CI pipeline |
Harbor или другой OCI-compatible registry |
внутри закрытого контура |
хранение базовых образов, CI-образов и образов приложения |
Helm-чарт GitLab Runner |
внутренний Helm-репозиторий или локальный |
установка runner без обращения к |
образы GitLab Runner и GitLab Runner Helper |
внутренний registry |
запуск runner и служебных Pod в Kubernetes executor |
образы Kaniko/build executor из |
внутренний registry |
сборка контейнерных образов без Docker daemon |
базовые образы приложения |
внутренний registry |
сборка сервисов приложения без скачивания из публичных registry |
зависимости языков и пакетных менеджеров |
внутренние зеркала Maven, npm, PyPI, Go proxy, apt/yum/apk и т. п. |
установка библиотек во время CI-сборки |
исходный код демонстрационного приложения |
внутренний GitLab |
воспроизводимость сценария внутри периметра |
TLS-сертификаты и CA bundle |
доверенные хранилища Nova, runner, FluxCD и worker-узлов |
корректная проверка сертификатов GitLab и Harbor |
DNS-записи |
внутренний DNS |
разрешение имён GitLab, Harbor, ingress-адресов и registry |
18.2. Перенос образов во внутренний registry
Все образы, которые указаны в Helm values, .gitlab-ci.yml, Dockerfile и Kubernetes-манифестах, должны ссылаться на внутренний registry. Например, вместо публичного или внешнего адреса используется адрес Harbor внутри закрытого контура:
image:
registry: <harbor_host>
image: library/gitlab-runner
tag: alpine-v18.2.1
То же правило применяется к helper image:
helper_image = "<harbor_host>/library/gitlab-runner-helper:x86_64-v18.2.1"
Если приложение собирается из Dockerfile, инструкции FROM также должны указывать на внутренний registry:
FROM <harbor_host>/library/alpine:3.20
Перед запуском практики проверьте, что GitLab Runner, job-Pod, FluxCD и worker-узлы Nova могут получить доступ к этим образам.
18.3. Перенос Helm chart в закрытый контур
Если нет доступа к charts.gitlab.io, чарт GitLab Runner необходимо скачать заранее и перенести во внутренний контур. После этого возможны два варианта установки.
Первый вариант — установить чарт из локального архива:
helm upgrade --install \
--namespace gitlab-runner \
gitlab-runner \
-f gitlab-runner-values.yaml \
./gitlab-runner-<chart_version>.tgz
Второй вариант — разместить чарт во внутреннем Helm-репозитории:
helm repo add internal-helm <internal_helm_repo>
helm upgrade --install \
--namespace gitlab-runner \
gitlab-runner \
-f gitlab-runner-values.yaml \
internal-helm/gitlab-runner
18.4. Зависимости сборки приложения
Даже если все контейнерные образы перенесены во внутренний Harbor, pipeline может обращаться к внешним источникам во время сборки. Это зависит от стека приложения и содержимого Dockerfile или CI job.
Перед запуском в закрытом контуре проверьте, используются ли в сборке:
-
apt,yum,dnf,apkили другие системные пакетные менеджеры; -
npm,yarn,pnpm; -
pip,poetry; -
maven,gradle; -
go mod downloadили внешний Go proxy; -
скачивание бинарных файлов через
curlилиwget; -
обращения к публичным container registry.
Для каждого такого источника настройте внутреннее зеркало или заранее подготовленный артефакт. Иначе pipeline может успешно стартовать, но завершиться ошибкой на этапе скачивания зависимостей.