Ansible-роли и OpenTofu-шаблоны для развёртывания инфраноды и Talos-кластера платформы ASVO https://git.asvo.io/ASVO/platform
  • Jinja 49.1%
  • HCL 41.1%
  • Go Template 9.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Mikhail Vorontsov 181c4a869a
All checks were successful
ci/woodpecker/push/tofu Pipeline was successful
ci/woodpecker/push/yamllint Pipeline was successful
ci/woodpecker/push/ansible Pipeline was successful
ci: add cache for ansible pipeline (#1)
Reviewed-on: ASVO/platform#1
2026-08-11 08:32:54 +00:00
.woodpecker ci: add cache for ansible pipeline (#1) 2026-08-11 08:32:54 +00:00
inventories/example style: fix yamllint errors 2026-08-10 22:28:05 +03:00
playbooks chore: prepare for public release 2026-08-10 21:49:35 +03:00
roles chore: suppress ansible-lint var-naming warnings 2026-08-10 23:06:43 +03:00
terraform/example docs: replace Terraform with OpenTofu in documentation 2026-08-10 22:19:06 +03:00
.ansible-lint chore: prepare for public release 2026-08-10 21:49:35 +03:00
.editorconfig chore: prepare for public release 2026-08-10 21:49:35 +03:00
.gitignore ci: add cache for ansible pipeline (#1) 2026-08-11 08:32:54 +00:00
.yamllint ci: add cache for ansible pipeline (#1) 2026-08-11 08:32:54 +00:00
ansible.cfg chore: prepare for public release 2026-08-10 21:49:35 +03:00
LICENSE chore: prepare for public release 2026-08-10 21:49:35 +03:00
README.md docs: replace Terraform with OpenTofu in documentation 2026-08-10 22:19:06 +03:00
requirements.yml feat: add ansible collection requirements 2026-08-10 23:05:17 +03:00

asvo-platform

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

Поддержка

В настоящее время платформа находится в пред-релизном состоянии. Возможно обилие ошибок и глюков. Поддержка пользователей осуществляется пока только в закрытой тг-группе силами самого сообщества: https://t.me/+BYHEKrajkKw3MjVi

АРМ оператора

Желательно иметь Linux в качестве ОС, но наверняка можно как-то работать и под Windows.

На самом АРМ необходимо или желательно иметь следующий софт:

  • Ansible, для раскатки плейбуков;
  • kubectl, для управления кластером;
  • git, чтобы работать в репозитории с кодом инфраструктуры;
  • k9s, если хотите управлять кластером через удобный псевдографический интерфейс;
  • skopeo, чтобы заполнить registry инфраноды, если вы будете делать установку в закрытый контур;
  • OpenTofu, если планируете использовать его для централизованного создания и управления виртуальными машинами;
  • openssl, чтобы генерировать собственные сертификаты;

Подготовка инфраноды

Мы выполняли тестирование на операционной системе Ubuntu 24.04, но вся инфраструктура контейнерезирована, и по сути, от системы требуется только docker с плагином compose, то есть, теоретически, должно заработать на любой ОС.

Необходимо, чтобы инфранода была доступна для оператора по SSH, а так же чтобы у оператора была возможность выполнять эсколацию привелегий (команда sudo), либо чтобы он работал напрямую как root (не рекомендуется).

Создание кластера с использованием OpenTofu с Proxmox-провайдером

Если у вас развернута открытая платформа виртуализации Proxmox, вы можете так же использовать OpenTofu для быстрого и управляемого создания виртуальных машин под свой кластер на нем. Порядок действий для этого будет примерно такой:

  1. Создайте в вашем Proxmox-кластере cloud-init-образ ubuntu, например, воспользовшись этой инструкцией;
  2. Настройте токен доступа к API вашего proxmox;
  3. Скопируйте шаблон cp -r terraform/example terraform/your-super-cluster/ и отредактируйте файлы в нем под ваше окружение (providers.tf — адрес API вашего Proxmox, terraform.tfvars — узел, пул, сеть, ssh-ключи и пароль root); 3.1. Скопируйте .env.example в .env и впишите туда токен доступа к API (файл в .gitignore, в репозиторий не попадёт);
  4. Инициализируйте окружение командой tofu init — она же создаст .terraform.lock.hcl с хешами провайдера (обратите внимание, реестры OpenTofu и HashiCorp блокируют доступ с российских IP-адресов, для инициализации используйте proxy или vpn);
  5. После инициализации выполните tofu plan, убедитесь в корректности планируемых действий, после чего выполните tofu apply;

Использование Proxmox с OpenTofu даст Вам возможность быстро создавать и управлять параметризированными окружениями, это очень сильная магия.

Создание кластера на Virtualbox

Если у Вас достаточно мощностей вашего АРМа, вы можете развернуть тестовый кластер прямо на нем, используя VirtualBox. Необходимо обеспечить минимум 3 шт. Control-Plane нод с хотя бы 4Gb RAM, и одну инфраноду, так же с 4 Gb. Можете попробовать запустить кластер на локальном VBox с меньшими ресурсами, но мы это не тестировали. Так же вам понадобится постоянное хранилище, как минимум, два диска: один под ОС TalosLinux, другой для CSI кластера (Linstor). Создайте необходимы виртуальные машины, настройте сеть (желательно, c VboxHostOnly-адаптером). Рекомендуем в процессе на разных этапах делать снапшоты виртуальных машин - так отладка будет быстрее и легче, но, желательно, в выключенном состояннии, чтобы не было проблем с "разъезжанием" кластера из-за того что какая-то нода "вернулась в прошлое" прежде, чем это сделали другие.

Создание кластера на "голом железе" (bare metal)

Это самый "хардкорный" вариант для начала, однако, именно он раскрывает всю мощь kubernetes и платформы ASVO. Для создания кластера на "голом железе" вам необходимо сперва подготвить само железо.

Вот примерный чек-лист:

  • У нод кластера 4+ Gb опервтивной памяти (возможно, получится запустить на меньшем количестве, но вряд ли это будет жизнеспособно)
  • Выставлен правильный приоритет загрузки: 1) Системный диск -> 2) Загрузка по сети (iPXE)
  • Сетевая карта ноды должна поддерживать iPXE-загрузку. Обычно с этим нет проблем у серверного оборудования, однако, десктопное может подкачать. Если у вас достаточно старая сетевая карта, попробуйте обновить её прошивку или BIOS, если она встроенная. В крайнем случае воспользуйтесь специальным загрузчиком iPXE.iso с официального сайта, который можно записать на usb-накопитель или даже компакт-диск, чтобы система смогла загрузиться и передать управление сетевой карте
  • Если хотите простой раскатки Linstor, убедитесь что диски на всех нодах определяются в udev единообразно (например, /dev/sda для целевого системного диска /dev/sdb для HDD, /dev/sdc для SSD). В противном случае придется сильно править манифесты Linstor. Чтобы проверить порядок отображения, загрузитесь с любого live-образа linux, и выполните команду lsblk. Чтобы поменять порядок определения дисков в Udev, поменяйте порядок подключения накопителей к материнской плате.
  • Все физические диски должны быть очищены от любой разметки. Для того чтобы очистить диски от разметки, загрузитесь с любого live-образа linux, и выполните команду `wipefs -fa /dev/sdX' последовательно для каждого диска (sda, sdb, sdc...)
  • Зафиксируйте MAC-адреса всех ваших нод (ip -br link) - это понадобится для дальнейшего составляения манифестов
  • Все ноды видят друг друга и инфраноду через L2-сеть

Подготовка манифестов

Воспользуйтесь готовым шаблоном inventories/example — это кластер из трёх control-plane и трёх worker-нод с собственным registry на инфраноде. Скопируйте его под имя своего стенда и отредактируйте основные файлы:

inventories/example
├── group_vars
│   ├── all.yml
│   └── infra
│       ├── cli.yml				- настройка прикладных утилит, а так же параметры загрузки ядра Talos
│       ├── components.yml		- системные компоненты, устанавливаемые вместе с ОС
│       ├── global.yml			- глобальные переменные кластера
│       ├── infra.yml			- переменные сервисов на инфраноде
│       ├── talm.yml			- переменные для Talm - рендера конфигураций Talos-нод
│       └── vault.yaml			- пароли и ключи (зашифруйте через ansible-vault)
└── inventory.yml				- описание нод кластера

Все адреса, домены и пароли в шаблоне — плейсхолдеры (192.168.100.0/24, example.loc, registry.example.com, CHANGEME), их нужно заменить на свои.

Обратите внимание, что для первоначальной инициализации gitea плейбуку будет нужно, чтобы в папке /root/.ssh/ лежали ssh-ключи admin admin.pub админ-пользователя Gitea, чтобы инициализировать репозиторий с кодом инфраструктуры. Не забудьте сгенерировать и "донести" его туда и публичный ключ в манифест infra.yml (так же можно добавить свои ключи туда). Так же вам понадобится ключевая пара для puller, создать её можно с помощью ssh-keygen.

При редактировании переменных Вам помогут readme-файлы ролей, смотрите каталог roles. По правилам линтера ansible, имя переменной должно начинаться с имени роли.

Раскатка инфраноды

Последовательность установки инфраноды будет одной и той же.

Подготовьте инфраструктурные сервисы инфраноды:

ansible-playbook -i inventories/<ваш_стенд>/inventory.yml playbooks/bootstrap/infra.yml

По окончании работы этого плейбука, на инфраноде будут созданы сервисы tier-0:

  • chrony, для синхронизации времени на нодах кластера
  • dnsmasq, для обеспечения загрузки по нод кластера через сеть и резолвинг DNS
  • gitea, для обеспечения GitOps для системных кластерных служб
  • httpd, для доставки основных системных манифестов и параметров до того, как заработает GitOps
  • registry, для контейнеров кластера

Все сервисы находятся в compose-проектах по пути /opt/asvotech. Если что-то по этому пути не работает, используйте docker compose logs для отладки.

Контроль успешного развертывания сервисов - отсутствие ошибок в выводе ansible, а так же работающие контейнеры:

root@infra:~# docker ps
CONTAINER ID   IMAGE                                                   COMMAND                  CREATED      STATUS                PORTS                                                                                      NAMES
c75ea7fc61f8   registry.example.com/library/httpd:2.4.65-alpine   "httpd -D FOREGROUND…"   3 days ago   Up 3 days (healthy)   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp                                                    httpd
6a53e7493f8f   registry.example.com/library/registry:3.0.0        "/entrypoint.sh /etc…"   3 days ago   Up 3 days (healthy)   0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp                                                registry
c9bcac4b023c   registry.example.com/dockurr/chrony:4.8            "/bin/startup"           3 days ago   Up 3 days (healthy)   0.0.0.0:123->123/udp, [::]:123->123/udp                                                    chrony
1f2b0e27e313   registry.example.com/gitea/gitea:1.24.6-rootless   "/usr/bin/dumb-init …"   3 days ago   Up 3 days (healthy)   0.0.0.0:2222->2222/tcp, [::]:2222->2222/tcp, 0.0.0.0:3000->3000/tcp, [::]:3000->3000/tcp   gitea
2351851e6398   registry.example.com/postgres:16.9-alpine          "docker-entrypoint.s…"   3 days ago   Up 3 days (healthy)   5432/tcp                                                                                   gitea-postgres
72cb51ecc4aa   registry.example.com/dockurr/dnsmasq:2.91          "/sbin/tini -- /usr/…"   3 days ago   Up 3 days (healthy)                                                                                              dnsmasq

Если всё ок, можно приступать к сетевой загрузке. Включите ваши виртуальные или физические ноды, проверьте ход загрузки по iPXE. Если вы всё сделали правильно, Talos у вас должен загрузиться в maintence-режиме на каждой из нод. Если это так, переходите к следующему этапу.

Раскатка кластера

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

ansible-playbook -i inventories/<ваш_стенд>/inventory.yml playbooks/cluster/create.yml 

Он сам проконтролирует корректность загрузки нод кластера, и проведёт все необходимые манипуляции. Если плейбук отработал без ошибок, поздравляем, ваш кластер успешно установлен! Проверим это, получив к нему административный доступ. Для этого выполните:

cd /opt/asvotech/cluster/*имя_вашего_кластера*
talm kubeconfig -n X.X.X.X -e X.X.X.X

где X.X.X.X - ip-адрес любого из мастеров (control-plane нод) вашего кластера.

В результате вы получте файл kubeconfig, в директории ~/.kube/config, который позволит администрировать кластер. Его можно забрать с инфраноды на АРМ администратора.

Выполните команду "kubectl get no" чтобы увидеть состояние ваших нод, например:

root@talos-dev-infra:~# kubectl get no
NAME           STATUS   ROLES           AGE   VERSION
dev-master-1   Ready    control-plane   23d   v1.33.1
dev-master-2   Ready    control-plane   23d   v1.33.1
dev-master-3   Ready    control-plane   23d   v1.33.1
dev-worker-1   Ready    <none>          23d   v1.33.1
dev-worker-2   Ready    <none>          23d   v1.33.1

Все ноды должны быть в статусе "Ready"

Так же выполните команду

kubectl get pod -A

чтобы увидеть список работающих подов кластера. Все поды должны быть в статусе "Running" или "Completed".

Если вы всё сделали правильно и получили такой результат, можете переходить к следующему этапу. Кстати, здесь отличное место, чтобы сделать контрольный снапшот ваших виртуальных машин!

Установка платформы и последующее администрирование кластера

Итак, вы получили пустой, готовый к работе кластер. Давайте теперь наполним его системными службами и сервисами. Для начала склонируйте на свой АРМ GitOps-репозиторий с инфраноды. Если вы предали в Gitea на этапе подготовки манифестов собственные пользовательские ssh-ключи, будет достаточно выполнить команду:

git clone ssh://git@*АДРЕСНФРАНОДЫ*:2222/*ИМЯ_КЛАСТЕРА*/cluster.git

Вы получите код инфраструктуры, с помощью редактирования которого вы сможете управлять вашим кластером! В противном случае, залогиньтесь в gitea по адресу https://АДРЕСНФРАНОДЫ:3000/ и дайте себе все нужные доступы.

Инициализационный репозиторий имеет много предустановок (адресация, ssl-сертификаты и т.д.), которые, скорее всего, не подойдут для вас. Просмотрите все основные манифесты в папке flux/, platform/ИМЯ_СЕРВИСА/config и platform/ИМЯ_СЕРВИСА/kustomization код и исправьте нужные места. Не забудьте сделать git add/git commit/git push после своих правок!

После того, как репозиторий с кодом будет настроен, самое время применить его! Для этого нужно выполнить три действия:

  1. Создайте секрет с ssh-отпечатком Gitea и git-пользователя для flux:
ssh-keyscan -p 2222 *АДРЕСНФРАНОДЫ* > known_hosts

kubectl create secret generic flux-ssh \
  --namespace=cluster-flux \
  --from-file=identity=./puller \
  --from-file=identity.pub=./puller.pub \
  --from-file=known_hosts=./known_hosts
  1. Настройте репозиторий, манифестируя с помошью kubectl apply -f flux-gitrepo.yaml соответствующий манифест:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: cluster
  namespace: cluster-flux
spec:
  interval: 1m0s
  ref:
    branch: main
  url: ssh://git@1**АДРЕСНФРАНОДЫ**:2222/**ИМЯ_КЛАСТЕРА**/cluster.git
  secretRef:
    name: flux-ssh
  1. Настройте flux применять все .yaml-манифесты из папки ./flux/ репозитория:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: cluster
  namespace: cluster-flux
spec:
  interval: 1m0s
  path: ./flux/
  prune: true
  sourceRef:
    kind: GitRepository
    name: cluster
  targetNamespace: cluster-flux
  wait: true

После последнего действия, если вы всё сделали правильно в кластере появится множество различных kustomizations и helmrelease, которые постепенно будут устанавливаться в кластер. Мониторить их состояние можно, например, вот так:

watch kubectl -n cluster-flux get helmreleases.helm.toolkit.fluxcd.io 

и

watch kubectl -n cluster-flux get kustomizations.kustomize.toolkit.fluxcd.io

Если в итоге всё раскаталось правильно, вы должны будете увидеть что-то вроде:

$ kubectl -n cluster-flux get kustomizations.kustomize.toolkit.fluxcd.io
NAME                     AGE   READY   STATUS
certmanager-configs      3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster                  3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-auth             3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-auth-configs     3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-console          3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-dns-configs      3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-observability    3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
cluster-s3               3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
ingress                  3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
metallb-configs          3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
metallb-kustomizations   3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1
piraeus-operator         3d    True    Applied revision: main@sha1:387a91bb45dc797911832f90a19c31b1c3f5e9d1

$ kubectl -n cluster-flux get helmreleases.helm.toolkit.fluxcd.io 
NAME                              AGE   READY   STATUS
cluster-consoloe                  3d    True    Helm install succeeded for release cluster-console/headlamp.v1 with chart headlamp@0.37.0
cluster-csi-affinity-controller   3d    True    Helm install succeeded for release cluster-csi/linstor-affinity-controller.v1 with chart linstor-affinity-controller@1.5.0
cluster-csi-linstor               3d    True    Helm install succeeded for release cluster-csi/linstor.v1 with chart linstor-cluster@1.1.1
cluster-dbms-cnpg                 3d    True    Helm install succeeded for release cluster-dbms/cnpg.v1 with chart cloudnative-pg@0.26.1
cluster-dbms-dragonfly-operator   3d    True    Helm install succeeded for release cluster-dbms/dragonfly-operator.v1 with chart dragonfly-operator@v1.3.1
cluster-dbms-mariadb-crds         3d    True    Helm install succeeded for release cluster-dbms/mariadb-crds.v1 with chart mariadb-operator-crds@25.10.2
cluster-dbms-mariadb-operator     3d    True    Helm install succeeded for release cluster-dbms/mariadb-operator.v1 with chart mariadb-operator@25.10.2
cluster-dns                       3d    True    Helm install succeeded for release cluster-dns/powerdns.v1 with chart powerdns@0.1.0
cluster-dns-external-dns          3d    True    Helm install succeeded for release cluster-dns/external-dns.v1 with chart external-dns@1.19.0
cluster-dns-operator              3d    True    Helm install succeeded for release cluster-dns/powerdns-operator.v1 with chart powerdns-operator@0.6.0
cluster-ingress                   3d    True    Helm install succeeded for release cluster-ingress/ingress-int.v1 with chart ingress-nginx@4.13.3
cluster-ingress-ext               3d    True    Helm install succeeded for release cluster-ingress/ingress-ext.v1 with chart ingress-nginx@4.13.3
cluster-keycloak-edp-operator     3d    True    Helm install succeeded for release cluster-auth/keycloak-edp-operator.v1 with chart keycloak-operator@1.29.0
cluster-keycloak-operator         3d    True    Helm install succeeded for release cluster-auth/keycloak-operator.v1 with chart keycloak-operator@1.0.20251104042352
cluster-lb                        3d    True    Helm install succeeded for release cluster-lb/metallb.v1 with chart metallb@0.15.2
cluster-observability             3d    True    Helm install succeeded for release cluster-observability/vm.v1 with chart victoria-metrics-k8s-stack@0.63.5
cluster-pki                       3d    True    Helm install succeeded for release cluster-pki/cert-manager.v1 with chart cert-manager@v1.19.1
cluster-s3                        3d    True    Helm install succeeded for release cluster-s3/sys-seaweedfs.v1 with chart seaweedfs@4.0.400
cluster-s3-csi                    3d    True    Helm install succeeded for release cluster-s3/sys-seaweedfs-csi.v1 with chart seaweedfs-csi-driver@0.2.3

И на этом поздравляем, вы - великолепны!

Удаление кластера

Если ваш кластер был создан на виртуальных машинах, самый быстрый и простой способ удалить его - просто откатиться к начальному снапшоту с "пустыми" виртуалками. Так же, если вы использовали OpenTofu, можно снести весь ваш стенд, выполнив tofu destroy.

В случае с железным кластером, Вам сперва потребуется затереть разметку на всех дисках с данными, например, вот так:

#!/bin/bash

linstor_nodes=$(kubectl -n cluster-csi get pod | grep linstor-satellite | awk '{print $1}')

for node in $linstor_nodes; do
	echo $node;
	kubectl -n cluster-csi exec -it $node -- wipefs -fa /dev/sdb
	kubectl -n cluster-csi exec -it $node -- wipefs -fa /dev/sdc
done

После чего запустить плейбук, разрушающий кластер:

ansible-playbook -i inventories/<ваш_стенд>/inventory.yml playbooks/cluster/reset.yml

После успешного сброса ноды снова загрузятся в maintence mode, и их можно будет использовать повторно

Лицензия

Copyright (C) 2026 ASVO

Этот проект распространяется на условиях GNU Affero General Public License версии 3 или, по вашему выбору, любой более поздней версии. Полный текст — в файле LICENSE.