Всем привет! С вами снова Виктор Ашакин, DevOps-инженер компании «Флант», и мы продолжаем готовить экосистему управления кодом и его развёртывания в Kubernetes на основе Gitea. В первой части статьи мы настроили Gitea и использовали его как Identity Provider (IdP) в Deckhouse Kubernetes Platform, а также разобрались, как настроить DKP для работы с внешним IdP и разграничить права доступа к ресурсам кластера в платформе.
В этой части инструкции поговорим о Gitea Actions. Настроим инфраструктуру и Actions CI/CD — всё необходимое перед созданием тестового репозитория и написанием Gitea Actions-пайплайнов.
Подготовка инфраструктуры CI/CD
Перед тем как мы приступим к делу, позвольте минутку теории для начинающих. CI/CD-пайплайн (Continuous Integration & Continuous Delivery) — это сценарий, в котором описаны автоматизация процесса сборки и доставки приложения до среды его работы. В этапы пайплайна могут входить различные задания: тесты, линт, сканирования на уязвимости, очистка сборочной среды и так далее. Как его построить, я расскажу далее.
Подготовительные работы
Обычно задачи пайплайнов выполняются отдельной программой — агентом, раннером, билдером, в зависимости от терминологии конкретной CI/CD-системы. Раннер подключается к системе управления Git-репозиториев, получает от неё задания, выполняет их и предоставляет отчёт о выполнении.
В Gitea Actions раннер — это утилита act_runner. Она регистрируется
на сервере Gitea, а затем ожидает и выполняет задания, описанные в пайплайне Gitea Actions. К серверу Gitea может быть подключено сразу несколько раннеров. Их назначение можно гибко разделять по типам заданий, командам пользователей, отдельным проектам или просто для распараллеливания заданий.
Мы будем собирать и упаковывать код приложения в Docker-контейнеры, а после выкатывать собранное приложение в Deckhouse Kubernetes Cluster. Для этого понадобится раннер-сервер с установленными средствами сборки Docker-контейнеров и их доставки до DKP.
Раннер должен отвечать следующим минимальным требованиям:
не менее 2 ядер CPU;
не менее 4 ГБ RAM;
не менее 50 ГБ дискового пространства (лучше больше, так как Docker-образы порой занимают много места);
сконфигурированный доступ по SSH.
Act_runner написан на Go и может работать на большинстве ОС: Linux, Windows, macOS. Так что выбор исходит из потребностей кода приложения и предпочтений инженера. Я предпочитаю Ubuntu Server 22.04.
Для выполнения задач пайплайнов нам понадобятся Git, Docker Engine, kubectl и werf.
Установим Docker и Git:
# Подключение репозитория
apt update
apt install apt-transport-https ca-certificates curl git
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
# Установка docker engine
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Далее установим kubectl:
apt install apt-transport-https ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -LO https://dl.k8s.io/release/`curl -LS https://dl.k8s.io/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
kubectl version --client
Наконец, устанавливаем werf:
sudo su - act_runner
curl -sSL https://werf.io/install.sh | bash -s -- --ci
Настройка act_runner
Создаём пользователя для act_runner и предоставляем ему права на работу с Docker:
adduser --system --shell /bin/bash --group --disabled-password --home /home/act_runner act_runner
gpasswd -a act_runner docker
Устанавливаем act_runner:
apt install nodejs
# Указана актуальная версия act_runner на момент написания статьи
wget -O act_runner https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
chmod +x act_runner
В официальной документации о Node.js ничего не сказано. Однако без него в Gitea Actions у меня не появлялась информация о ходе стадий пайплайна. О такой же проблеме есть сообщение на форуме Gitea.
Готовим структуру каталогов:
cp act_runner /usr/local/bin/
mkdir /etc/act_runner /var/lib/act_runner
chown -R root:act_runner /etc/act_runner /var/lib/act_runner
chmod 770 /etc/act_runner /var/lib/act_runner
Создаём дефолтный конфигурационный файл:
su -c 'act_runner generate-config > /etc/act_runner/config.yaml' act_runner
В конфигурационном файле act_runner указываем путь к файлу регистрации act_runner и добавляем лейблы для нашего раннера:
vim /etc/act_runner/config.yaml
runner:
...
file: /etc/act_runner/.runner
...
labels:
- "ubuntu-22.04:docker://gitea/etc/act_runner/.runner-images:ubuntu-22.04"
- "werf"
# - "можно указать свой тег по вкусу"
С помощью лейблов в CI/CD-пайплайне можно отправлять задачи на разные раннеры. Например, можно разделить раннеры для сборки и доставки или на одном раннере собирать бэкенд, а на другом — фронтенд. В моём случае указан универсальный лейбл werf
.
На этом этапе нужно зарегистрировать act_runner на сервере Gitea. В Gitea раннер может быть зарегистрирован на разном уровне использования: глобальный уровень,
уровень организации или уровень отдельного репозитория. Выбираем глобальный уровень.
На сервере Gitea через веб-интерфейс получаем токен для регистрации раннера: Site Administration → Actions → Runners → Create new Runner.
На сервере с act_runner выполняем регистрацию, где указываем домен Gitea и подставляем полученный выше токен:
act_runner register --no-interactive \
--instance https://<your_gitea_server_domain> \
--token JgZESdw13qUl0gk0hkL0YfkjnQ9qA0rH2OBnBcUFeoupR \
--name sandbox-gitea-runner
Переносим регистрационный файл .runner
в каталог с настройками:
chown act_runner:act_runner .runner
mv .runner /etc/act_runner/
Создаём юнит systemd
:
vim /etc/systemd/system/act_runner.service
[Unit]
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service
[Service]
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/var/lib/act_runner
TimeoutSec=0
RestartSec=10
Restart=always
User=act_runner
[Install]
WantedBy=multi-user.target
Инициализируем юнит и проверяем его работу:
systemctl daemon-reload
systemctl enable act_runner --now
systemctl status act_runner.service
Готово, теперь можно посмотреть зарегистрированный раннер в Gitea. Для этого в веб-интерфейсе заходим по пути: Site Administration → Actions → Runners. В графе Status
видно, что раннер в текущее время подключён и ожидает заданий.
Подготовка раннера для работы с Kubernetes
Теперь нам нужно настроить доступ к Kubernetes API. Он понадобится для выполнения стадий пайплайнов, в которых предусматривается работа с K8s: например, деплой приложения, создание/удаление ревью окружений, задания по расписанию и тому подобное.
Со стороны кластера мы создаём системного пользователя и предоставляем ему права. Затем генерируем конфигурационный файл kubeconfig, который позволит раннеру управлять кластером через утилиту kubectl.
Настраиваем права доступа. В кластере DKP создаём сервисного пользователя с помощью ресурса ServiceAccount
:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: act-runner
namespace: d8-service-accounts
Генерируем секретный токен:
---
apiVersion: v1
kind: Secret
metadata:
name: act-runner-token
namespace: d8-service-accounts
annotations:
kubernetes.io/service-account.name: act-runner
type: kubernetes.io/service-account-token
Назначаем права доступа для нашего сервисного пользователя. Для примера создаём пользователя так, как указано ниже, но в целом организация доступа в кластер для раннера — это тема для отдельной статьи.
---
apiVersion: deckhouse.io/v1
kind: ClusterAuthorizationRule
metadata:
name: act-runner
spec:
subjects:
- kind: ServiceAccount
name: act-runner
namespace: d8-service-accounts
accessLevel: SuperAdmin
Создаём файл kubeconfig. На основе созданного сервисного пользователя act-runner сформируем конфигурационный файл для kubectl.
Моя конфигурация стенда предполагает, что act_runner и Deckhouse Kubernetes Cluster находятся в одной локальной сети. Если у вас другая архитектура, процесс формирования конфигурационного файла будет иным, подробности ищите в документации.
1. Заполняем переменные окружения:
export SERVISE_ACCOUNT_TOKEN_NAME=act-runner-token
# Переменные CLUSTER_NAME и USER_NAME могут быть произвольными
export CLUSTER_NAME=charlie-sandbox
export USER_NAME=act-runner.${CLUSTER_NAME}
export CONTEXT_NAME=${CLUSTER_NAME}-${USER_NAME}
export FILE_NAME=kube.config
2. Получаем сертификат CA-кластера Kubernetes:
kubectl get cm kube-root-ca.crt -o jsonpath='{ .data.ca\.crt }' > /tmp/ca.crt
3. Формируем секцию cluster. Для доступа используется IP-адрес API-сервера:
kubectl config set-cluster $CLUSTER_NAME --embed-certs=true \
--server=https://$(kubectl get ep kubernetes -o json | jq -rc '.subsets[0] | "\(.addresses[0].ip):\(.ports[0].port)"') \
--certificate-authority=/tmp/ca.crt \
--kubeconfig=$FILE_NAME
4. Генерируем секцию user с токеном из Secret’а ServiceAccount
в файле конфигурации kubectl:
kubectl config set-credentials $USER_NAME \
--token=$(kubectl -n d8-service-accounts get secret $SERVISE_ACCOUNT_TOKEN_NAME -o json |jq -r '.data["token"]' | base64 -d) \
--kubeconfig=$FILE_NAME
5. Формируем контекст в файле конфигурации kubectl:
kubectl config set-context $CONTEXT_NAME \
--cluster=$CLUSTER_NAME --user=$USER_NAME \
--kubeconfig=$FILE_NAME
6. Устанавливаем сгенерированный контекст как используемый по умолчанию в файле конфигурации kubectl:
kubectl config use-context $CONTEXT_NAME --kubeconfig=$FILE_NAME
Копируем полученный конфигурационный файл на сервер с act_runner:
scp kube.config <your_gitea_runner_server>:~/kube.config
Переходим на раннер-сервер и переносим конфигурационный файл kubectl в каталог пользователя act_runner:
mkdir /home/act_runner/.kube/
mv kube.config /home/act_runner/.kube/config
chown -R act_runner:act_runner /home/act_runner/.kube
Проверяем, работает ли kubectl со сформированным конфигом:
su - act_runner
kubectl get ns
Будет выведен список пространств имён кластера, создадим тестовое пространство имён и под:
kubectl create ns runner-test-ns
kubectl -n runner-test-ns run test-pod
kubectl delete ns runner-test-ns
namespace "runner-test-ns" deleted--image=nginx
pod/test-pod created
Видим, что тестовый под с nginx работает, удаляем пространство имён:
kubectl delete ns runner-test-ns
namespace "runner-test-ns" deleted
Ура, с настройками раннера можно закончить! Перейдём к настройке Gitea Actions CI/CD.
Настройка Gitea Actions CI/CD
Перед написанием Gitea Actions-пайплайнов нам нужно создать специального пользователя и сформировать для него токен для работы с встроенным в Gitea container registry. Токен данного пользователя будем использовать в пайплайнах и при скачивании образов контейнеров в кластере Kubernetes.
Создаём пользователя docker_puller
: Site administration → Identity & Access → Organization → User Accounts → Create User Account.
Чтобы у созданного пользователя docker_puller был доступ ко всем репозиториям организации, добавляем его в группу Owners своей организации (у меня это team-romeo): Site administration → Identity & Access → Organization → org_name → Teams → Owners → Add Team Member.
Логинимся в Gitea под пользователем docker_puller и выписываем токен для работы с container registry: User → Settings → Applications → Generate New Token.
Укажем права, которые будут доступны пользователю по данному токену:
token Name: registry_api
repository: Read
package: Read and Write
Обратите внимание: новый токен нужно сохранить отдельно, так как он будет недоступен для просмотра после перехода со страницы.
Для возможности использования токена во всех пайплайнах добавляем его в секреты на уровне организации: Organization → Settings → Actions → Secrets WERF_IMAGES_REPO_TOKEN=<your_token_value>
Аналогичным образом в переменные добавляем логин специального пользователя и доменное имя сервера Gitea. Но уже не в секреты, а в обычные переменные: Organization → Settings → Actions → Variables
WERF_IMAGES_REPO_USER=docker_puller
WERF_REPO=your_gitea_domain_name.com
Значения секретных переменных в листинге пайплайнов не будут видны, это позволяет скрыть конфиденциальную информацию.
Чтобы кластер Kubernetes мог при деплое приложения пулить образы из репозитория, ему нужны логин и пароль от container registry. Для этого создаём в кластере Deckhouse YAML-манифест Secret
, в котором указываем адрес нашего container registry, пользователя docker_puller и его токен:
# Создаём в дефолтном пространстве имён Secret с именем gitea-regsecret
kubectl -n default create secret docker-registry gitea-regsecret \
--docker-server=$WERF_REPO \
--docker-username=$WERF_IMAGES_REPO_USER \
--docker-password=$WERF_IMAGES_REPO_TOKEN
В Deckhouse Kubernetes Platform есть незаменимый модуль secret-copier, который автоматически копирует секреты по всем пространствам имён. Для копирования секретов достаточно добавить специальный лейбл на нужный секрет.
Проставим лейблы на наш секрет с доступом к registry:
# Добавляем лейбл для secret-copier
kubectl -n default label secrets gitea-regsecret secret-copier.deckhouse.io/enabled=""
Наш секрет gitea-regsecret
будет автоматически скопирован во все пространства имён, подобным образом можно раскидывать секреты SSL-сертификатов.
Промежуточный итог
Теперь всё готово к созданию тестового репозитория и написанию Gitea Actions-пайплайнов! Этим мы займёмся в заключительной части статьи.
P. S.
Читайте также в нашем блоге: