- SMTP Relay (bokysan/mail): Postfix relay через Yandex SMTP, порт 465 с
TLS wrappermode, trusted networks only (pod/service CIDR), без аутентификации
внутри кластера — поды отправляют на smtp-relay:25
- HashiCorp Vault (hashicorp/vault): standalone и HA (Raft) режимы,
auto-unseal: k8s Secret (homelab), AWS KMS, GCP CKMS, Azure Key Vault,
Transit; Vault Agent Injector по умолчанию; Job инициализации + Unsealer
Deployment для k8s режима; README с полным гайдом по injection в YAML/Helm
- External Secrets Operator (ESO): синхронизирует Vault секреты в k8s Secrets,
ClusterSecretStore с AppRole auth, README с примерами ExternalSecret в
YAML манифестах, Helm чартах и ArgoCD
Обновлены: addons.yml (3 новых флага + секции), vault.yml.example
(smtp_relay_password, aws_kms_*, eso_approle_secret_id),
playbooks/addons.yml, Makefile
Proxy cache (harbor_proxy_cache_enabled: true):
- Автоматически создаёт registry endpoints + proxy cache проекты для:
docker.io, gcr.io, quay.io, ghcr.io, registry.k8s.io, mcr.microsoft.com, public.ecr.aws
- При pull образа через harbor.example.com/<registry>/<image> он кэшируется
- Реализовано через alpine:3.19 + curl + jq Kubernetes Job (вызывает Harbor REST API изнутри кластера)
Tag retention (harbor_retention_enabled: true, harbor_retention_max_tags: 3):
- Политика "latestPushedN=3" применяется ко ВСЕМ проектам (включая proxy cache)
- Пропускает проекты с уже существующей политикой (idempotent)
- Запуск: ежедневно в 03:00 UTC (cron schedule в Harbor)
Механизм: Job запускается после Helm install, достучивается до harbor-core по
internal service DNS, ждёт API готовности (40 попыток × 15 сек = 10 мин max).
Harbor (harbor/harbor, авто-версия):
- Values-шаблон с полной конфигурацией expose/ingress/tls/persistence
- external DB при addon_postgresql=true (Job для создания user/db)
- internal PostgreSQL + Redis в противном случае
- Метрики + ServiceMonitor при addon_prometheus_stack=true
Gitea (gitea-charts/gitea, авто-версия):
- Values-шаблон, встроенный PostgreSQL отключается при addon_postgresql=true
- Job для создания dedicated user/db в shared PostgreSQL
- Опциональный SSH NodePort (gitea_ssh_enabled)
- ServiceMonitor при addon_prometheus_stack=true
ownCloud OCIS (owncloud/ocis, авто-версия):
- Values-шаблон с insecure-режимом для HTTP
- Persistence для storageusers/storagesystem/nats/search/thumbnails
- Пароль admin через extraEnv IDM_ADMIN_PASSWORD
- ServiceMonitor при addon_prometheus_stack=true
Nextcloud (nextcloud/nextcloud, авто-версия):
- Values-шаблон, external PostgreSQL при addon_postgresql=true
- Job для создания dedicated user/db в shared PostgreSQL
- Встроенный Redis для file locking
- nextcloud-exporter (metrics sidecar) + ServiceMonitor
- Cron-задача для фоновых операций
Авто-версия: helm search repo ... --output json | from_json[0].version
Применяется при version: "" — переопределяется через ARGS="-e *_version=X.Y.Z"
- Добавлены tempo_ingress_enabled/host/class/tls/cert_issuer в defaults
- Создан tempo-values.yaml.j2 (вместо inline values в задаче — проще с условиями)
- tasks/main.yml обновлён под values_files + показывает ingress-адрес в итоговом выводе
Loki (grafana/loki 6.7.3):
- Монолитный режим (singleBinary) — оптимально для малых кластеров
- Хранение: filesystem по умолчанию, автоматически S3 если addon_minio=true
(создаёт бакеты chunks/ruler/admin в MinIO через Job)
- Retention 30 дней, отключён self-monitoring (без Grafana Agent Operator)
- ServiceMonitor + Grafana datasource ConfigMap при addon_prometheus_stack=true
- Datasource включает derivedFields → Tempo если addon_tempo=true
Promtail (grafana/promtail 6.16.4):
- DaemonSet на всех нодах (tolerations: Exists)
- Отправляет логи в Loki по http://loki.loki.svc.cluster.local:3100
- ServiceMonitor при addon_prometheus_stack=true
Tempo (grafana/tempo 1.10.3):
- Монолитный режим с PVC для трейсов
- Receivers: OTLP gRPC/HTTP, Jaeger, опционально Zipkin
- Grafana datasource ConfigMap при addon_prometheus_stack=true
(tracesToLogsV2 → Loki если addon_loki=true, serviceMap → Prometheus)
- ServiceMonitor при addon_prometheus_stack=true
Pushgateway (prometheus-community/prometheus-pushgateway 2.14.0):
- Устанавливается в monitoring namespace (рядом с Prometheus)
- ServiceMonitor при addon_prometheus_stack=true
- Опциональные persistence и ingress
- Устанавливает prometheus-node-exporter на NFS-хостах (включает NFSD-коллектор из /proc/net/rpc/nfsd)
- Открывает порт 9100 в UFW для cluster-сети
- При addon_prometheus_stack=true создаёт в k8s:
- headless Service nfs-server-node-exporter
- Endpoints со списком IP NFS-хостов из inventory
- ServiceMonitor с label release: kube-prometheus-stack
- cert-manager: prometheus.enabled + servicemonitor (port 9402)
- ingress-nginx: динамический ServiceMonitor вместо захардкоженного false
- ArgoCD: metrics.enabled для всех компонентов (server, repoServer, applicationSet, notifications, controller)
- Longhorn: metrics.serviceMonitor.enabled
- Istio: ServiceMonitor для istiod (port http-monitoring), enablePrometheusMerge для sidecar-метрик, fix istio_telemetry_enabled → istio_metrics_enabled в шаблоне
Во всех случаях ServiceMonitor создаётся только при addon_prometheus_stack: true.
Базы данных:
- addons/postgresql: Bitnami PostgreSQL (Helm), vault_postgresql_*
- addons/mysql: Bitnami MySQL (Helm), vault_mysql_*
Объектное хранилище и backup:
- addons/minio: Bitnami MinIO в distributed режиме (4 ноды по умолчанию)
- addons/velero: backup кластера через Velero + MinIO как S3 backend;
bucket создаётся автоматически через mc Job; daily schedule 02:00
Безопасность:
- addons/crowdsec: CrowdSec LAPI + DaemonSet агенты, мониторит ingress-nginx;
опциональный nginx bouncer (crowdsec_nginx_bouncer_enabled: true)
Резервное копирование БД:
- addons/databasus: OCI chart, автоматически подключается к addon_postgresql
и addon_mysql когда те включены (shared endpoint через postgresql_external_host
и mysql_external_host)
Общее:
- group_vars/all/addons.yml: флаги addon_* + конфиги для всех 6 аддонов;
shared DB endpoints postgresql_external_host / mysql_external_host
- group_vars/all/vault.yml.example: примеры паролей для всех аддонов
- Makefile: targets addon-postgresql/mysql/databasus/minio/velero/crowdsec
## Аддоны (group_vars/all/addons.yml)
- Создан group_vars/all/addons.yml — единое место для включения/отключения
аддонов (addon_ingress_nginx: true/false и т.д.) и их основных настроек
- Из group_vars/all/main.yml убраны все секции аддонов (NFS, CSI, ingress,
cert-manager, etcd backup, Istio, Prometheus) — остался только core кластер
- Создан playbooks/addons.yml — комбинированный плейбук с 10 плеями,
каждый с `when: addon_X | default(false) | bool`; запускает только включённые
- make install-full: core (site.yml) + аддоны по addons.yml
- make install-addons: только аддоны без переустановки core
- Убраны все *_enabled флаги из аддонов (cert_manager_enabled, istio_enabled,
prometheus_stack_enabled и др.) — аддон ставится явным вызовом
- kube-vip: убран skip guard и kube_vip_enabled флаг (core, всегда ставится)
- TLS defaults в argocd/longhorn/kubernetes-dashboard: убрана зависимость
от cert_manager_enabled, теперь просто false (задаётся явно)
- Kiali: убрана зависимость от prometheus_stack_enabled, добавлены переменные
kiali_prometheus_enabled/url и kiali_grafana_enabled/url
## Внешний etcd кластер
- Новая переменная k3s_etcd_type: embedded|external в main.yml
- inventory/hosts.ini: добавлена группа [etcd_nodes] — любые серверы,
не обязательно мастера
- roles/etcd/: полная роль для установки внешнего etcd кластера:
- install.yml — скачивает бинарник, создаёт пользователя и директории
- pki.yml — генерирует CA + server/peer/client сертификаты через openssl
на Ansible-контроллере; раскладывает на etcd ноды и k3s мастера
- service.yml — разворачивает etcd.env и systemd сервис, проверяет здоровье
- etcd.env.j2 и etcd.service.j2 — шаблоны конфигурации
- etcd_pki_local_dir: persistent путь (<project>/etcd-pki/) вместо /tmp,
etcd-pki/ добавлен в .gitignore
- roles/k3s/templates/k3s-server-config.yaml.j2: при external режиме
подставляет datastore-endpoint со всеми etcd нодами + пути к клиентским
сертификатам; при embedded — прежняя логика cluster-init
- playbooks/site.yml: условный плей для etcd перед k3s (тег etcd)
- make install-etcd: отдельная команда для развёртывания etcd кластера
## Управление etcd нодами
- playbooks/add-etcd-node.yml: добавить ноду в работающий etcd кластер
(PKI генерация → install → etcdctl member add → start с state=existing → verify)
- playbooks/remove-etcd-node.yml: безопасно удалить ноду из etcd кластера
(проверка кворума → member remove → stop → clean up PKI)
- playbooks/add-node.yml: при k3s_etcd_type=external и наличии ноды в
[etcd_nodes] автоматически добавляет её в etcd кластер после k3s
- playbooks/remove-node.yml: при k3s_etcd_type=external сначала удаляет
ноду из etcd (member remove + stop), затем из k3s
- make add-etcd-node NODE=etcd04 / make remove-etcd-node NODE=etcd04
- Команды add-etcd-node / remove-etcd-node в docker/entrypoint.sh
Проблема: bootstrap создавал отдельного пользователя ansible (k3s_admin_user),
хотя у нас уже есть cluster_service_users с k8s и devops.
Решение:
- k3s_admin_user: devops (один из cluster_service_users, не отдельный пользователь)
- bootstrap phase 1: создаёт ВСЕХ пользователей из cluster_service_users через k8s-user role
- bootstrap phase 2: деплоит SSH ключ Ansible runner только в authorized_keys k3s_admin_user
- roles/bootstrap/tasks/main.yml: удалено создание пользователя/группы/sudoers (теперь в k8s-user)
- roles/bootstrap/defaults/main.yml: удалены k3s_admin_shell/comment/groups (не нужны)
- добавлена проверка: k3s_admin_user должен быть в cluster_service_users (assert)
group_vars/all/main.yml:
- ansible_user: "{{ k3s_admin_user }}" — все playbooks подключаются как k3s_admin_user
- ansible_ssh_private_key_file: "~/.ssh/id_rsa"
- k3s_admin_ssh_additional_keys: [] — для нескольких инженеров через vault
inventory/hosts.ini:
- убраны ansible_user=ubuntu с каждого хоста (теперь в group_vars)
- убран ansible_ssh_private_key_file из group vars (теперь в group_vars/all/main.yml)
Список пользователей (cluster_service_users):
- заменяет отдельные k8s_service_user и devops_service_user переменные
- поддерживает неограниченное число пользователей — добавь строку в список
- каждый пользователь: name, comment, shell, sudo, key_type, key_bits, key_comment, ssh_dir
- playbooks/k8s-user.yml полностью переработан — все plays используют loop: cluster_service_users
- generate_keys/distribute_keys/create_user вызываются через include_role + vars
- .gitignore: keys/*_id_rsa (паттерн вместо перечисления конкретных имён)
Роль chrony — синхронизация времени:
- устанавливается ПЕРЕД k3s как обязательный компонент (добавлена в site.yml play 0)
- часовой пояс: chrony_timezone: "Europe/Moscow" (переопределяется в group_vars)
- NTP серверы: pool.ntp.org (настраиваемые через chrony_ntp_servers)
- community.general.timezone: идемпотентная установка TZ
- chronyc makestep: принудительная синхронизация при первом деплое
- устанавливается также на lab_hosts в playbooks/k8s-user.yml
- make chrony — отдельная цель для переустановки/смены TZ (make chrony TZ=UTC)
- команда chrony в entrypoint.sh
Роль k8s-user сделана универсальной:
- generate_keys.yml: имена фактов стали динамическими — {{ k8s_service_user }}_ssh_private_key
вместо захардкоженных k8s_ssh_private_key (поддержка любого пользователя)
- distribute_keys.yml: обращение к фактам через [k8s_service_user + '_ssh_private_key']
playbooks/k8s-user.yml переработан — 12 plays (6 для k8s + 6 для devops):
- devops plays вызывают ту же роль k8s-user с vars-переопределением k8s_service_user
- теги k8s/k8s_user и devops/devops_user — можно запустить одного пользователя
- ключи сохраняются: ./keys/k8s_id_rsa, ./keys/devops_id_rsa (приватные в .gitignore)
- имя файла ключа динамическое: {{ k8s_service_user }}_id_rsa
group_vars/all/main.yml:
- добавлены devops_service_user, devops_service_user_comment, devops_service_user_sudo и др.
Запуск только devops: ansible-playbook playbooks/k8s-user.yml --tags devops
Организация плейбуков:
- все .yml плейбуки перенесены из корня в playbooks/
- Makefile и entrypoint.sh обновлены — все пути с playbooks/ префиксом
- k8s-user.yml переработан: include_tasks → include_role (корректная работа из подкаталога)
Сохранение ключей и kubeconfig локально:
- k8s-user.yml: новый play сохраняет k8s SSH ключи в ./keys/ на машине запуска
- переменная k8s_local_keys_dir: "./keys" (настраивается в group_vars)
- .gitignore: keys/k8s_id_rsa исключён (публичный ключ можно коммитить)
- kubeconfig уже сохранялся роль k3s (k3s_kubeconfig_local_path: "./kubeconfig")
Автоматическая ротация сертификатов K3S (роль k3s-certs):
- K3S выпускает сертификаты на 1 год (hardcoded), таймер обеспечивает их обновление
- скрипт k3s-cert-check.sh: проверяет срок через openssl, ротирует при k3s_cert_rotate_before_days
- systemd service + timer: запуск по расписанию k3s_cert_check_schedule (по умолчанию monthly)
- RandomizedDelaySec: снижает нагрузку при одновременном запуске на нескольких нодах
- переменные: k3s_cert_validity_years: 5, k3s_cert_rotate_before_days: 90
- добавлен в site.yml (тег certs) и отдельный плейбук playbooks/k3s-certs.yml
- make k3s-certs и команда k3s-certs в entrypoint.sh
Роль mdadm:
- автоопределение RAID массива через mdadm --detail --scan
- монтирование в /storage через fstab (UUID-based, nofail)
- автоопределение fstype через blkid
- обновление mdadm.conf + initramfs
- флаг mdadm_enabled для отключения на отдельных нодах
Роль k8s-user:
- создание пользователя k8s + группа + sudo без пароля (visudo validation)
- генерация RSA 4096 ключевой пары на первом мастере (идемпотентно, creates:)
- раскладка приватного и публичного ключа на все ноды кластера
- добавление public key в authorized_keys — SSH с любой ноды на любую
- обновление /etc/hosts блоками через blockinfile (k3s_cluster + lab_hosts)
- поддержка lab_hosts: создание пользователя и деплой ключей через пароль из vault
Плейбуки:
- k8s-user.yml — полная оркестрация (5 plays: create → generate → distribute → hosts → lab)
- mdadm.yml — запуск роли mdadm на k3s_cluster
Инфраструктура:
- inventory: добавлена группа [lab_hosts] с примерами
- host_vars/nas01/vault.yml.example — шаблон credentials для лаб-серверов
- group_vars/all/main.yml: переменные mdadm_enabled и k8s_service_user_*
- Makefile: цели k8s-user и mdadm
- docker/entrypoint.sh: команды k8s-user и mdadm