Files
K3S/Makefile
Sergey Antropoff a94039e0f1 feat: аддоны через addons.yml, внешний etcd, управление etcd нодами
## Аддоны (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
2026-04-25 06:34:48 +03:00

528 lines
32 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ═══════════════════════════════════════════════════════════════════════════════
# K3S Ansible Stack — Makefile
# Всё запускается через Docker — Ansible устанавливать не нужно!
#
# Требования: docker, make
# Начало работы: make setup → отредактируй .env и inventory → make install
# ═══════════════════════════════════════════════════════════════════════════════
# ── Конфигурация ──────────────────────────────────────────────────────────────
IMAGE_NAME := k3s-ansible
CONTAINER_NAME := k3s-ansible-runner
# Загружаем .env если существует
-include .env
export
# Цвета терминала
CYAN := \033[0;36m
GREEN := \033[0;32m
YELLOW := \033[1;33m
RED := \033[0;31m
BOLD := \033[1m
NC := \033[0m
# ── Базовая команда запуска контейнера ────────────────────────────────────────
# Molecule запускается тоже из контейнера — монтируем Docker socket для DinD
DOCKER_RUN_MOLECULE := docker run --rm -it \
--name $(CONTAINER_NAME)-molecule \
-v $(PWD):/ansible \
-v /var/run/docker.sock:/var/run/docker.sock \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_NO_LOG=0 \
$(IMAGE_NAME)
DOCKER_RUN := docker run --rm -it \
--name $(CONTAINER_NAME) \
--network host \
-v $(PWD):/ansible \
-v $(or $(SSH_KEY_PATH),$(HOME)/.ssh):/root/.ssh:ro \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
-e ANSIBLE_VERBOSITY="$(ANSIBLE_VERBOSITY)" \
-e ANSIBLE_TAGS="$(ANSIBLE_TAGS)" \
-e ANSIBLE_SKIP_TAGS="$(ANSIBLE_SKIP_TAGS)" \
-e EXTRA_VARS="$(EXTRA_VARS)" \
-e VERSION="$(VERSION)" \
-e ANSIBLE_FORCE_COLOR=1 \
$(IMAGE_NAME)
.PHONY: help setup build rebuild \
bootstrap k8s-user mdadm k3s-certs chrony \
install install-full install-k3s install-cni install-kubevip \
addon-ingress-nginx addon-cert-manager addon-nfs-server addon-csi-nfs addon-nfs \
addon-istio addon-prometheus-stack addon-metrics-server \
addon-argocd addon-longhorn addon-kubernetes-dashboard \
add-node remove-node \
add-etcd-node remove-etcd-node \
etcd-backup etcd-restore etcd-list-snapshots \
upgrade uninstall health verify ping \
shell lint check \
molecule-k3s molecule-prometheus molecule-istio molecule-all molecule-lint \
vault-create vault-edit vault-view vault-encrypt-string \
vault-bootstrap-create vault-bootstrap-edit \
clean clean-all \
_check_env _check_image
# ── DEFAULT ───────────────────────────────────────────────────────────────────
.DEFAULT_GOAL := help
help: ## Показать эту справку
@echo ""
@printf "$(CYAN)$(BOLD)K3S Ansible Stack — управление через Docker$(NC)\n"
@printf "$(CYAN)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$(NC)\n"
@echo ""
@printf "$(BOLD)Первый запуск:$(NC)\n"
@echo " 1. make setup — создать .env из шаблона"
@echo " 2. Отредактируй .env и inventory/hosts.ini"
@echo " 3. make build — собрать Docker образ"
@echo " 4. make vault-create — создать vault с K3S токеном"
@echo " 5. make vault-bootstrap-create NODE=... — создать vault с паролями нод"
@echo " 6. make bootstrap — создать пользователя + задеплоить SSH ключ"
@echo " 7. make ping — проверить SSH"
@echo " 8. make install — развернуть полный стек"
@echo ""
@printf "$(BOLD)Все команды:$(NC)\n"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| grep -v '^_' \
| awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-26s$(NC) %s\n", $$1, $$2}'
@echo ""
@printf "$(BOLD)Переменные (передаются в командной строке):$(NC)\n"
@printf " $(CYAN)VERSION$(NC)=v1.30.0+k3s1 версия K3S для upgrade\n"
@printf " $(CYAN)NODE$(NC)=master04 нода для add-node/remove-node\n"
@printf " $(CYAN)SNAPSHOT$(NC)=k3s-etcd-...db снимок для etcd-restore\n"
@printf " $(CYAN)ETCD_COPY$(NC)=true скопировать backup локально\n"
@printf " $(CYAN)ANSIBLE_VERBOSITY$(NC)=2 уровень debug вывода (0-4)\n"
@printf " $(CYAN)ANSIBLE_TAGS$(NC)=k3s,kube_vip запустить только теги\n"
@echo ""
# ═══════════════════════════════════════════════════════════════════════════════
# НАСТРОЙКА
# ═══════════════════════════════════════════════════════════════════════════════
setup: ## Первоначальная настройка: создать .env из шаблона
@if [ -f .env ]; then \
printf "$(YELLOW)⚠ .env уже существует, пропускаю$(NC)\n"; \
else \
cp .env.example .env; \
printf "$(GREEN)✓ Создан .env$(NC)\n"; \
fi
@echo ""
@printf "$(BOLD)Следующие шаги:$(NC)\n"
@echo " 1. nano .env — задай VAULT_PASSWORD"
@echo " 2. nano inventory/hosts.ini — укажи IP серверов"
@echo " 3. nano group_vars/all/main.yml — задай kube_vip_address и интерфейс"
@echo " 4. make build — собери Docker образ"
@echo " 5. make vault-create — создай vault"
@echo " 6. make ping — проверь SSH"
@echo " 7. make install — разверни стек"
# ═══════════════════════════════════════════════════════════════════════════════
# DOCKER ОБРАЗ
# ═══════════════════════════════════════════════════════════════════════════════
build: ## Собрать Docker образ ansible-runner
@printf "$(CYAN)Сборка образа $(IMAGE_NAME)...$(NC)\n"
docker build \
--build-arg HELM_VERSION=3.14.4 \
--build-arg KUBECTL_VERSION=v1.29.3 \
-t $(IMAGE_NAME):latest \
-f Dockerfile .
@printf "$(GREEN)✓ Образ $(IMAGE_NAME):latest собран$(NC)\n"
rebuild: ## Пересобрать образ без кэша
@printf "$(CYAN)Пересборка без кэша...$(NC)\n"
docker build --no-cache \
--build-arg HELM_VERSION=3.14.4 \
--build-arg KUBECTL_VERSION=v1.29.3 \
-t $(IMAGE_NAME):latest \
-f Dockerfile .
@printf "$(GREEN)✓ Готово$(NC)\n"
# ═══════════════════════════════════════════════════════════════════════════════
# ПРОВЕРКИ
# ═══════════════════════════════════════════════════════════════════════════════
ping: _check_env _check_image ## Проверить SSH доступность всех нод
@printf "$(CYAN)Проверка SSH...$(NC)\n"
$(DOCKER_RUN) ping
check: _check_env _check_image ## Dry-run: проверить плейбук без изменений
@printf "$(CYAN)Dry-run...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/site.yml --check --diff
lint: _check_image ## Проверить синтаксис всех плейбуков
@printf "$(CYAN)Проверка синтаксиса...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/site.yml --syntax-check
@printf "$(GREEN)✓ Синтаксис корректен$(NC)\n"
# ═══════════════════════════════════════════════════════════════════════════════
# УСТАНОВКА
# ═══════════════════════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════════════════════
# BOOTSTRAP — первичная настройка нод (создание пользователя + SSH ключ)
# ═══════════════════════════════════════════════════════════════════════════════
bootstrap: _check_env _check_image ## Первый запуск: создать пользователя и задеплоить SSH ключ на все ноды
@printf "$(CYAN)$(BOLD)Bootstrap нод (пользователь + SSH ключ)...$(NC)\n"
@printf "$(YELLOW)Нужны: host_vars/<node>/vault.yml с bootstrap_user и bootstrap_password$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/bootstrap.yml \
$(if $(NODE),-e "node_to_bootstrap=$(NODE)",)
vault-bootstrap-create: _check_image ## Создать vault с bootstrap credentials для ноды (NODE=master01)
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make vault-bootstrap-create NODE=master01$(NC)\n"; \
exit 1; \
fi
@if [ ! -f "host_vars/$(NODE)/vault.yml.example" ]; then \
printf "$(RED)Не найден host_vars/$(NODE)/vault.yml.example$(NC)\n"; \
exit 1; \
fi
@cp host_vars/$(NODE)/vault.yml.example host_vars/$(NODE)/vault.yml
docker run --rm -it \
-v $(PWD):/ansible \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
$(IMAGE_NAME) \
ansible vault encrypt host_vars/$(NODE)/vault.yml
@printf "$(GREEN)✓ Vault host_vars/$(NODE)/vault.yml создан$(NC)\n"
vault-bootstrap-edit: _check_image ## Редактировать bootstrap vault ноды (NODE=master01)
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make vault-bootstrap-edit NODE=master01$(NC)\n"; \
exit 1; \
fi
docker run --rm -it \
-v $(PWD):/ansible \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
$(IMAGE_NAME) \
ansible vault edit host_vars/$(NODE)/vault.yml
k8s-user: _check_env _check_image ## Создать k8s пользователя + разложить SSH ключи на все ноды (cluster + lab_hosts)
@printf "$(CYAN)$(BOLD)Настройка k8s пользователя и SSH ключей...$(NC)\n"
@printf "$(YELLOW)Нужны: host_vars/<node>/vault.yml с bootstrap_user и bootstrap_password для lab_hosts$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/k8s-user.yml \
$(if $(NODE),-e "node_to_limit=$(NODE)" --limit $(NODE),)
mdadm: _check_env _check_image ## Найти RAID массив и смонтировать в /storage (mdadm_enabled: true)
@printf "$(CYAN)Настройка mdadm RAID...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/mdadm.yml \
$(if $(NODE),--limit $(NODE),)
chrony: _check_env _check_image ## Установить и настроить chrony (синхронизация времени + часовой пояс)
@printf "$(CYAN)Настройка chrony (timezone: $(or $(TZ),из group_vars))...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/site.yml --tags chrony \
$(if $(TZ),-e chrony_timezone=$(TZ),) \
$(if $(NODE),--limit $(NODE),)
k3s-certs: _check_env _check_image ## Установить systemd таймер автоматической ротации сертификатов K3S
@printf "$(CYAN)Настройка автоматической ротации сертификатов K3S...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/k3s-certs.yml \
$(if $(NODE),--limit $(NODE),)
install: _check_env _check_image ## Развернуть core кластер (K3S + kube-vip + сертификаты)
@printf "$(CYAN)$(BOLD)Разворачиваю K3S core кластер...$(NC)\n"
$(DOCKER_RUN) install
install-full: _check_env _check_image ## Полный стек: core + аддоны по флагам из group_vars/all/addons.yml
@printf "$(CYAN)$(BOLD)Полный стек: core + аддоны из addons.yml...$(NC)\n"
$(DOCKER_RUN) install
$(DOCKER_RUN) install-addons
install-k3s: _check_env _check_image ## Установить только K3S кластер
@printf "$(CYAN)Устанавливаю K3S...$(NC)\n"
$(DOCKER_RUN) install-k3s
install-cni: _check_env _check_image ## Установить CNI плагин (задай K3S_CNI=calico|cilium)
@printf "$(CYAN)Устанавливаю CNI ($(or $(K3S_CNI),flannel))...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/site.yml --tags cni $(if $(K3S_CNI),-e k3s_cni=$(K3S_CNI),)
install-kubevip: _check_env _check_image ## Установить только kube-vip
@printf "$(CYAN)Устанавливаю kube-vip...$(NC)\n"
$(DOCKER_RUN) install-kubevip
install-addons: _check_env _check_image ## Установить аддоны по флагам из group_vars/all/addons.yml
@printf "$(CYAN)Устанавливаю аддоны по addons.yml...$(NC)\n"
$(DOCKER_RUN) install-addons
install-etcd: _check_env _check_image ## Развернуть внешний etcd кластер (k3s_etcd_type: external)
@printf "$(CYAN)Развёртываю внешний etcd кластер...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/site.yml --tags etcd $(ARGS)
# ═══════════════════════════════════════════════════════════════════════════════
# АДДОНЫ — дополнительные компоненты кластера (addons/<name>/playbook.yml)
# Кастомизация: make addon-<name> ARGS="-e var=value"
# Добавить новый аддон: создай addons/<name>/playbook.yml + addons/<name>/role/
# ═══════════════════════════════════════════════════════════════════════════════
# ── Сетевые и хранилище ───────────────────────────────────────────────────────
addon-nfs-server: _check_env _check_image ## Установить NFS сервер (запускается на группе nfs_server)
@printf "$(CYAN)Устанавливаю NFS сервер...$(NC)\n"
$(DOCKER_RUN) addon nfs-server $(ARGS)
addon-csi-nfs: _check_env _check_image ## Установить CSI NFS Driver + StorageClass
@printf "$(CYAN)Устанавливаю CSI NFS Driver...$(NC)\n"
$(DOCKER_RUN) addon csi-nfs $(ARGS)
addon-nfs: _check_env _check_image ## Установить NFS сервер + CSI Driver (комплект)
@printf "$(CYAN)$(BOLD)Устанавливаю NFS сервер + CSI Driver...$(NC)\n"
$(DOCKER_RUN) addon nfs-server $(ARGS)
$(DOCKER_RUN) addon csi-nfs $(ARGS)
addon-ingress-nginx: _check_env _check_image ## Установить ingress-nginx — Ingress controller
@printf "$(CYAN)Устанавливаю ingress-nginx...$(NC)\n"
$(DOCKER_RUN) addon ingress-nginx $(ARGS)
# ── TLS и безопасность ────────────────────────────────────────────────────────
addon-cert-manager: _check_env _check_image ## Установить cert-manager — TLS сертификаты (Let's Encrypt / self-signed)
@printf "$(CYAN)Устанавливаю cert-manager...$(NC)\n"
$(DOCKER_RUN) addon cert-manager $(ARGS)
# ── Мониторинг ────────────────────────────────────────────────────────────────
addon-prometheus-stack: _check_env _check_image ## Установить Prometheus + Grafana + Alertmanager
@printf "$(CYAN)Устанавливаю kube-prometheus-stack...$(NC)\n"
$(DOCKER_RUN) addon prometheus-stack $(ARGS)
addon-metrics-server: _check_env _check_image ## Установить metrics-server (kubectl top nodes/pods, HPA)
@printf "$(CYAN)Устанавливаю metrics-server...$(NC)\n"
$(DOCKER_RUN) addon metrics-server $(ARGS)
# ── Service Mesh ──────────────────────────────────────────────────────────────
addon-istio: _check_env _check_image ## Установить Istio + Kiali (ARGS="-e kiali_enabled=true" для Kiali)
@printf "$(CYAN)Устанавливаю Istio...$(NC)\n"
$(DOCKER_RUN) addon istio $(ARGS)
# ── GitOps и прочее ───────────────────────────────────────────────────────────
addon-argocd: _check_env _check_image ## Установить ArgoCD — GitOps CD (ARGS="-e argocd_ingress_enabled=true -e argocd_ingress_host=argocd.example.com")
@printf "$(CYAN)Устанавливаю ArgoCD...$(NC)\n"
$(DOCKER_RUN) addon argocd $(ARGS)
addon-longhorn: _check_env _check_image ## Установить Longhorn — distributed block storage (ARGS="-e longhorn_default_replica_count=1" для single-node)
@printf "$(CYAN)Устанавливаю Longhorn...$(NC)\n"
$(DOCKER_RUN) addon longhorn $(ARGS)
addon-kubernetes-dashboard: _check_env _check_image ## Установить Kubernetes Dashboard — веб UI кластера
@printf "$(CYAN)Устанавливаю Kubernetes Dashboard...$(NC)\n"
$(DOCKER_RUN) addon kubernetes-dashboard $(ARGS)
# Generic цель — любой аддон из addons/<name>/playbook.yml
addon-%: _check_env _check_image
@if [ ! -f "addons/$*/playbook.yml" ]; then \
printf "$(RED)✗ Аддон '$*' не найден. Ожидается: addons/$*/playbook.yml$(NC)\n"; \
printf "$(YELLOW) Доступные аддоны:$(NC) "; \
ls addons/ 2>/dev/null | tr '\n' ' '; echo ""; \
exit 1; \
fi
@printf "$(CYAN)Устанавливаю аддон $*...$(NC)\n"
$(DOCKER_RUN) addon $* $(ARGS)
# ═══════════════════════════════════════════════════════════════════════════════
# МАСШТАБИРОВАНИЕ КЛАСТЕРА
# ═══════════════════════════════════════════════════════════════════════════════
add-node: _check_env _check_image ## Добавить ноду: make add-node NODE=master04
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make add-node NODE=<nodename>$(NC)\n"; \
exit 1; \
fi
@printf "$(CYAN)Добавляю ноду $(NODE) в кластер...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/add-node.yml -e "node_to_add=$(NODE)"
remove-node: _check_env _check_image ## Удалить ноду: make remove-node NODE=worker04
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make remove-node NODE=<nodename>$(NC)\n"; \
exit 1; \
fi
@printf "$(RED)$(BOLD)Удаление ноды $(NODE) из кластера...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/remove-node.yml -e "node_to_remove=$(NODE)"
add-etcd-node: _check_env _check_image ## Добавить etcd ноду: make add-etcd-node NODE=etcd04
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make add-etcd-node NODE=<nodename>$(NC)\n"; \
printf "$(YELLOW) Нода должна быть в [etcd_nodes] в inventory$(NC)\n"; \
exit 1; \
fi
@printf "$(CYAN)Добавляю etcd ноду $(NODE)...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/add-etcd-node.yml -e "node_to_add=$(NODE)" $(ARGS)
remove-etcd-node: _check_env _check_image ## Удалить etcd ноду: make remove-etcd-node NODE=etcd04
@if [ -z "$(NODE)" ]; then \
printf "$(RED)✗ Укажи ноду: make remove-etcd-node NODE=<nodename>$(NC)\n"; \
exit 1; \
fi
@printf "$(RED)$(BOLD)Удаление etcd ноды $(NODE) из кластера...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/remove-etcd-node.yml -e "node_to_remove=$(NODE)" $(ARGS)
# ═══════════════════════════════════════════════════════════════════════════════
# РЕЗЕРВНОЕ КОПИРОВАНИЕ ETCD
# ═══════════════════════════════════════════════════════════════════════════════
etcd-backup: _check_env _check_image ## Создать снимок etcd (make etcd-backup [SNAPSHOT=name] [ETCD_COPY=true])
@printf "$(CYAN)Создаю снимок etcd...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/etcd-backup.yml \
$(if $(SNAPSHOT),-e etcd_backup_name=$(SNAPSHOT),) \
$(if $(ETCD_COPY),-e etcd_backup_copy_to_local=$(ETCD_COPY),)
etcd-restore: _check_env _check_image ## Восстановить etcd: make etcd-restore SNAPSHOT=k3s-etcd-20250101.db
@if [ -z "$(SNAPSHOT)" ]; then \
printf "$(RED)✗ Укажи снимок: make etcd-restore SNAPSHOT=<filename>$(NC)\n"; \
printf "$(YELLOW) Список снимков: make etcd-list-snapshots$(NC)\n"; \
exit 1; \
fi
@printf "$(RED)$(BOLD)ВНИМАНИЕ: восстановление etcd перезапишет данные кластера!$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/etcd-restore.yml \
-e "etcd_restore_snapshot=$(SNAPSHOT)" \
$(if $(FORCE),-e etcd_restore_force=true,)
etcd-list-snapshots: _check_env _check_image ## Показать доступные снимки etcd
@printf "$(CYAN)Список снимков etcd...$(NC)\n"
$(DOCKER_RUN) ansible-playbook playbooks/etcd-restore.yml --tags list
# ═══════════════════════════════════════════════════════════════════════════════
# ОБНОВЛЕНИЕ
# ═══════════════════════════════════════════════════════════════════════════════
upgrade: _check_env _check_image ## Обновить K3S (make upgrade VERSION=v1.30.0+k3s1)
@if [ -z "$(VERSION)" ]; then \
printf "$(RED)✗ Укажи версию: make upgrade VERSION=v1.30.0+k3s1$(NC)\n"; \
exit 1; \
fi
@printf "$(CYAN)Обновляю K3S до $(VERSION)...$(NC)\n"
$(DOCKER_RUN) upgrade
# ═══════════════════════════════════════════════════════════════════════════════
# ДИАГНОСТИКА
# ═══════════════════════════════════════════════════════════════════════════════
health: _check_env _check_image ## Диагностика кластера (сервисы, поды, диск, память)
@printf "$(CYAN)Диагностика...$(NC)\n"
$(DOCKER_RUN) health
verify: _check_env _check_image ## Проверить весь стек (nodes/pods/svc/sc/ingress)
@printf "$(CYAN)Проверка стека...$(NC)\n"
$(DOCKER_RUN) verify
# ═══════════════════════════════════════════════════════════════════════════════
# УДАЛЕНИЕ
# ═══════════════════════════════════════════════════════════════════════════════
uninstall: _check_env _check_image ## ВНИМАНИЕ: удалить весь стек и данные
@printf "$(RED)$(BOLD)ВНИМАНИЕ: Удаление всего стека — данные будут потеряны!$(NC)\n"
@printf "$(YELLOW)Введи 'yes' для подтверждения: $(NC)"; \
read CONFIRM && [ "$$CONFIRM" = "yes" ] || (printf "Отменено.\n" && exit 1)
$(DOCKER_RUN) uninstall
# ═══════════════════════════════════════════════════════════════════════════════
# ANSIBLE VAULT
# ═══════════════════════════════════════════════════════════════════════════════
vault-create: _check_image ## Создать зашифрованный vault (group_vars/all/vault.yml)
@printf "$(CYAN)Создание vault...$(NC)\n"
docker run --rm -it \
-v $(PWD):/ansible \
$(IMAGE_NAME) \
ansible vault create group_vars/all/vault.yml
@printf "$(GREEN)✓ Vault создан$(NC)\n"
vault-edit: _check_image ## Редактировать vault
docker run --rm -it \
-v $(PWD):/ansible \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
$(IMAGE_NAME) \
ansible vault edit group_vars/all/vault.yml
vault-view: _check_image ## Просмотреть vault (расшифрованный вывод)
docker run --rm -it \
-v $(PWD):/ansible \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
$(IMAGE_NAME) \
ansible vault view group_vars/all/vault.yml
vault-encrypt-string: _check_image ## Зашифровать строку: make vault-encrypt-string STR=... NAME=...
@if [ -z "$(STR)" ]; then \
printf "$(RED)✗ Нужна строка: make vault-encrypt-string STR=мой-токен NAME=vault_k3s_token$(NC)\n"; \
exit 1; \
fi
docker run --rm -it \
-v $(PWD):/ansible \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
$(IMAGE_NAME) \
ansible vault encrypt_string '$(STR)' --name '$(or $(NAME),encrypted_var)'
# ═══════════════════════════════════════════════════════════════════════════════
# MOLECULE — ТЕСТИРОВАНИЕ РОЛЕЙ
# Требования: pip install -r requirements-python.txt (molecule, molecule-plugins[docker])
# ═══════════════════════════════════════════════════════════════════════════════
molecule-k3s: _check_image ## Тест роли k3s — 3 контейнера (Ubuntu+Debian), ~8-12 мин
@printf "$(CYAN)Тестирую роль k3s (3 ноды: master01, worker01, rpi01)...$(NC)\n"
$(DOCKER_RUN_MOLECULE) molecule k3s
@printf "$(GREEN)✓ k3s role: OK$(NC)\n"
molecule-prometheus: _check_image ## Тест роли prometheus-stack (шаблоны + PVC), ~2-3 мин
@printf "$(CYAN)Тестирую роль prometheus-stack...$(NC)\n"
$(DOCKER_RUN_MOLECULE) molecule prometheus-stack
@printf "$(GREEN)✓ prometheus-stack role: OK$(NC)\n"
molecule-istio: _check_image ## Тест роли istio + kiali (шаблоны), ~2-3 мин
@printf "$(CYAN)Тестирую роль istio...$(NC)\n"
$(DOCKER_RUN_MOLECULE) molecule istio
@printf "$(GREEN)✓ istio role: OK$(NC)\n"
molecule-all: _check_image ## Запустить все Molecule тесты последовательно (~15-20 мин)
@printf "$(CYAN)$(BOLD)Запуск всех Molecule тестов...$(NC)\n"
$(MAKE) molecule-k3s
$(MAKE) molecule-prometheus
$(MAKE) molecule-istio
@printf "$(GREEN)$(BOLD)Все тесты прошли успешно$(NC)\n"
molecule-lint: _check_image ## Линтинг (yamllint + ansible-lint) в контейнере, ~30 сек
@printf "$(CYAN)Запуск линтинга...$(NC)\n"
$(DOCKER_RUN_MOLECULE) molecule-lint
@printf "$(GREEN)✓ Линтинг прошёл$(NC)\n"
# ═══════════════════════════════════════════════════════════════════════════════
# ИНТЕРАКТИВНЫЙ SHELL
# ═══════════════════════════════════════════════════════════════════════════════
shell: _check_image ## Запустить интерактивный bash внутри контейнера
@printf "$(CYAN)Запуск shell (exit для выхода)...$(NC)\n"
docker run --rm -it \
--name $(CONTAINER_NAME)-shell \
--network host \
-v $(PWD):/ansible \
-v $(or $(SSH_KEY_PATH),$(HOME)/.ssh):/root/.ssh:ro \
-e VAULT_PASSWORD="$(VAULT_PASSWORD)" \
-e ANSIBLE_FORCE_COLOR=1 \
$(IMAGE_NAME) shell
# ═══════════════════════════════════════════════════════════════════════════════
# ОЧИСТКА
# ═══════════════════════════════════════════════════════════════════════════════
clean: ## Удалить Docker образ
@printf "$(YELLOW)Удаляю образ $(IMAGE_NAME)...$(NC)\n"
docker rmi $(IMAGE_NAME):latest 2>/dev/null || printf "$(YELLOW)Образ не найден$(NC)\n"
clean-all: clean ## Удалить образ + kubeconfig + кэш Docker
rm -f kubeconfig
docker system prune -f
@printf "$(GREEN)✓ Очистка завершена$(NC)\n"
# ═══════════════════════════════════════════════════════════════════════════════
# ВНУТРЕННИЕ
# ═══════════════════════════════════════════════════════════════════════════════
_check_env:
@if [ ! -f .env ]; then \
printf "$(RED)✗ Файл .env не найден! Запусти: make setup$(NC)\n"; \
exit 1; \
fi
_check_image:
@if ! docker image inspect $(IMAGE_NAME):latest > /dev/null 2>&1; then \
printf "$(YELLOW)⚠ Образ не найден, собираю...$(NC)\n"; \
$(MAKE) build; \
fi