Files
K3S/Makefile
Sergey Antropoff b8e15fae45 feat: добавить аддоны Loki, Promtail, Tempo, Pushgateway
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
2026-04-25 11:37:23 +03:00

575 lines
36 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 \
addon-postgresql addon-mysql addon-databasus \
addon-minio addon-velero addon-crowdsec \
addon-loki addon-promtail addon-tempo addon-pushgateway \
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)
# ── Базы данных ───────────────────────────────────────────────────────────────
addon-postgresql: _check_env _check_image ## Установить PostgreSQL (Bitnami; ARGS="-e postgresql_storage_size=20Gi")
@printf "$(CYAN)Устанавливаю PostgreSQL...$(NC)\n"
$(DOCKER_RUN) addon postgresql $(ARGS)
addon-mysql: _check_env _check_image ## Установить MySQL (Bitnami; ARGS="-e mysql_storage_size=20Gi")
@printf "$(CYAN)Устанавливаю MySQL...$(NC)\n"
$(DOCKER_RUN) addon mysql $(ARGS)
addon-databasus: _check_env _check_image ## Установить Databasus — управление резервными копиями БД (ARGS="-e databasus_ingress_host=backup.example.com")
@printf "$(CYAN)Устанавливаю Databasus...$(NC)\n"
$(DOCKER_RUN) addon databasus $(ARGS)
# ── Объектное хранилище и backup ──────────────────────────────────────────────
addon-minio: _check_env _check_image ## Установить MinIO — S3 объектное хранилище (ARGS="-e minio_storage_size=20Gi")
@printf "$(CYAN)Устанавливаю MinIO...$(NC)\n"
$(DOCKER_RUN) addon minio $(ARGS)
addon-velero: _check_env _check_image ## Установить Velero — backup кластера + PVC через S3/MinIO
@printf "$(CYAN)Устанавливаю Velero...$(NC)\n"
$(DOCKER_RUN) addon velero $(ARGS)
# ── Безопасность ──────────────────────────────────────────────────────────────
addon-crowdsec: _check_env _check_image ## Установить CrowdSec — обнаружение вторжений (ARGS="-e crowdsec_nginx_bouncer_enabled=true")
@printf "$(CYAN)Устанавливаю CrowdSec...$(NC)\n"
$(DOCKER_RUN) addon crowdsec $(ARGS)
# ── Observability (logging / tracing / metrics) ───────────────────────────────
addon-loki: _check_env _check_image ## Установить Loki — агрегация логов (ARGS="-e loki_storage_type=s3" для MinIO)
@printf "$(CYAN)Устанавливаю Loki...$(NC)\n"
$(DOCKER_RUN) addon loki $(ARGS)
addon-promtail: _check_env _check_image ## Установить Promtail — агент сбора логов → Loki
@printf "$(CYAN)Устанавливаю Promtail...$(NC)\n"
$(DOCKER_RUN) addon promtail $(ARGS)
addon-tempo: _check_env _check_image ## Установить Tempo — distributed tracing (OTLP/Jaeger/Zipkin)
@printf "$(CYAN)Устанавливаю Tempo...$(NC)\n"
$(DOCKER_RUN) addon tempo $(ARGS)
addon-pushgateway: _check_env _check_image ## Установить Prometheus Pushgateway — метрики batch-задач и скриптов
@printf "$(CYAN)Устанавливаю Pushgateway...$(NC)\n"
$(DOCKER_RUN) addon pushgateway $(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