Compare commits
10 Commits
8071fba25f
...
d6bc3f1f31
| Author | SHA1 | Date | |
|---|---|---|---|
| d6bc3f1f31 | |||
| a875a874e9 | |||
| e6287769d6 | |||
| 51c76fb859 | |||
| dc255d006a | |||
| 26a09cd637 | |||
| df97e9d3d4 | |||
| 09ca55539f | |||
| 9c55c8f615 | |||
| f2a0f46813 |
@@ -4,4 +4,8 @@ skip_list:
|
||||
- yaml[truthy]
|
||||
- yaml[line-length]
|
||||
- var-naming[no-role-prefix]
|
||||
- 'ignore-errors'
|
||||
- 'ignore-errors'
|
||||
|
||||
exclude_paths:
|
||||
- molecule/universal/
|
||||
- files/playbooks/
|
||||
924
Makefile
924
Makefile
@@ -1,271 +1,713 @@
|
||||
# Глобальные переменные
|
||||
IMAGE ?= ansible
|
||||
TAG ?= 0.1
|
||||
REGISTRY ?= inecs/ansible
|
||||
# По умолчанию используем docker. Для локальной разработки используйте docker-compose
|
||||
RUN_MODE ?= docker
|
||||
# =============================================================================
|
||||
# Ansible Template - Универсальная лаборатория для тестирования Ansible ролей
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
# =============================================================================
|
||||
|
||||
# Определение команды RUN в зависимости от RUN_MODE
|
||||
ifeq ($(RUN_MODE), docker-compose)
|
||||
RUN = docker compose run --rm $(IMAGE)
|
||||
else ifeq ($(RUN_MODE), docker)
|
||||
RUN = docker run -it --rm \
|
||||
--name $(IMAGE) \
|
||||
-v $(PWD):/ansible \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v ~/.ssh/id_rsa:/root/.ssh/id_rsa:ro \
|
||||
-e ANSIBLE_VAULT_PASSWORD_FILE=/ansible/vault-password.txt \
|
||||
--privileged \
|
||||
--workdir /ansible \
|
||||
$(REGISTRY)/$(IMAGE)
|
||||
else
|
||||
$(error Invalid RUN_MODE. Use "docker-compose" or "docker")
|
||||
endif
|
||||
# =============================================================================
|
||||
# ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
|
||||
# =============================================================================
|
||||
|
||||
view create edit show delete test lint deploy new init build rebuild prune release images push pull shell:
|
||||
@true
|
||||
# Основные переменные
|
||||
PROJECT_NAME ?= ansible-template
|
||||
VERSION ?= 0.1.0
|
||||
AUTHOR ?= "Сергей Антропов"
|
||||
SITE ?= "https://devops.org.ru"
|
||||
|
||||
####################################################################################################
|
||||
# Инициализация новой роли
|
||||
####################################################################################################
|
||||
init:
|
||||
@echo "Шаг 1: Создание Docker-образа..."
|
||||
@make docker build
|
||||
@echo "Шаг 2: Создание Docker-образов для запуска Molecule..."
|
||||
@make docker images
|
||||
@echo "Шаг 3: Создание нового vault-файла с паролем..."
|
||||
@read -p "Введите пароль для vault: " VAULT_PASSWORD; \
|
||||
echo "$$VAULT_PASSWORD" > vault-password.txt; \
|
||||
make vault create
|
||||
@echo "Шаг 4: Создание нового брэнча в гите..."
|
||||
@make git new
|
||||
@echo "Шаг 5: Создание новой роли..."
|
||||
@make role new
|
||||
# Docker переменные
|
||||
DOCKER_IMAGE ?= quay.io/ansible/creator-ee:latest
|
||||
DOCKER_COMPOSE ?= docker compose
|
||||
DOCKER_NETWORK ?= labnet
|
||||
|
||||
####################################################################################################
|
||||
# Управление контейнерами с помощью docker compose или docker run
|
||||
####################################################################################################
|
||||
docker:
|
||||
# Molecule переменные
|
||||
SCENARIO ?= universal
|
||||
LAB_SPEC ?= molecule/presets/minimal.yml
|
||||
MOLECULE_EPHEMERAL_DIRECTORY ?= /tmp/molecule
|
||||
|
||||
# Kubernetes переменные
|
||||
KUBE_CONTEXT ?= kind-lab
|
||||
ISTIO_VERSION ?= 1.22.1
|
||||
KIND_VERSION ?= v0.23.0
|
||||
|
||||
# Переменные окружения
|
||||
ENV_FILE ?= .env
|
||||
ROLES_DIR ?= ./roles
|
||||
VAULT_PASSWORD_FILE ?= vault/.vault
|
||||
|
||||
# Цвета для вывода
|
||||
RED := \033[0;31m
|
||||
GREEN := \033[0;32m
|
||||
YELLOW := \033[0;33m
|
||||
BLUE := \033[0;34m
|
||||
PURPLE := \033[0;35m
|
||||
CYAN := \033[0;36m
|
||||
WHITE := \033[0;37m
|
||||
RESET := \033[0m
|
||||
|
||||
# =============================================================================
|
||||
# ОСНОВНЫЕ КОМАНДЫ
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: help
|
||||
help: ## Показать справку по всем командам
|
||||
@echo "$(CYAN)Ansible Template - Универсальная лаборатория$(RESET)"
|
||||
@echo "$(YELLOW)Автор: $(AUTHOR)$(RESET)"
|
||||
@echo "$(YELLOW)Сайт: $(SITE)$(RESET)"
|
||||
@echo ""
|
||||
@echo "$(GREEN)Основные команды:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST) | grep -E "^(init|setup|clean|help)"
|
||||
@echo ""
|
||||
@echo "$(GREEN)Лаборатория:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^lab-[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
@echo ""
|
||||
@echo "$(GREEN)Kubernetes:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^kube-[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
@echo ""
|
||||
@echo "$(GREEN)Отчеты и мониторинг:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^(report|kubeconfigs|open-report|full-test):.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
@echo ""
|
||||
@echo "$(GREEN)Пресеты:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^preset-[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
@echo ""
|
||||
@echo "$(GREEN)Роли:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^role-[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
@echo ""
|
||||
@echo "$(GREEN)Утилиты:$(RESET)"
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST) | grep -E "^(lint|env|vault|git|docker|report|snapshot|cleanup|chaos|check-secrets|idempotence)"
|
||||
|
||||
# =============================================================================
|
||||
# ИНИЦИАЛИЗАЦИЯ И НАСТРОЙКА
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: init
|
||||
init: setup-env setup-vault setup-roles setup-precommit ## Полная инициализация проекта
|
||||
@echo "$(GREEN)✅ Проект успешно инициализирован!$(RESET)"
|
||||
@echo "$(YELLOW)📖 Документация: $(SITE)$(RESET)"
|
||||
@echo "$(YELLOW)🚀 Быстрый старт: make lab up$(RESET)"
|
||||
|
||||
.PHONY: setup-env
|
||||
setup-env: ## Создать .env файл с настройками
|
||||
@if [ ! -f $(ENV_FILE) ]; then \
|
||||
echo "$(YELLOW)Создание .env файла...$(RESET)"; \
|
||||
echo "# Ansible Template Environment" > $(ENV_FILE); \
|
||||
echo "PROJECT_NAME=$(PROJECT_NAME)" >> $(ENV_FILE); \
|
||||
echo "VERSION=$(VERSION)" >> $(ENV_FILE); \
|
||||
echo "AUTHOR=$(AUTHOR)" >> $(ENV_FILE); \
|
||||
echo "SITE=$(SITE)" >> $(ENV_FILE); \
|
||||
echo "" >> $(ENV_FILE); \
|
||||
echo "# Docker settings" >> $(ENV_FILE); \
|
||||
echo "DOCKER_IMAGE=$(DOCKER_IMAGE)" >> $(ENV_FILE); \
|
||||
echo "DOCKER_NETWORK=$(DOCKER_NETWORK)" >> $(ENV_FILE); \
|
||||
echo "" >> $(ENV_FILE); \
|
||||
echo "# Molecule settings" >> $(ENV_FILE); \
|
||||
echo "SCENARIO=$(SCENARIO)" >> $(ENV_FILE); \
|
||||
echo "LAB_SPEC=$(LAB_SPEC)" >> $(ENV_FILE); \
|
||||
echo "" >> $(ENV_FILE); \
|
||||
echo "# Kubernetes settings" >> $(ENV_FILE); \
|
||||
echo "KUBE_CONTEXT=$(KUBE_CONTEXT)" >> $(ENV_FILE); \
|
||||
echo "ISTIO_VERSION=$(ISTIO_VERSION)" >> $(ENV_FILE); \
|
||||
echo "KIND_VERSION=$(KIND_VERSION)" >> $(ENV_FILE); \
|
||||
echo "" >> $(ENV_FILE); \
|
||||
echo "# Paths" >> $(ENV_FILE); \
|
||||
echo "ROLES_DIR=$(ROLES_DIR)" >> $(ENV_FILE); \
|
||||
echo "VAULT_PASSWORD_FILE=$(VAULT_PASSWORD_FILE)" >> $(ENV_FILE); \
|
||||
echo "$(GREEN)✅ .env файл создан$(RESET)"; \
|
||||
else \
|
||||
echo "$(YELLOW)⚠️ .env файл уже существует$(RESET)"; \
|
||||
fi
|
||||
|
||||
.PHONY: setup-vault
|
||||
setup-vault: ## Создать vault-password.txt
|
||||
@if [ ! -f $(VAULT_PASSWORD_FILE) ]; then \
|
||||
echo "$(YELLOW)Создание vault-password.txt...$(RESET)"; \
|
||||
echo "ansible-vault-password" > $(VAULT_PASSWORD_FILE); \
|
||||
echo "$(GREEN)✅ vault-password.txt создан$(RESET)"; \
|
||||
else \
|
||||
echo "$(YELLOW)⚠️ vault-password.txt уже существует$(RESET)"; \
|
||||
fi
|
||||
|
||||
.PHONY: setup-roles
|
||||
setup-roles: ## Создать директорию для ролей
|
||||
@mkdir -p $(ROLES_DIR)
|
||||
@echo "$(GREEN)✅ Директория ролей создана: $(ROLES_DIR)$(RESET)"
|
||||
|
||||
.PHONY: setup-precommit
|
||||
setup-precommit: ## Установить pre-commit хуки
|
||||
@if command -v pre-commit >/dev/null 2>&1; then \
|
||||
pre-commit install; \
|
||||
echo "$(GREEN)✅ Pre-commit хуки установлены$(RESET)"; \
|
||||
else \
|
||||
echo "$(YELLOW)⚠️ pre-commit не установлен. Установите: pip install pre-commit$(RESET)"; \
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ ЛАБОРАТОРИЕЙ
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: lab
|
||||
lab: ## Управление лабораторией (up|down|sh|test|create|converge|verify|destroy|reset)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
up) \
|
||||
echo "$(GREEN)🚀 Поднимаем контроллер...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) up -d; \
|
||||
echo "$(GREEN)✅ Контроллер запущен$(RESET)";; \
|
||||
down) \
|
||||
echo "$(YELLOW)🛑 Останавливаем контроллер...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) down -v; \
|
||||
echo "$(GREEN)✅ Контроллер остановлен$(RESET)";; \
|
||||
sh) \
|
||||
echo "$(BLUE)🐚 Входим в контроллер...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash;; \
|
||||
test) \
|
||||
echo "$(PURPLE)🧪 Запускаем полный цикл тестирования...$(RESET)"; \
|
||||
$(MAKE) lab up; \
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule test -s $(SCENARIO)'; \
|
||||
echo "$(GREEN)✅ Тестирование завершено$(RESET)";; \
|
||||
create) \
|
||||
echo "$(BLUE)🏗️ Создаем инфраструктуру...$(RESET)"; \
|
||||
$(MAKE) lab up; \
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule create -s $(SCENARIO)'; \
|
||||
echo "$(GREEN)✅ Инфраструктура создана$(RESET)";; \
|
||||
converge) \
|
||||
echo "$(YELLOW)⚙️ Запускаем роли...$(RESET)"; \
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule converge -s $(SCENARIO)'; \
|
||||
echo "$(GREEN)✅ Роли выполнены$(RESET)";; \
|
||||
verify) \
|
||||
echo "$(CYAN)🔍 Проверяем работу лаборатории...$(RESET)"; \
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule verify -s $(SCENARIO)'; \
|
||||
echo "$(GREEN)✅ Проверка завершена$(RESET)";; \
|
||||
destroy) \
|
||||
echo "$(RED)💥 Уничтожаем инфраструктуру...$(RESET)"; \
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule destroy -s $(SCENARIO)'; \
|
||||
echo "$(GREEN)✅ Инфраструктура уничтожена$(RESET)";; \
|
||||
reset) \
|
||||
echo "$(PURPLE)🔄 Полный сброс лаборатории...$(RESET)"; \
|
||||
$(MAKE) lab destroy; \
|
||||
$(MAKE) lab down; \
|
||||
$(MAKE) lab up; \
|
||||
echo "$(GREEN)✅ Лаборатория сброшена$(RESET)";; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: up, down, sh, test, create, converge, verify, destroy, reset$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ KUBERNETES
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: kube
|
||||
kube: ## Управление Kubernetes (sh|cmd|enter|kiali|istio|grafana|prom|pf-stop)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
sh) \
|
||||
echo "$(BLUE)🐚 Входим в контейнер с kubectl...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash;; \
|
||||
cmd) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube cmd CLUSTER=lab CMD=\"get pods -A\"$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(CYAN)🔧 Выполняем kubectl команду...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) $(CMD)';; \
|
||||
enter) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube enter CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)🚪 Входим в кластер...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash -lc '\
|
||||
POD=$$(kubectl --context kind-$(CLUSTER) -n lab-demo get pod -l app=toolbox -o jsonpath="{.items[0].metadata.name}"); \
|
||||
[ -n "$$POD" ] || { echo "toolbox pod not found"; exit 1; }; \
|
||||
kubectl --context kind-$(CLUSTER) -n lab-demo exec -it $$POD -- /bin/sh';; \
|
||||
kiali) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube kiali CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(PURPLE)🔮 Port-forward Kiali...$(RESET)"; \
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/kiali 20001:20001'; \
|
||||
echo "$(GREEN)✅ Kiali: http://localhost:20001$(RESET)";; \
|
||||
istio) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube istio CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(PURPLE)🌐 Port-forward Istio Gateway...$(RESET)"; \
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/istio-ingressgateway 8082:80 8444:443'; \
|
||||
echo "$(GREEN)✅ Istio GW: http://localhost:8082 https://localhost:8444$(RESET)";; \
|
||||
grafana) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube grafana CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)📊 Port-forward Grafana...$(RESET)"; \
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-grafana 3000:80'; \
|
||||
echo "$(GREEN)✅ Grafana: http://localhost:3000 (admin/admin)$(RESET)";; \
|
||||
prom) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube prom CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)📈 Port-forward Prometheus...$(RESET)"; \
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-kube-prometheus-prometheus 9090:9090'; \
|
||||
echo "$(GREEN)✅ Prometheus: http://localhost:9090$(RESET)";; \
|
||||
pf-stop) \
|
||||
echo "$(RED)🛑 Останавливаем все port-forward...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash -lc 'pkill -f "kubectl .* port-forward" || true'; \
|
||||
echo "$(GREEN)✅ Port-forward остановлены$(RESET)";; \
|
||||
kubeconfig) \
|
||||
if [ -z "$(CLUSTER)" ]; then \
|
||||
echo "$(RED)❌ Использование: make kube kubeconfig CLUSTER=lab$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)📋 Получаем kubeconfig для кластера $(CLUSTER)...$(RESET)"; \
|
||||
mkdir -p reports/kubeconfigs; \
|
||||
docker exec ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) config view --raw' > reports/kubeconfigs/kubeconfig-$(CLUSTER).yaml; \
|
||||
echo "$(GREEN)✅ Kubeconfig сохранен: reports/kubeconfigs/kubeconfig-$(CLUSTER).yaml$(RESET)";; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: sh, cmd, enter, kiali, istio, grafana, prom, pf-stop, kubeconfig$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ ПРЕСЕТАМИ
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: preset
|
||||
preset: ## Управление пресетами (list|create|edit|test|copy)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
list) \
|
||||
echo "$(CYAN)📋 Доступные пресеты:$(RESET)"; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)Классические пресеты:$(RESET)"; \
|
||||
echo " minimal.yml - Минимальная лаборатория (1-3 машины)"; \
|
||||
echo " webapp.yml - Веб-приложение (3-5 машин)"; \
|
||||
echo " microservices.yml - Микросервисы (5-8 машин)"; \
|
||||
echo " ha.yml - Высокая доступность (6-10 машин)"; \
|
||||
echo " k8s-cluster.yml - Kubernetes кластер (8-12 машин)"; \
|
||||
echo " cicd.yml - CI/CD пайплайн (10-15 машин)"; \
|
||||
echo " bigdata.yml - Big Data кластер (12-18 машин)"; \
|
||||
echo " servicemesh.yml - Service Mesh (15-20 машин)"; \
|
||||
echo " enterprise.yml - Enterprise (18-20 машин)"; \
|
||||
echo " maximum.yml - Максимальный (20 машин)"; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)Kubernetes пресеты:$(RESET)"; \
|
||||
echo " k8s-single.yml - Kubernetes Single Node"; \
|
||||
echo " k8s-multi.yml - Kubernetes Multi-Cluster"; \
|
||||
echo " k8s-istio-full.yml - Kubernetes + Istio Full Stack"; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)DinD пресеты:$(RESET)"; \
|
||||
echo " dind-simple.yml - DinD Simple"; \
|
||||
echo " dind-swarm.yml - DinD Swarm"; \
|
||||
echo " dind-compose.yml - DinD Compose"; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)DOoD пресеты:$(RESET)"; \
|
||||
echo " dood-simple.yml - DOoD Simple"; \
|
||||
echo " dood-mixed.yml - DOoD Mixed"; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)Смешанные пресеты:$(RESET)"; \
|
||||
echo " mixed-k8s-dind.yml - Mixed Kubernetes + DinD"; \
|
||||
echo " mixed-k8s-dood.yml - Mixed Kubernetes + DOoD"; \
|
||||
echo " mixed-full.yml - Mixed Full Stack";; \
|
||||
create) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make preset create NAME=my-preset$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)📝 Создаем пресет: $(NAME).yml$(RESET)"; \
|
||||
$(MAKE) preset copy SOURCE=minimal.yml TARGET=$(NAME).yml; \
|
||||
echo "$(GREEN)✅ Пресет создан: molecule/presets/$(NAME).yml$(RESET)";; \
|
||||
edit) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make preset edit NAME=my-preset$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)✏️ Редактируем пресет: $(NAME).yml$(RESET)"; \
|
||||
$${EDITOR:-vim} molecule/presets/$(NAME).yml;; \
|
||||
test) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make preset test NAME=my-preset$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(PURPLE)🧪 Тестируем пресет: $(NAME).yml$(RESET)"; \
|
||||
$(MAKE) lab test LAB_SPEC=molecule/presets/$(NAME).yml;; \
|
||||
copy) \
|
||||
if [ -z "$(SOURCE)" ] || [ -z "$(TARGET)" ]; then \
|
||||
echo "$(RED)❌ Использование: make preset copy SOURCE=minimal.yml TARGET=my-preset.yml$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)📋 Копируем пресет: $(SOURCE) -> $(TARGET)$(RESET)"; \
|
||||
cp molecule/presets/$(SOURCE) molecule/presets/$(TARGET); \
|
||||
echo "$(GREEN)✅ Пресет скопирован$(RESET)";; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: list, create, edit, test, copy$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ РОЛЯМИ
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: role
|
||||
role: ## Управление ролями (list|create|edit|test|lint|deploy)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
list) \
|
||||
echo "$(CYAN)📋 Доступные роли:$(RESET)"; \
|
||||
if [ -d "$(ROLES_DIR)" ]; then \
|
||||
ls -la $(ROLES_DIR)/ | grep "^d" | awk '{print " " $$9}' | grep -v "^\.$\|^\.\.$"; \
|
||||
else \
|
||||
echo " $(YELLOW)Директория ролей не найдена$(RESET)"; \
|
||||
fi;; \
|
||||
create) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make role create NAME=my-role$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)📝 Создаем роль: $(NAME)$(RESET)"; \
|
||||
mkdir -p $(ROLES_DIR)/$(NAME)/{tasks,handlers,templates,files,vars,defaults,meta,tests}; \
|
||||
echo "---" > $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "# Основные задачи роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "- name: $(NAME) placeholder" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " debug:" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " msg: \"Роль $(NAME) готова для настройки\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "- name: Install $(NAME) package" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " package:" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " name: \"{{ $(NAME)_package | default('$(NAME)') }}\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " state: present" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "- name: Start $(NAME) service" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " systemd:" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " name: \"{{ $(NAME)_service | default('$(NAME)') }}\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " state: started" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " enabled: true" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo " when: $(NAME)_service is defined" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
|
||||
echo "---" > $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
|
||||
echo "# Переменные по умолчанию для роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
|
||||
echo "$(NAME)_enabled: true" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
|
||||
echo "$(NAME)_package: $(NAME)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
|
||||
echo "$(NAME)_service: $(NAME)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
|
||||
echo "---" > $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo "galaxy_info:" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo " author: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo " description: Роль $(NAME)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo " company: $(SITE)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo " license: MIT" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo " min_ansible_version: 2.9" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo "dependencies: []" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
|
||||
echo "---" > $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "# Роль $(NAME)" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "Описание роли $(NAME)." >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "## Переменные" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "| Переменная | По умолчанию | Описание |" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "|------------|--------------|----------|" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "| \`$(NAME)_enabled\` | \`true\` | Включить роль |" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "| \`$(NAME)_package\` | \`$(NAME)\` | Имя пакета |" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "| \`$(NAME)_service\` | \`$(NAME)\` | Имя сервиса |" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "## Использование" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "\`\`\`yaml" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "- hosts: all" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo " roles:" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo " - role: $(NAME)" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "\`\`\`" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "## Автор" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "$(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/README.md; \
|
||||
echo "$(GREEN)✅ Роль $(NAME) создана$(RESET)";; \
|
||||
edit) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make role edit NAME=my-role$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)✏️ Редактируем роль: $(NAME)$(RESET)"; \
|
||||
$${EDITOR:-vim} $(ROLES_DIR)/$(NAME)/tasks/main.yml;; \
|
||||
test) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make role test NAME=my-role$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(PURPLE)🧪 Тестируем роль: $(NAME)$(RESET)"; \
|
||||
$(MAKE) lab test LAB_SPEC=molecule/presets/minimal.yml;; \
|
||||
lint) \
|
||||
echo "$(YELLOW)🔍 Проверяем роли...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint $(ROLES_DIR)/*'; \
|
||||
echo "$(GREEN)✅ Проверка завершена$(RESET)";; \
|
||||
deploy) \
|
||||
echo "$(PURPLE)🚀 Развертываем роли...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml files/playbooks/site.yml'; \
|
||||
echo "$(GREEN)✅ Развертывание завершено$(RESET)";; \
|
||||
info) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make role info NAME=my-role$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(BLUE)📋 Информация о роли: $(NAME)$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'cat /ansible/roles/$(NAME)/README.md';; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: list, create, edit, test, lint, deploy, info$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ VAULT
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: vault
|
||||
vault: ## Управление Ansible Vault (show|create|edit|delete|rekey|decrypt|encrypt)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
show) \
|
||||
echo "$(BLUE)🔍 Показываем содержимое vault...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-vault view --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
create) \
|
||||
echo "$(YELLOW)📝 Создаем vault файл...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'echo "---" > vault/secrets.yml && ansible-vault encrypt --encrypt-vault-id default --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
edit) \
|
||||
echo "$(BLUE)✏️ Редактируем vault файл...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-vault edit --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
delete) \
|
||||
echo "$(RED)🗑️ Удаляем vault файл...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'rm vault/secrets.yml';; \
|
||||
rekey) \
|
||||
echo "$(YELLOW)🔑 Изменяем пароль vault...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-vault rekey --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
decrypt) \
|
||||
echo "$(GREEN)🔓 Расшифровываем vault файл...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-vault decrypt --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
encrypt) \
|
||||
echo "$(RED)🔒 Шифруем vault файл...$(RESET)"; \
|
||||
docker exec ansible-controller bash -lc 'ansible-vault encrypt --encrypt-vault-id default --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: show, create, edit, delete, rekey, decrypt, encrypt$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ GIT
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: git
|
||||
git: ## Управление Git (status|add|commit|push|pull|branch|merge)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
status) \
|
||||
echo "$(CYAN)📊 Статус Git репозитория:$(RESET)"; \
|
||||
git status;; \
|
||||
add) \
|
||||
echo "$(GREEN)➕ Добавляем файлы в Git...$(RESET)"; \
|
||||
git add .;; \
|
||||
commit) \
|
||||
if [ -z "$(MESSAGE)" ]; then \
|
||||
echo "$(RED)❌ Использование: make git commit MESSAGE=\"your commit message\"$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)💾 Создаем коммит...$(RESET)"; \
|
||||
git commit -m "$(MESSAGE)";; \
|
||||
push) \
|
||||
echo "$(BLUE)🚀 Отправляем изменения...$(RESET)"; \
|
||||
git push;; \
|
||||
pull) \
|
||||
echo "$(GREEN)📥 Получаем изменения...$(RESET)"; \
|
||||
git pull;; \
|
||||
branch) \
|
||||
if [ -z "$(NAME)" ]; then \
|
||||
echo "$(RED)❌ Использование: make git branch NAME=my-branch$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(PURPLE)🌿 Создаем ветку: $(NAME)$(RESET)"; \
|
||||
git checkout -b $(NAME);; \
|
||||
merge) \
|
||||
if [ -z "$(BRANCH)" ]; then \
|
||||
echo "$(RED)❌ Использование: make git merge BRANCH=my-branch$(RESET)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "$(YELLOW)🔀 Сливаем ветку: $(BRANCH)$(RESET)"; \
|
||||
git merge $(BRANCH);; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: status, add, commit, push, pull, branch, merge$(RESET)";; \
|
||||
esac
|
||||
|
||||
# =============================================================================
|
||||
# УПРАВЛЕНИЕ DOCKER
|
||||
# =============================================================================
|
||||
|
||||
.PHONY: docker
|
||||
docker: ## Управление Docker (build|rebuild|prune|shell|logs|stop|start)
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
build) \
|
||||
docker buildx create --use --name multiarch-builder --driver docker-container; \
|
||||
if [ "$(RUN_MODE)" = "docker-compose" ]; then \
|
||||
docker compose build $(c); \
|
||||
else \
|
||||
docker build -t $(REGISTRY)/$(IMAGE) .; \
|
||||
fi;; \
|
||||
echo "$(YELLOW)🔨 Собираем Docker образы...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) build;; \
|
||||
rebuild) \
|
||||
docker buildx create --use --name multiarch-builder --driver docker-container; \
|
||||
if [ "$(RUN_MODE)" = "docker-compose" ]; then \
|
||||
docker compose build --no-cache $(c); \
|
||||
else \
|
||||
docker build --no-cache -t $(REGISTRY)/$(IMAGE) .; \
|
||||
fi;; \
|
||||
echo "$(YELLOW)🔨 Пересобираем Docker образы...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) build --no-cache;; \
|
||||
prune) \
|
||||
echo "$(RED)🧹 Очищаем Docker...$(RESET)"; \
|
||||
docker system prune -af;; \
|
||||
shell) \
|
||||
clear; \
|
||||
echo "Entering to Ansible container shell..."; \
|
||||
$(RUN) bash ;; \
|
||||
release) \
|
||||
docker buildx create --use --name multiarch-builder --driver docker-container; \
|
||||
docker login $(REGISTRY); \
|
||||
docker buildx build -t $(REGISTRY)/$(IMAGE):$(TAG) -t $(REGISTRY)/$(IMAGE):latest --platform linux/amd64,linux/arm64 --push .;; \
|
||||
images) \
|
||||
docker buildx create --use --name multiarch-builder --driver docker-container; \
|
||||
echo "Логинимся в Docker Hub..."; \
|
||||
docker login; \
|
||||
echo "Собираем и пушим основной Ansible образ..."; \
|
||||
docker buildx build -t $(REGISTRY)/$(IMAGE):$(TAG) -t $(REGISTRY)/$(IMAGE):latest --platform linux/amd64,linux/arm64 --push .; \
|
||||
echo "Собираем и пушим образ CentOS..."; \
|
||||
docker buildx build -t $(REGISTRY):centos --platform linux/amd64,linux/arm64 --push -f Dockerfile-CentOS .; \
|
||||
echo "Собираем и пушим образ Ubuntu..."; \
|
||||
docker buildx build -t $(REGISTRY):ubuntu --platform linux/amd64,linux/arm64 --push -f Dockerfile-Ubuntu .; \
|
||||
echo "Образы успешно опубликованы в Docker Hub: $(REGISTRY)";; \
|
||||
*) echo "Unknown action. Available actions: build, rebuild, prune, release";; \
|
||||
echo "$(BLUE)🐚 Входим в Docker контейнер...$(RESET)"; \
|
||||
docker exec -it ansible-controller bash;; \
|
||||
logs) \
|
||||
echo "$(CYAN)📋 Показываем логи...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) logs -f;; \
|
||||
stop) \
|
||||
echo "$(RED)🛑 Останавливаем контейнеры...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) stop;; \
|
||||
start) \
|
||||
echo "$(GREEN)▶️ Запускаем контейнеры...$(RESET)"; \
|
||||
$(DOCKER_COMPOSE) start;; \
|
||||
*) \
|
||||
echo "$(RED)❌ Неизвестная команда. Доступные: build, rebuild, prune, shell, logs, stop, start$(RESET)";; \
|
||||
esac
|
||||
|
||||
####################################################################################################
|
||||
# Работа с ролью
|
||||
####################################################################################################
|
||||
vault:
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
show) $(RUN) bash -c "ansible-vault view --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
create) $(RUN) bash -c "ansible-vault create --encrypt-vault-id default --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
edit) $(RUN) bash -c "ansible-vault edit --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
delete) $(RUN) bash -c "rm vars/secrets.yml";; \
|
||||
rekey) $(RUN) bash -c "ansible-vault rekey --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
decrypt) $(RUN) bash -c "ansible-vault decrypt --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
encrypt) $(RUN) bash -c "ansible-vault encrypt --encrypt-vault-id default --vault-password-file vault-password.txt vars/secrets.yml";; \
|
||||
*) echo "Unknown action";; \
|
||||
esac
|
||||
# =============================================================================
|
||||
# ОТЧЕТЫ И МОНИТОРИНГ
|
||||
# =============================================================================
|
||||
|
||||
role:
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
new) \
|
||||
clear; \
|
||||
echo "Введите название новой роли на английском:"; \
|
||||
read ROLE_NAME; \
|
||||
echo "Введите описание роли:"; \
|
||||
read ROLE_DESC; \
|
||||
cp -r default/ "roles/$${ROLE_NAME}"; \
|
||||
printf "\n- name: $${ROLE_DESC}" >> roles/deploy.yaml; \
|
||||
printf "\n import_playbook: $${ROLE_NAME}/deploy.yaml" >> roles/deploy.yaml; \
|
||||
printf '\n - ../../roles/%s' "$$ROLE_NAME" >> molecule/default/converge.yml; \
|
||||
printf "\n - $${ROLE_NAME}" >> roles/$$ROLE_NAME/deploy.yaml;; \
|
||||
lint) \
|
||||
clear; \
|
||||
echo "Check your role..."; \
|
||||
$(RUN) bash -c "ansible-vault decrypt --vault-password-file vault-password.txt vars/secrets.yml"; \
|
||||
$(RUN) bash -c "ansible-lint roles/*"; \
|
||||
$(RUN) bash -c "ansible-vault encrypt vars/secrets.yml --encrypt-vault-id default --vault-password-file vault-password.txt";; \
|
||||
test) \
|
||||
clear; \
|
||||
echo "Running test roles..."; \
|
||||
$(RUN) bash -c "ansible-vault decrypt --vault-password-file vault-password.txt vars/secrets.yml"; \
|
||||
$(RUN) bash -c "docker login $(REGISTRY) && molecule test --parallel --destroy=always"; \
|
||||
$(RUN) bash -c "ansible-vault encrypt vars/secrets.yml --encrypt-vault-id default --vault-password-file vault-password.txt";; \
|
||||
deploy) \
|
||||
clear; \
|
||||
echo "Deploying roles to production..."; \
|
||||
$(RUN) bash -c "ansible-playbook roles/deploy.yaml";; \
|
||||
*) echo "Unknown action";; \
|
||||
esac
|
||||
.PHONY: report
|
||||
report: ## Сгенерировать HTML отчет
|
||||
@echo "$(PURPLE)📊 Генерируем HTML отчет...$(RESET)"
|
||||
@mkdir -p reports
|
||||
@docker exec ansible-controller bash -lc 'python3 /ansible/scripts/report_html.py /ansible/reports/lab-health.json /ansible/reports/lab-report.html'
|
||||
@echo "$(GREEN)✅ HTML отчет: reports/lab-report.html$(RESET)"
|
||||
@echo "$(YELLOW)📖 Откройте отчет в браузере:$(RESET)"
|
||||
@echo " $(BLUE)file://$(PWD)/reports/lab-report.html$(RESET)"
|
||||
|
||||
####################################################################################################
|
||||
# Работа с Git
|
||||
####################################################################################################
|
||||
git:
|
||||
@case "$(word 2, $(MAKECMDGOALS))" in \
|
||||
push) \
|
||||
git branch; \
|
||||
read -p "Выберите ветку для пуша: " BRANCH; \
|
||||
read -p "Введите описание коммита: " COMMIT; \
|
||||
commitname=$$COMMIT; \
|
||||
git add . ; \
|
||||
git commit -m "$$commitname"; \
|
||||
git push -u origin $$BRANCH; \
|
||||
echo "Изменения внесены в Git";; \
|
||||
pull) \
|
||||
git pull;; \
|
||||
new) \
|
||||
read -p "Введите имя новой ветки: " BRANCH_NAME; \
|
||||
NEW_BRANCH="$$BRANCH_NAME"; \
|
||||
git checkout -b $$NEW_BRANCH; \
|
||||
echo "Создана и переключена на новую ветку: $$NEW_BRANCH";; \
|
||||
*) echo "Unknown action. Available actions: push, pull, cluster-branch";; \
|
||||
esac
|
||||
.PHONY: kubeconfigs
|
||||
kubeconfigs: ## Получить все kubeconfig файлы
|
||||
@echo "$(BLUE)📋 Получаем все kubeconfig файлы...$(RESET)"
|
||||
@mkdir -p reports/kubeconfigs
|
||||
@docker exec ansible-controller bash -lc 'for cluster in $$(kind get clusters 2>/dev/null || echo ""); do \
|
||||
if [ -n "$$cluster" ]; then \
|
||||
echo "Получаем kubeconfig для $$cluster..."; \
|
||||
kubectl --context kind-$$cluster config view --raw > /ansible/reports/kubeconfigs/kubeconfig-$$cluster.yaml; \
|
||||
fi; \
|
||||
done'
|
||||
@echo "$(GREEN)✅ Kubeconfig файлы сохранены в reports/kubeconfigs/$(RESET)"
|
||||
@if [ -d "reports/kubeconfigs" ] && [ -n "$$(ls reports/kubeconfigs/ 2>/dev/null)" ]; then \
|
||||
echo "$(YELLOW)📁 Найденные kubeconfig файлы:$(RESET)"; \
|
||||
ls -la reports/kubeconfigs/ | grep -v "^total" | awk '{print " " $$9}'; \
|
||||
fi
|
||||
|
||||
# ====== УНИВЕРСАЛЬНАЯ ЛАБОРАТОРИЯ (Molecule universal) ======
|
||||
SCENARIO ?= universal
|
||||
COMPOSE ?= docker compose
|
||||
.PHONY: open-report
|
||||
open-report: ## Открыть HTML отчет в браузере
|
||||
@if [ -f "reports/lab-report.html" ]; then \
|
||||
echo "$(BLUE)🌐 Открываем отчет в браузере...$(RESET)"; \
|
||||
if command -v open >/dev/null 2>&1; then \
|
||||
open reports/lab-report.html; \
|
||||
elif command -v xdg-open >/dev/null 2>&1; then \
|
||||
xdg-open reports/lab-report.html; \
|
||||
else \
|
||||
echo "$(YELLOW)⚠️ Откройте отчет вручную: file://$(PWD)/reports/lab-report.html$(RESET)"; \
|
||||
fi; \
|
||||
echo "$(GREEN)✅ Отчет открыт$(RESET)"; \
|
||||
else \
|
||||
echo "$(RED)❌ Отчет не найден. Сначала выполните: make report$(RESET)"; \
|
||||
fi
|
||||
|
||||
lab-up: ## Поднять контроллер
|
||||
$(COMPOSE) up -d
|
||||
.PHONY: full-test
|
||||
full-test: ## Полный цикл тестирования с отчетом и kubeconfig
|
||||
@echo "$(PURPLE)🚀 Запускаем полный цикл тестирования...$(RESET)"
|
||||
@$(MAKE) lab test
|
||||
@echo "$(BLUE)📊 Генерируем отчеты...$(RESET)"
|
||||
@$(MAKE) report
|
||||
@$(MAKE) kubeconfigs
|
||||
@echo "$(GREEN)✅ Полный цикл завершен!$(RESET)"
|
||||
@echo "$(YELLOW)📁 Результаты:$(RESET)"
|
||||
@echo " $(BLUE)📊 HTML отчет: reports/lab-report.html$(RESET)"
|
||||
@echo " $(BLUE)📋 Kubeconfig файлы: reports/kubeconfigs/$(RESET)"
|
||||
@echo "$(YELLOW)🌐 Открыть отчет: make open-report$(RESET)"
|
||||
|
||||
lab-down: ## Погасить контроллер
|
||||
$(COMPOSE) down -v
|
||||
.PHONY: chaos
|
||||
chaos: ## Запустить Chaos Engineering тесты
|
||||
@echo "$(RED)🧨 Запускаем Chaos Engineering...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml /ansible/files/playbooks/chaos.yml'
|
||||
@echo "$(GREEN)✅ Chaos Engineering завершен$(RESET)"
|
||||
|
||||
lab-sh: ## Войти в контроллер
|
||||
docker exec -it ansible-controller bash
|
||||
.PHONY: check-secrets
|
||||
check-secrets: ## Проверить безопасность секретов
|
||||
@echo "$(YELLOW)🔍 Проверяем безопасность секретов...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/secret_scan.sh'
|
||||
@echo "$(GREEN)✅ Проверка секретов завершена$(RESET)"
|
||||
|
||||
lab-test: lab-up ## Полный цикл Molecule (create+converge+verify+destroy)
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule test -s $(SCENARIO)'
|
||||
.PHONY: idempotence
|
||||
idempotence: ## Проверить идемпотентность
|
||||
@echo "$(BLUE)🔄 Проверяем идемпотентность...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml /ansible/files/playbooks/site.yml --check'
|
||||
@echo "$(GREEN)✅ Идемпотентность проверена$(RESET)"
|
||||
|
||||
lab-create: lab-up ## Создать инфраструктуру лаборатории
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule create -s $(SCENARIO)'
|
||||
.PHONY: snapshot
|
||||
snapshot: ## Сохранить снапшот лаборатории
|
||||
@echo "$(YELLOW)📸 Создаем снапшот...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/snapshot.sh'
|
||||
@echo "$(GREEN)✅ Снапшот сохранен$(RESET)"
|
||||
|
||||
lab-converge: ## Запустить роли в лаборатории
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule converge -s $(SCENARIO)'
|
||||
.PHONY: restore
|
||||
restore: ## Восстановить из снапшота
|
||||
@echo "$(BLUE)🔄 Восстанавливаем из снапшота...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/restore.sh'
|
||||
@echo "$(GREEN)✅ Снапшот восстановлен$(RESET)"
|
||||
|
||||
lab-verify: ## Проверить работу лаборатории
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule verify -s $(SCENARIO)'
|
||||
.PHONY: cleanup
|
||||
cleanup: ## Очистить лабораторию
|
||||
@echo "$(RED)🧹 Очищаем лабораторию...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/cleanup.sh'
|
||||
@echo "$(GREEN)✅ Лаборатория очищена$(RESET)"
|
||||
|
||||
lab-destroy: ## Уничтожить инфраструктуру лаборатории
|
||||
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||
bash -lc 'cd /ansible && molecule destroy -s $(SCENARIO)'
|
||||
# =============================================================================
|
||||
# УТИЛИТЫ
|
||||
# =============================================================================
|
||||
|
||||
lab-reset: lab-destroy lab-down lab-up ## Полный сброс лаборатории
|
||||
.PHONY: lint
|
||||
lint: ## Проверить весь проект на ошибки
|
||||
@echo "$(YELLOW)🔍 Проверяем весь проект...$(RESET)"
|
||||
@docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint molecule/universal/'
|
||||
@docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint files/playbooks/'
|
||||
@if [ -d "$(ROLES_DIR)" ] && [ -n "$$(ls $(ROLES_DIR)/ 2>/dev/null)" ]; then \
|
||||
docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint $(ROLES_DIR)/*'; \
|
||||
fi
|
||||
@echo "$(GREEN)✅ Проверка завершена$(RESET)"
|
||||
|
||||
# ====== K8S ХЕЛПЕРЫ ======
|
||||
kube-sh: ## Shell с kubectl/helm/istioctl внутри контейнера
|
||||
docker exec -it ansible-controller bash
|
||||
.PHONY: env
|
||||
env: ## Показать переменные окружения
|
||||
@echo "$(CYAN)🔧 Переменные окружения:$(RESET)"
|
||||
@echo "PROJECT_NAME: $(PROJECT_NAME)"
|
||||
@echo "VERSION: $(VERSION)"
|
||||
@echo "AUTHOR: $(AUTHOR)"
|
||||
@echo "SITE: $(SITE)"
|
||||
@echo "DOCKER_IMAGE: $(DOCKER_IMAGE)"
|
||||
@echo "DOCKER_NETWORK: $(DOCKER_NETWORK)"
|
||||
@echo "SCENARIO: $(SCENARIO)"
|
||||
@echo "LAB_SPEC: $(LAB_SPEC)"
|
||||
@echo "KUBE_CONTEXT: $(KUBE_CONTEXT)"
|
||||
@echo "ROLES_DIR: $(ROLES_DIR)"
|
||||
@echo "VAULT_PASSWORD_FILE: $(VAULT_PASSWORD_FILE)"
|
||||
|
||||
kube-cmd: ## make kube-cmd CLUSTER=lab CMD="get pods -A"
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make kube-cmd CLUSTER=lab CMD=\"get pods -A\""; exit 1
|
||||
endif
|
||||
docker exec -it ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) $(CMD)'
|
||||
.PHONY: clean
|
||||
clean: cleanup ## Полная очистка проекта
|
||||
@echo "$(RED)🧹 Полная очистка проекта...$(RESET)"
|
||||
@rm -rf .env
|
||||
@rm -rf vault/
|
||||
@rm -rf reports/
|
||||
@rm -rf snapshots/
|
||||
@echo "$(GREEN)✅ Проект очищен$(RESET)"
|
||||
|
||||
kube-enter: ## make kube-enter CLUSTER=lab
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make kube-enter CLUSTER=lab"; exit 1
|
||||
endif
|
||||
docker exec -it ansible-controller bash -lc '\
|
||||
POD=$$(kubectl --context kind-$(CLUSTER) -n lab-demo get pod -l app=toolbox -o jsonpath="{.items[0].metadata.name}"); \
|
||||
[ -n "$$POD" ] || { echo "toolbox pod not found"; exit 1; }; \
|
||||
kubectl --context kind-$(CLUSTER) -n lab-demo exec -it $$POD -- /bin/sh'
|
||||
# =============================================================================
|
||||
# ЗАГЛУШКИ ДЛЯ ПАРАМЕТРОВ
|
||||
# =============================================================================
|
||||
|
||||
# Port-forward Kiali (http://localhost:20001)
|
||||
kiali-port-forward: ## make kiali-port-forward CLUSTER=lab
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make kiali-port-forward CLUSTER=lab"; exit 1
|
||||
endif
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/kiali 20001:20001'
|
||||
%:
|
||||
@:
|
||||
|
||||
# Port-forward Istio IngressGateway (HTTP 8082, HTTPS 8444)
|
||||
istio-gw-port-forward: ## make istio-gw-port-forward CLUSTER=lab
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make istio-gw-port-forward CLUSTER=lab"; exit 1
|
||||
endif
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/istio-ingressgateway 8082:80 8444:443'
|
||||
@echo "Istio GW forwarded: http://localhost:8082 https://localhost:8444"
|
||||
# =============================================================================
|
||||
# ЗАГРУЗКА ПЕРЕМЕННЫХ ИЗ .env
|
||||
# =============================================================================
|
||||
|
||||
# Port-forward Grafana (http://localhost:3000)
|
||||
grafana-port-forward: ## make grafana-port-forward CLUSTER=lab
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make grafana-port-forward CLUSTER=lab"; exit 1
|
||||
endif
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-grafana 3000:80'
|
||||
@echo "Grafana: http://localhost:3000 (admin/admin)"
|
||||
|
||||
# Port-forward Prometheus (http://localhost:9090)
|
||||
prom-port-forward: ## make prom-port-forward CLUSTER=lab
|
||||
ifeq ($(strip $(CLUSTER)),)
|
||||
@echo "Usage: make prom-port-forward CLUSTER=lab"; exit 1
|
||||
endif
|
||||
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-kube-prometheus-prometheus 9090:9090'
|
||||
@echo "Prometheus: http://localhost:9090"
|
||||
|
||||
# Stop all port-forwards
|
||||
kube-pf-stop: ## убить все port-forward в контроллере
|
||||
docker exec -it ansible-controller bash -lc 'pkill -f "kubectl .* port-forward" || true'
|
||||
|
||||
# ====== ОТЧЕТЫ ======
|
||||
lab-report: ## Сгенерировать HTML отчет
|
||||
docker exec ansible-controller bash -lc 'python3 /ansible/scripts/report_html.py /ansible/reports/lab-health.json /ansible/reports/lab-report.html'
|
||||
@echo "HTML report: reports/lab-report.html"
|
||||
|
||||
# ====== ДОПОЛНИТЕЛЬНЫЕ ХЕЛПЕРЫ ======
|
||||
bookinfo-url: ## echo productpage URL via Istio Gateway (needs istio-gw-port-forward first)
|
||||
@echo "Open: http://localhost:8082/productpage"
|
||||
|
||||
grafana-open: ## echo URL to Grafana + hint dashboards
|
||||
@echo "Grafana: http://localhost:3000 (admin/admin)"
|
||||
@echo "Dashboards:"
|
||||
@echo " - Istio • Overview (uid: istio-overview)"
|
||||
@echo " - Service • SLI (uid: service-sli)"
|
||||
|
||||
# ====== СНАПШОТЫ И ОЧИСТКА ======
|
||||
lab-snapshot: ## Сохранить снапшот лаборатории
|
||||
bash scripts/snapshot.sh
|
||||
|
||||
lab-restore: ## Восстановить из снапшота
|
||||
bash scripts/restore.sh
|
||||
|
||||
lab-cleanup: ## Очистить лабораторию
|
||||
bash scripts/cleanup.sh
|
||||
ifneq (,$(wildcard .env))
|
||||
include .env
|
||||
export
|
||||
endif
|
||||
90
README.md
90
README.md
@@ -50,14 +50,83 @@ make pre-commit-install
|
||||
### Первый запуск
|
||||
|
||||
```bash
|
||||
# Инициализация проекта
|
||||
make init
|
||||
|
||||
# Поднять контроллер
|
||||
make lab-up
|
||||
make lab up
|
||||
|
||||
# Запустить минимальную лабораторию
|
||||
make lab-test LAB_SPEC=molecule/presets/minimal.yml
|
||||
make lab test
|
||||
|
||||
# Посмотреть отчет
|
||||
make lab-report
|
||||
make report
|
||||
```
|
||||
|
||||
### Основные команды
|
||||
|
||||
```bash
|
||||
# Показать справку
|
||||
make help
|
||||
|
||||
# Управление лабораторией
|
||||
make lab up # Поднять контроллер
|
||||
make lab down # Остановить контроллер
|
||||
make lab test # Полный цикл тестирования
|
||||
make lab create # Создать инфраструктуру
|
||||
make lab converge # Запустить роли
|
||||
make lab verify # Проверить работу
|
||||
make lab destroy # Уничтожить инфраструктуру
|
||||
make lab reset # Полный сброс
|
||||
|
||||
# Управление Kubernetes
|
||||
make kube sh # Войти в контейнер
|
||||
make kube cmd CLUSTER=lab CMD="get pods -A"
|
||||
make kube kiali CLUSTER=lab
|
||||
make kube istio CLUSTER=lab
|
||||
make kube grafana CLUSTER=lab
|
||||
make kube prom CLUSTER=lab
|
||||
make kube kubeconfig CLUSTER=lab # Получить kubeconfig
|
||||
|
||||
# Управление пресетами
|
||||
make preset list # Список пресетов
|
||||
make preset create NAME=my-preset
|
||||
make preset test NAME=my-preset
|
||||
make preset edit NAME=my-preset
|
||||
|
||||
# Управление ролями
|
||||
make role list # Список ролей
|
||||
make role create NAME=my-role
|
||||
make role test NAME=my-role
|
||||
make role lint # Проверка ролей
|
||||
make role deploy # Развертывание ролей
|
||||
make role info NAME=my-role # Информация о роли
|
||||
|
||||
# Проверка всего проекта
|
||||
make lint # Проверить весь проект на ошибки
|
||||
make check-secrets # Проверить безопасность секретов
|
||||
make idempotence # Проверить идемпотентность
|
||||
make chaos # Запустить Chaos Engineering тесты
|
||||
|
||||
# Управление Vault
|
||||
make vault show # Показать содержимое
|
||||
make vault create # Создать vault файл
|
||||
make vault edit # Редактировать vault файл
|
||||
|
||||
# Управление Git
|
||||
make git status # Статус репозитория
|
||||
make git add # Добавить файлы
|
||||
make git commit MESSAGE="your message"
|
||||
make git push # Отправить изменения
|
||||
|
||||
# Отчеты и мониторинг
|
||||
make report # HTML отчет
|
||||
make kubeconfigs # Получить все kubeconfig файлы
|
||||
make open-report # Открыть отчет в браузере
|
||||
make full-test # Полный цикл с отчетом и kubeconfig
|
||||
make snapshot # Создать снапшот
|
||||
make restore # Восстановить снапшот
|
||||
make cleanup # Очистить лабораторию
|
||||
```
|
||||
|
||||
## 📚 Документация
|
||||
@@ -67,6 +136,7 @@ make lab-report
|
||||
- **[Универсальная лаборатория](docs/universal-lab.md)** - полное руководство по работе с лабораторией
|
||||
- **[Пресеты](docs/presets.md)** - описание всех 21 готового пресета
|
||||
- **[Роли](docs/roles.md)** - структура и создание Ansible ролей
|
||||
- **[CI/CD](ci-cd/README.md)** - настройка CI/CD для Ansible ролей
|
||||
|
||||
### Дополнительные материалы
|
||||
|
||||
@@ -239,9 +309,9 @@ images:
|
||||
|
||||
# Настройки по умолчанию для systemd контейнеров
|
||||
systemd_defaults:
|
||||
privileged: true
|
||||
privileged: true
|
||||
command: "/sbin/init"
|
||||
volumes:
|
||||
volumes:
|
||||
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
|
||||
tmpfs:
|
||||
- "/run"
|
||||
@@ -332,6 +402,11 @@ ansible-template/
|
||||
│ ├── examples.md # Примеры использования
|
||||
│ ├── troubleshooting.md # Решение проблем
|
||||
│ └── api.md # API Reference
|
||||
├── ci-cd/ # CI/CD конфигурация
|
||||
│ ├── README.md # Документация CI/CD
|
||||
│ ├── .gitlab-ci.yml # GitLab CI/CD
|
||||
│ ├── gitlab/ # GitLab Runner
|
||||
│ └── dockerfiles/ # Dockerfile'ы для разных ОС
|
||||
├── molecule/ # Molecule конфигурация
|
||||
│ ├── universal/ # Универсальный сценарий
|
||||
│ │ ├── molecule.yml # Конфигурация Molecule
|
||||
@@ -352,11 +427,14 @@ ansible-template/
|
||||
│ └── requirements.yml # Ansible коллекции
|
||||
├── roles/ # Ansible роли
|
||||
│ └── your_role/ # Ваши роли
|
||||
├── scripts/ # Скрипты
|
||||
├── scripts/ # Скрипты (запускаются через Docker)
|
||||
│ ├── report_html.py # Генератор HTML отчетов
|
||||
│ ├── snapshot.sh # Создание снапшотов
|
||||
│ ├── restore.sh # Восстановление снапшотов
|
||||
│ └── cleanup.sh # Очистка лаборатории
|
||||
├── vault/ # Секреты и пароли
|
||||
│ ├── .vault # Пароль для Ansible Vault
|
||||
│ └── secrets.yml # Зашифрованные секреты
|
||||
└── .pre-commit-config.yaml # Pre-commit конфигурация
|
||||
```
|
||||
|
||||
|
||||
123
ci-cd/README.md
Normal file
123
ci-cd/README.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# CI/CD для Ansible ролей
|
||||
|
||||
Этот раздел содержит примеры настройки CI/CD для Ansible ролей с использованием GitLab CI/CD.
|
||||
|
||||
## Структура
|
||||
|
||||
```
|
||||
ci-cd/
|
||||
├── README.md # Эта документация
|
||||
├── .gitlab-ci.yml # GitLab CI/CD конфигурация
|
||||
├── gitlab/ # GitLab Runner конфигурация
|
||||
│ ├── config.json # Docker registry конфигурация
|
||||
│ ├── docker-compose.yaml # GitLab Runner в Docker
|
||||
│ └── runner/
|
||||
│ └── config.toml # Runner конфигурация
|
||||
└── dockerfiles/ # Dockerfile'ы для разных ОС
|
||||
├── Dockerfile # Базовый Dockerfile
|
||||
├── Dockerfile-CentOS # Dockerfile для CentOS
|
||||
└── Dockerfile-Ubuntu # Dockerfile для Ubuntu
|
||||
```
|
||||
|
||||
## GitLab CI/CD
|
||||
|
||||
### Основные этапы
|
||||
|
||||
1. **Lint** - проверка синтаксиса Ansible
|
||||
2. **Test** - запуск тестов через Molecule
|
||||
3. **Deploy** - развертывание в продакшн
|
||||
4. **Notify** - уведомления о результатах
|
||||
|
||||
### Настройка
|
||||
|
||||
1. **Переменные окружения:**
|
||||
- `CI_REGISTRY_USER` - пользователь Docker registry
|
||||
- `CI_REGISTRY_PASSWORD` - пароль Docker registry
|
||||
- `SSH_PRIVATE_KEY` - SSH ключ для доступа к серверам
|
||||
- `TELEGRAM_BOT_TOKEN` - токен Telegram бота
|
||||
- `TELEGRAM_CHAT_ID` - ID чата для уведомлений
|
||||
|
||||
2. **Docker Registry:**
|
||||
- Настроен доступ к `hub.cism-ms.ru`
|
||||
- Используется образ `hub.cism-ms.ru/ansible/ansible:latest`
|
||||
|
||||
3. **Vault:**
|
||||
- Автоматическое расшифрование/шифрование секретов
|
||||
- Используется `vault-password.txt` для доступа
|
||||
|
||||
## GitLab Runner
|
||||
|
||||
### Конфигурация
|
||||
|
||||
- **Executor:** Docker
|
||||
- **Image:** `hub.cism-ms.ru/ansible/ansible:latest`
|
||||
- **Privileged:** true
|
||||
- **Volumes:** Docker socket для DinD
|
||||
|
||||
### Настройка Runner
|
||||
|
||||
1. Зарегистрировать Runner:
|
||||
```bash
|
||||
docker-compose -f ci-cd/gitlab/docker-compose.yaml up -d
|
||||
```
|
||||
|
||||
2. Настроить переменные в `ci-cd/gitlab/runner/config.toml`
|
||||
|
||||
## Dockerfile'ы
|
||||
|
||||
### Базовый Dockerfile
|
||||
- Основан на Ubuntu
|
||||
- Установлены Ansible, Molecule, Docker
|
||||
- Настроен systemd для тестирования
|
||||
|
||||
### Dockerfile-CentOS
|
||||
- Основан на CentOS
|
||||
- Адаптирован для RHEL-семейства
|
||||
- Установлены необходимые пакеты
|
||||
|
||||
### Dockerfile-Ubuntu
|
||||
- Основан на Ubuntu
|
||||
- Оптимизирован для Debian-семейства
|
||||
- Включены дополнительные инструменты
|
||||
|
||||
## Использование
|
||||
|
||||
### Локальная разработка
|
||||
|
||||
```bash
|
||||
# Создать роль
|
||||
make role create NAME=my-role
|
||||
|
||||
# Тестировать роль
|
||||
make role test NAME=my-role
|
||||
|
||||
# Проверить синтаксис
|
||||
make role lint
|
||||
```
|
||||
|
||||
### CI/CD Pipeline
|
||||
|
||||
1. **Автоматический запуск** при push в ветки
|
||||
2. **Lint проверка** всех ролей
|
||||
3. **Molecule тесты** для каждой роли
|
||||
4. **Deploy** в продакшн (ручной запуск)
|
||||
5. **Уведомления** в Telegram
|
||||
|
||||
### Настройка для своего проекта
|
||||
|
||||
1. Скопировать `.gitlab-ci.yml` в корень проекта
|
||||
2. Настроить переменные в GitLab
|
||||
3. Обновить Docker registry URL
|
||||
4. Настроить SSH ключи для деплоя
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Все секреты хранятся в Ansible Vault
|
||||
- SSH ключи используются только для деплоя
|
||||
- Docker registry требует аутентификации
|
||||
- Vault файлы автоматически шифруются после использования
|
||||
|
||||
## Автор
|
||||
|
||||
Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
@@ -8,12 +8,16 @@ services:
|
||||
command: sleep infinity
|
||||
environment:
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
ANSIBLE_VAULT_PASSWORD_FILE: /ansible/vault-password.txt
|
||||
ANSIBLE_VAULT_PASSWORD_FILE: /ansible/vault/.vault
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./molecule:/ansible/molecule
|
||||
- ./files:/ansible/files
|
||||
- ./vault-password.txt:/ansible/vault-password.txt
|
||||
- ./scripts:/ansible/scripts
|
||||
- ./reports:/ansible/reports
|
||||
- ./snapshots:/ansible/snapshots
|
||||
- ./vault:/ansible/vault
|
||||
- ./.ansible-lint:/ansible/.ansible-lint
|
||||
# каталог с ролями (локальный или внешний)
|
||||
- ${ROLES_DIR:-./roles}:/ansible/roles:ro
|
||||
working_dir: /ansible
|
||||
|
||||
54
docs/api.md
54
docs/api.md
@@ -197,6 +197,50 @@ kubectl logs <pod-name>
|
||||
kubectl exec -it <pod-name> -- /bin/sh
|
||||
```
|
||||
|
||||
### Ansible-lint команды
|
||||
|
||||
```bash
|
||||
# Проверить весь проект
|
||||
make lint
|
||||
|
||||
# Проверить роли
|
||||
make role lint
|
||||
|
||||
# Проверить конкретную роль
|
||||
ansible-lint --config-file .ansible-lint roles/my-role/
|
||||
|
||||
# Проверить playbook
|
||||
ansible-lint --config-file .ansible-lint files/playbooks/site.yml
|
||||
```
|
||||
|
||||
### Настройки ansible-lint (.ansible-lint)
|
||||
|
||||
```yaml
|
||||
skip_list:
|
||||
- fqcn # Полные имена модулей
|
||||
- yaml[new-line-at-end-of-file] # Новая строка в конце файла
|
||||
- yaml[truthy] # Булевы значения
|
||||
- yaml[line-length] # Длина строки
|
||||
- var-naming[no-role-prefix] # Префиксы переменных
|
||||
- 'ignore-errors' # Игнорирование ошибок
|
||||
|
||||
exclude_paths:
|
||||
- molecule/universal/ # Исключить файлы Molecule
|
||||
- files/playbooks/ # Исключить playbooks с Docker модулями
|
||||
```
|
||||
|
||||
**Описание пропускаемых правил:**
|
||||
- `fqcn` - позволяет использовать короткие имена модулей (например, `yum` вместо `ansible.builtin.yum`)
|
||||
- `yaml[new-line-at-end-of-file]` - не требует новой строки в конце YAML файлов
|
||||
- `yaml[truthy]` - позволяет использовать `yes/no` вместо `true/false`
|
||||
- `yaml[line-length]` - не ограничивает длину строк в YAML
|
||||
- `var-naming[no-role-prefix]` - не требует префиксов для переменных ролей
|
||||
- `ignore-errors` - позволяет использовать `ignore_errors: yes`
|
||||
|
||||
**Исключенные пути:**
|
||||
- `molecule/universal/` - файлы Molecule с Docker модулями
|
||||
- `files/playbooks/` - playbooks с Docker Compose модулями
|
||||
|
||||
### Port-forward команды
|
||||
|
||||
```bash
|
||||
@@ -432,10 +476,10 @@ python3 scripts/report_html.py <input.json> <output.html>
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Создание снапшотов лаборатории
|
||||
# Создание снапшотов лаборатории (запускается через Docker)
|
||||
|
||||
# Параметры
|
||||
OUT_DIR="snapshots"
|
||||
OUT_DIR="/ansible/snapshots"
|
||||
|
||||
# Создать директорию
|
||||
mkdir -p "$OUT_DIR"
|
||||
@@ -457,10 +501,10 @@ done
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Восстановление из снапшотов
|
||||
# Восстановление из снапшотов (запускается через Docker)
|
||||
|
||||
# Параметры
|
||||
IN_DIR="snapshots"
|
||||
IN_DIR="/ansible/snapshots"
|
||||
|
||||
# Проверить директорию
|
||||
[ -d "$IN_DIR" ] || { echo "No snapshots dir"; exit 1; }
|
||||
@@ -480,7 +524,7 @@ done
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Очистка лаборатории
|
||||
# Очистка лаборатории (запускается через Docker)
|
||||
|
||||
echo "[cleanup] removing lab containers/volumes/networks"
|
||||
|
||||
|
||||
73
env.example
73
env.example
@@ -1,16 +1,69 @@
|
||||
# Переменные окружения для универсальной лаборатории
|
||||
# =============================================================================
|
||||
# Ansible Template Environment Configuration
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
# =============================================================================
|
||||
|
||||
# Путь к каталогу с Ansible ролями (вне этого репозитория)
|
||||
ROLES_DIR=/path/to/your/ansible/roles
|
||||
# Основные настройки проекта
|
||||
PROJECT_NAME=ansible-template
|
||||
VERSION=0.1.0
|
||||
AUTHOR="Сергей Антропов"
|
||||
SITE="https://devops.org.ru"
|
||||
|
||||
# Telegram уведомления (опционально)
|
||||
TG_TOKEN=your_telegram_bot_token
|
||||
TG_CHAT=your_telegram_chat_id
|
||||
# Docker настройки
|
||||
DOCKER_IMAGE=quay.io/ansible/creator-ee:latest
|
||||
DOCKER_NETWORK=labnet
|
||||
DOCKER_COMPOSE=docker compose
|
||||
|
||||
# Пауза для ручной проверки (минуты)
|
||||
LAB_PAUSE_MINUTES=10
|
||||
|
||||
# Сценарий Molecule
|
||||
# Molecule настройки
|
||||
SCENARIO=universal
|
||||
LAB_SPEC=molecule/presets/minimal.yml
|
||||
MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule
|
||||
|
||||
# Kubernetes настройки
|
||||
KUBE_CONTEXT=kind-lab
|
||||
ISTIO_VERSION=1.22.1
|
||||
KIND_VERSION=v0.23.0
|
||||
|
||||
# Пути
|
||||
ROLES_DIR=./roles
|
||||
VAULT_PASSWORD_FILE=vault/.vault
|
||||
|
||||
# Переменные для лаборатории
|
||||
LAB_PAUSE_MINUTES=10
|
||||
LAB_SPEC=molecule/presets/minimal.yml
|
||||
|
||||
# Переменные для пресетов
|
||||
PRESET_NAME=minimal
|
||||
PRESET_TYPE=classic
|
||||
|
||||
# Переменные для ролей
|
||||
ROLE_NAME=my-role
|
||||
ROLE_DESCRIPTION="My Ansible role"
|
||||
|
||||
# Переменные для Git
|
||||
GIT_BRANCH=main
|
||||
GIT_REMOTE=origin
|
||||
|
||||
# Переменные для Docker
|
||||
DOCKER_REGISTRY=quay.io
|
||||
DOCKER_TAG=latest
|
||||
|
||||
# Переменные для мониторинга
|
||||
GRAFANA_ADMIN_PASSWORD=admin
|
||||
PROMETHEUS_RETENTION=15d
|
||||
|
||||
# Переменные для Istio
|
||||
ISTIO_PROFILE=demo
|
||||
KIALI_AUTH_STRATEGY=anonymous
|
||||
|
||||
# Переменные для Kind
|
||||
KIND_WORKERS=2
|
||||
KIND_API_PORT=6443
|
||||
|
||||
# Переменные для портов
|
||||
HTTP_PORT=8080
|
||||
HTTPS_PORT=8443
|
||||
GRAFANA_PORT=3000
|
||||
PROMETHEUS_PORT=9090
|
||||
KIALI_PORT=20001
|
||||
93
files/playbooks/chaos.yml
Normal file
93
files/playbooks/chaos.yml
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
# Chaos Engineering для тестирования отказоустойчивости
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- name: Chaos Network (add latency)
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
chaos_duration: "{{ chaos_duration | default(60) }}"
|
||||
chaos_latency: "{{ chaos_latency | default('100ms') }}"
|
||||
chaos_loss: "{{ chaos_loss | default('5%') }}"
|
||||
|
||||
tasks:
|
||||
- name: Install chaos tools
|
||||
package:
|
||||
name: [iproute2, iptables, tc]
|
||||
state: present
|
||||
|
||||
- name: Add network latency
|
||||
command: >
|
||||
tc qdisc add dev eth0 root netem delay {{ chaos_latency }}
|
||||
ignore_errors: true
|
||||
|
||||
- name: Add packet loss
|
||||
command: >
|
||||
tc qdisc add dev eth0 root netem loss {{ chaos_loss }}
|
||||
ignore_errors: true
|
||||
|
||||
- name: Wait for chaos duration
|
||||
pause:
|
||||
seconds: "{{ chaos_duration }}"
|
||||
|
||||
- name: Remove network chaos
|
||||
command: >
|
||||
tc qdisc del dev eth0 root
|
||||
ignore_errors: true
|
||||
|
||||
- name: Chaos Services (random failures)
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
chaos_services:
|
||||
- postgresql
|
||||
- redis
|
||||
- nginx
|
||||
- docker
|
||||
|
||||
tasks:
|
||||
- name: Random service stop
|
||||
systemd:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
loop: "{{ chaos_services }}"
|
||||
when: (ansible_play_hosts.index(inventory_hostname) + ansible_date_time.epoch) % 3 == 0
|
||||
|
||||
- name: Wait for chaos
|
||||
pause:
|
||||
seconds: 30
|
||||
|
||||
- name: Restart services
|
||||
systemd:
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
loop: "{{ chaos_services }}"
|
||||
when: (ansible_play_hosts.index(inventory_hostname) + ansible_date_time.epoch) % 3 == 0
|
||||
|
||||
- name: Chaos Docker (container failures)
|
||||
hosts: "{{ groups['dind'] | default([]) }}"
|
||||
gather_facts: false
|
||||
vars:
|
||||
docker_host: "tcp://{{ inventory_hostname }}:2375"
|
||||
|
||||
tasks:
|
||||
- name: Random container stop
|
||||
community.docker.docker_container:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
docker_host: "{{ docker_host }}"
|
||||
loop: "{{ ansible_play_hosts }}"
|
||||
when: (ansible_play_hosts.index(inventory_hostname) + ansible_date_time.epoch) % 4 == 0
|
||||
|
||||
- name: Wait for chaos
|
||||
pause:
|
||||
seconds: 20
|
||||
|
||||
- name: Restart containers
|
||||
community.docker.docker_container:
|
||||
name: "{{ item }}"
|
||||
state: started
|
||||
docker_host: "{{ docker_host }}"
|
||||
loop: "{{ ansible_play_hosts }}"
|
||||
when: (ansible_play_hosts.index(inventory_hostname) + ansible_date_time.epoch) % 4 == 0
|
||||
@@ -35,66 +35,11 @@
|
||||
- unzip
|
||||
state: present
|
||||
|
||||
# Под каждую группу — свои роли. Подставь свои имена.
|
||||
- name: ETCD
|
||||
hosts: etcd
|
||||
# Развертывание инфраструктуры
|
||||
- name: Deploy infrastructure
|
||||
hosts: all
|
||||
become: true
|
||||
roles:
|
||||
# - role: your_role_etcd
|
||||
tasks:
|
||||
- name: ETCD placeholder
|
||||
- name: Infrastructure placeholder
|
||||
debug:
|
||||
msg: "ETCD группа готова для настройки"
|
||||
|
||||
- name: Patroni
|
||||
hosts: patroni
|
||||
become: true
|
||||
roles:
|
||||
# - role: your_role_patroni
|
||||
tasks:
|
||||
- name: Patroni placeholder
|
||||
debug:
|
||||
msg: "Patroni группа готова для настройки"
|
||||
|
||||
- name: HAProxy
|
||||
hosts: haproxy
|
||||
become: true
|
||||
roles:
|
||||
# - role: your_role_haproxy
|
||||
tasks:
|
||||
- name: HAProxy placeholder
|
||||
debug:
|
||||
msg: "HAProxy группа готова для настройки"
|
||||
|
||||
# Пример: развернуть docker-compose прямо внутри DinD хоста(ов)
|
||||
- name: DinD stack deploy
|
||||
hosts: apps
|
||||
gather_facts: false
|
||||
vars:
|
||||
docker_host: "tcp://{{ inventory_hostname }}:2375"
|
||||
stack_dir: /root/stack
|
||||
tasks:
|
||||
- name: Create stack directory
|
||||
file:
|
||||
path: "{{ stack_dir }}"
|
||||
state: directory
|
||||
|
||||
- name: Copy demo docker-compose.yml
|
||||
copy:
|
||||
dest: "{{ stack_dir }}/docker-compose.yml"
|
||||
content: |
|
||||
version: "3.9"
|
||||
services:
|
||||
web:
|
||||
image: nginx:alpine
|
||||
ports: ["8080:80"]
|
||||
cache:
|
||||
image: redis:7-alpine
|
||||
|
||||
- name: Deploy stack on DinD
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ stack_dir }}"
|
||||
state: present
|
||||
docker_host: "{{ docker_host }}"
|
||||
when: item.type is defined and item.type == 'dind'
|
||||
loop: "{{ groups['apps'] | map('extract', hostvars) | list }}"
|
||||
msg: "Инфраструктура готова для настройки"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
- name: Converge
|
||||
hosts: all
|
||||
vars_files:
|
||||
- ../../vars/secrets.yml
|
||||
roles:
|
||||
@@ -1,8 +0,0 @@
|
||||
- name: Destroy containers on interrupt
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Ensure containers are destroyed
|
||||
docker_container:
|
||||
name: "{{ item.name }}"
|
||||
state: absent
|
||||
loop: "{{ molecule_yml.platforms }}"
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
dependency:
|
||||
name: galaxy
|
||||
enabled: false
|
||||
options:
|
||||
requirements-file: requirements.yml
|
||||
|
||||
driver:
|
||||
name: docker
|
||||
|
||||
platforms:
|
||||
- name: centos
|
||||
image: "inecs/ansible:centos"
|
||||
privileged: true
|
||||
pre_build_image: true
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
tmpfs:
|
||||
- /tmp
|
||||
- /run
|
||||
- name: ubuntu
|
||||
image: "inecs/ansible:ubuntu"
|
||||
privileged: true
|
||||
pre_build_image: true
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
tmpfs:
|
||||
- /tmp
|
||||
- /run
|
||||
|
||||
provisioner:
|
||||
name: ansible
|
||||
connection_options:
|
||||
ansible_connection: docker
|
||||
ansible_user: root
|
||||
env:
|
||||
ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3
|
||||
lint:
|
||||
name: ansible-lint
|
||||
|
||||
verifier:
|
||||
name: ansible
|
||||
|
||||
scenario:
|
||||
name: default
|
||||
test_sequence:
|
||||
- dependency
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- idempotence
|
||||
- side_effect
|
||||
- verify
|
||||
- cleanup
|
||||
- destroy
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
- name: Prepare
|
||||
hosts: all
|
||||
tasks:
|
||||
- name: Detect OS family
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- "min"
|
||||
|
||||
- name: Обновляем пакеты для работы с Ansible в RockyLinux (Centos/RedHat)
|
||||
when: ansible_facts['os_family'] == "RedHat"
|
||||
block:
|
||||
- name: Устанавливаем репозиторий AppStream (если его нет)
|
||||
ansible.builtin.raw: dnf config-manager --set-enabled appstream
|
||||
changed_when: false
|
||||
|
||||
- name: Установить rsync
|
||||
ansible.builtin.raw: dnf install -y rsync
|
||||
changed_when: false
|
||||
|
||||
- name: Устанавливаем Python 3.8
|
||||
ansible.builtin.raw: dnf install -y python38 python38-pip
|
||||
changed_when: false
|
||||
|
||||
- name: Обновляем символическую ссылку python3
|
||||
ansible.builtin.raw: alternatives --set python /usr/bin/python3.8
|
||||
changed_when: false
|
||||
# - name: Fix repository URLs
|
||||
# ansible.builtin.command:
|
||||
# cmd: sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
||||
# changed_when: false
|
||||
|
||||
# - name: Update baseurl
|
||||
# ansible.builtin.command:
|
||||
# cmd: sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
||||
# changed_when: false
|
||||
|
||||
# - name: Install required packages
|
||||
# ansible.builtin.yum:
|
||||
# name:
|
||||
# - epel-release
|
||||
# - python3
|
||||
# - python3-pip
|
||||
# state: present
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
- name: Prepare
|
||||
hosts: all
|
||||
tasks:
|
||||
- name: Reun verify
|
||||
debug:
|
||||
msg: "Hello, Verify!"
|
||||
@@ -1,132 +0,0 @@
|
||||
---
|
||||
# Проверка работы systemd, docker и docker-compose в образах
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- name: Verify systemd, docker and docker-compose services
|
||||
hosts: all
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- name: Display OS information
|
||||
debug:
|
||||
msg: "Тестирование на {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
|
||||
- name: Check if systemd is available and running
|
||||
systemd:
|
||||
name: systemd
|
||||
state: started
|
||||
register: systemd_status
|
||||
failed_when: false
|
||||
|
||||
- name: Display systemd status
|
||||
debug:
|
||||
msg: "Systemd статус: {{ 'Доступен и запущен' if systemd_status is succeeded else 'Недоступен или не запущен' }}"
|
||||
|
||||
- name: Check systemd version
|
||||
command: systemd --version
|
||||
register: systemd_version
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display systemd version
|
||||
debug:
|
||||
msg: "Версия systemd: {{ systemd_version.stdout_lines[0] if systemd_version.stdout_lines else 'Не определена' }}"
|
||||
|
||||
- name: Check if docker service exists
|
||||
stat:
|
||||
path: /usr/bin/docker
|
||||
register: docker_binary
|
||||
|
||||
- name: Check if docker service exists (alternative path)
|
||||
stat:
|
||||
path: /usr/local/bin/docker
|
||||
register: docker_binary_alt
|
||||
|
||||
- name: Display docker binary status
|
||||
debug:
|
||||
msg: "Docker binary: {{ 'Найден в /usr/bin/docker' if docker_binary.stat.exists else ('Найден в /usr/local/bin/docker' if docker_binary_alt.stat.exists else 'Не найден') }}"
|
||||
|
||||
- name: Check docker version
|
||||
command: docker --version
|
||||
register: docker_version
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display docker version
|
||||
debug:
|
||||
msg: "Версия Docker: {{ docker_version.stdout if docker_version.stdout else 'Docker не установлен' }}"
|
||||
|
||||
- name: Check if docker daemon is running
|
||||
command: docker info
|
||||
register: docker_info
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display docker daemon status
|
||||
debug:
|
||||
msg: "Docker daemon: {{ 'Запущен' if docker_info is succeeded else 'Не запущен или недоступен' }}"
|
||||
|
||||
- name: Check if docker-compose binary exists
|
||||
stat:
|
||||
path: /usr/local/bin/docker-compose
|
||||
register: docker_compose_binary
|
||||
|
||||
- name: Check if docker-compose binary exists (alternative path)
|
||||
stat:
|
||||
path: /usr/bin/docker-compose
|
||||
register: docker_compose_binary_alt
|
||||
|
||||
- name: Check if docker compose plugin exists
|
||||
command: docker compose version
|
||||
register: docker_compose_plugin
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display docker-compose status
|
||||
debug:
|
||||
msg: "Docker Compose: {{ 'Найден как binary' if docker_compose_binary.stat.exists or docker_compose_binary_alt.stat.exists else ('Найден как plugin' if docker_compose_plugin is succeeded else 'Не найден') }}"
|
||||
|
||||
- name: Display docker-compose version
|
||||
debug:
|
||||
msg: "Версия Docker Compose: {{ docker_compose_plugin.stdout if docker_compose_plugin is succeeded else 'Docker Compose не установлен' }}"
|
||||
|
||||
- name: Test docker functionality
|
||||
command: docker run --rm hello-world
|
||||
register: docker_test
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display docker test result
|
||||
debug:
|
||||
msg: "Тест Docker: {{ 'Успешно' if docker_test is succeeded else 'Ошибка - ' + docker_test.stderr }}"
|
||||
|
||||
- name: Check systemd services status
|
||||
command: systemctl list-units --type=service --state=running
|
||||
register: running_services
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display running services count
|
||||
debug:
|
||||
msg: "Количество запущенных сервисов: {{ running_services.stdout_lines | length }}"
|
||||
|
||||
- name: Check for docker-related systemd services
|
||||
command: systemctl list-units --type=service | grep -i docker
|
||||
register: docker_services
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display docker services
|
||||
debug:
|
||||
msg: "Docker сервисы: {{ docker_services.stdout_lines if docker_services.stdout_lines else 'Не найдены' }}"
|
||||
|
||||
- name: Final summary
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
РЕЗУЛЬТАТЫ ПРОВЕРКИ ОБРАЗА {{ ansible_distribution }}:
|
||||
========================================
|
||||
Systemd: {{ '✓ Работает' if systemd_status is succeeded else '✗ Не работает' }}
|
||||
Docker: {{ '✓ Установлен и работает' if docker_info is succeeded else '✗ Не установлен или не работает' }}
|
||||
Docker Compose: {{ '✓ Доступен' if (docker_compose_binary.stat.exists or docker_compose_binary_alt.stat.exists or docker_compose_plugin is succeeded) else '✗ Недоступен' }}
|
||||
========================================
|
||||
@@ -5,17 +5,75 @@
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
# Перечисли файлы/глобы с секретами (можно добавлять свои пути)
|
||||
vault_targets:
|
||||
- /ansible/vault/secrets.yml
|
||||
- /ansible/files/playbooks/group_vars/*/vault.yml
|
||||
- /ansible/files/playbooks/host_vars/*/vault.yml
|
||||
- /ansible/roles/**/vars/vault.yml
|
||||
|
||||
pre_tasks:
|
||||
- name: Load lab preset (vars)
|
||||
include_vars:
|
||||
file: "{{ lab_spec }}"
|
||||
|
||||
tasks:
|
||||
- name: Install collections in controller
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: bash -lc "ansible-galaxy collection install -r /ansible/files/requirements.yml || true"
|
||||
|
||||
# --- Preflight Vault: если файл уже открыт, шифруем и снова расшифровываем ---
|
||||
- name: Preflight vault — normalize state (encrypt if plaintext, then decrypt)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -euo pipefail;
|
||||
shopt -s nullglob globstar;
|
||||
for p in {{ vault_targets | map('quote') | join(' ') }}; do
|
||||
for f in $p; do
|
||||
if [ ! -f "$f" ]; then continue; fi
|
||||
head -n1 "$f" | grep -q "^\$ANSIBLE_VAULT;" && enc=1 || enc=0
|
||||
if [ "$enc" -eq 0 ]; then
|
||||
echo "[vault] plaintext -> encrypt: $f";
|
||||
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault/.vault "$f";
|
||||
else
|
||||
echo "[vault] already encrypted: $f";
|
||||
fi
|
||||
echo "[vault] decrypt for run: $f";
|
||||
ansible-vault decrypt --vault-password-file /ansible/vault/.vault "$f";
|
||||
done
|
||||
done
|
||||
'
|
||||
|
||||
- name: Run external playbook (your roles live in /ansible/roles)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc "
|
||||
ANSIBLE_ROLES_PATH=/ansible/roles
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.yml /ansible/files/playbooks/site.yml
|
||||
"
|
||||
|
||||
# --- Пост-этап: всегда шифруем обратно ---
|
||||
- name: Post-run vault — re-encrypt everything
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -euo pipefail;
|
||||
shopt -s nullglob globstar;
|
||||
for p in {{ vault_targets | map('quote') | join(' ') }}; do
|
||||
for f in $p; do
|
||||
if [ ! -f "$f" ]; then continue; fi
|
||||
head -n1 "$f" | grep -q "^\$ANSIBLE_VAULT;" && enc=1 || enc=0
|
||||
if [ "$enc" -eq 0 ]; then
|
||||
echo "[vault] encrypt back: $f";
|
||||
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault/.vault "$f" || true;
|
||||
fi
|
||||
done
|
||||
done
|
||||
'
|
||||
ignore_errors: true
|
||||
|
||||
@@ -135,6 +135,31 @@
|
||||
content: "{{ inv_ini }}"
|
||||
mode: "0644"
|
||||
|
||||
# ---------- YAML inventory (primary, multi-groups) ----------
|
||||
- name: Build YAML inventory dict
|
||||
set_fact:
|
||||
inv_yaml_obj:
|
||||
all:
|
||||
vars:
|
||||
ansible_connection: community.docker.docker
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
children: "{{ children_map | default({}) }}"
|
||||
|
||||
- name: Build children map for YAML
|
||||
set_fact:
|
||||
children_map: "{{ children_map | default({}) | combine({ item_key: { 'hosts': dict((groups_map[item_key] | default([])) | zip((groups_map[item_key] | default([])) | map('extract', {}))) }}, recursive=True) }}"
|
||||
loop: "{{ groups_map.keys() | list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
vars:
|
||||
item_key: "{{ item }}"
|
||||
|
||||
- name: Write hosts.yml
|
||||
copy:
|
||||
dest: "{{ molecule_ephemeral_directory }}/inventory/hosts.yml"
|
||||
content: "{{ inv_yaml_obj | combine({'all': {'children': children_map | default({}) }}, recursive=True) | to_nice_yaml(indent=2) }}"
|
||||
mode: "0644"
|
||||
|
||||
# ---------- Kind clusters (если определены) ----------
|
||||
- name: Create kind cluster configs
|
||||
community.docker.docker_container_exec:
|
||||
|
||||
@@ -24,10 +24,14 @@ provisioner:
|
||||
name: ansible
|
||||
config_options:
|
||||
defaults:
|
||||
stdout_callback: default
|
||||
stdout_callback: yaml
|
||||
callbacks_enabled: profile_tasks
|
||||
env:
|
||||
ANSIBLE_STDOUT_CALLBACK: default
|
||||
ANSIBLE_STDOUT_CALLBACK: yaml
|
||||
ANSIBLE_CALLBACKS_ENABLED: profile_tasks
|
||||
inventory:
|
||||
links:
|
||||
hosts: "${MOLECULE_EPHEMERAL_DIRECTORY}/inventory/hosts.yml"
|
||||
|
||||
dependency:
|
||||
name: galaxy
|
||||
|
||||
@@ -27,9 +27,15 @@
|
||||
command: >
|
||||
bash -lc "
|
||||
ANSIBLE_ROLES_PATH=/ansible/roles
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml --check"
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.yml /ansible/files/playbooks/site.yml --check"
|
||||
register: idemp
|
||||
|
||||
- name: Assert idempotence
|
||||
assert:
|
||||
that:
|
||||
- "'changed=0' in idemp.stdout"
|
||||
fail_msg: "Playbook is not idempotent: {{ idemp.stdout }}"
|
||||
|
||||
# --- Helm demo nginx + Ingress + Toolbox per cluster ---
|
||||
- name: Helm nginx install & Ingress & Toolbox (per cluster)
|
||||
community.docker.docker_container_exec:
|
||||
@@ -265,6 +271,27 @@
|
||||
'
|
||||
when: kind_names | length > 0
|
||||
|
||||
# --- Health Dashboard ---
|
||||
- name: Generate health report
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
mkdir -p /ansible/reports;
|
||||
echo "{
|
||||
\"timestamp\": \"$(date -Iseconds)\",
|
||||
\"lab_status\": \"healthy\",
|
||||
\"containers\": [
|
||||
$(docker ps --format "{\"name\": \"{{.Names}}\", \"status\": \"{{.Status}}\", \"ports\": \"{{.Ports}}\"}" | tr "\n" "," | sed "s/,$//")
|
||||
],
|
||||
\"services\": [
|
||||
$(systemctl list-units --type=service --state=active --format=json | jq -r ".[] | select(.unit | startswith(\"postgresql\")) | {\"name\": .unit, \"status\": .sub}" | tr "\n" "," | sed "s/,$//")
|
||||
],
|
||||
\"idempotence\": {{ "true" if "'changed=0'" in idemp.stdout else "false" }},
|
||||
\"vault_status\": "encrypted"
|
||||
}" > /ansible/reports/lab-health.json
|
||||
'
|
||||
|
||||
# --- Final summary ---
|
||||
- name: Final summary
|
||||
debug:
|
||||
|
||||
0
reports/.gitkeep
Normal file
0
reports/.gitkeep
Normal file
@@ -1,4 +0,0 @@
|
||||
---
|
||||
collections:
|
||||
- name: maxhoesel.proxmox
|
||||
version: 5.0.1
|
||||
@@ -1 +0,0 @@
|
||||
---
|
||||
0
scripts/.gitkeep
Normal file
0
scripts/.gitkeep
Normal file
@@ -5,7 +5,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
IN_DIR="snapshots"
|
||||
IN_DIR="/ansible/snapshots"
|
||||
if [ ! -d "$IN_DIR" ]; then
|
||||
echo "No snapshots dir"
|
||||
exit 1
|
||||
|
||||
72
scripts/secret_scan.sh
Normal file
72
scripts/secret_scan.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
# Secrets Inspector - проверка безопасности секретов
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "[secrets] Проверяем безопасность секретов..."
|
||||
|
||||
# Проверка 1: Vault файлы должны быть зашифрованы
|
||||
echo "[secrets] Проверяем vault файлы..."
|
||||
vault_files=$(find /ansible -name "*.yml" -o -name "*.yaml" | grep -E "(vault|secret)" || true)
|
||||
if [ -n "$vault_files" ]; then
|
||||
for file in $vault_files; do
|
||||
if [ -f "$file" ]; then
|
||||
if head -n1 "$file" | grep -q "^\$ANSIBLE_VAULT;"; then
|
||||
echo "✅ $file - зашифрован"
|
||||
else
|
||||
echo "❌ $file - НЕ ЗАШИФРОВАН!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "ℹ️ Vault файлы не найдены"
|
||||
fi
|
||||
|
||||
# Проверка 2: Пароль vault не должен быть в Git
|
||||
echo "[secrets] Проверяем vault пароль..."
|
||||
if [ -f "/ansible/vault/.vault" ]; then
|
||||
if git ls-files | grep -q "vault/.vault"; then
|
||||
echo "❌ Vault пароль в Git!"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Vault пароль не в Git"
|
||||
fi
|
||||
else
|
||||
echo "❌ Vault пароль не найден"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверка 3: Нет открытых секретов в коде
|
||||
echo "[secrets] Проверяем открытые секреты..."
|
||||
secret_patterns=(
|
||||
"password.*=.*['\"][^'\"]{8,}['\"]"
|
||||
"api_key.*=.*['\"][^'\"]{8,}['\"]"
|
||||
"secret.*=.*['\"][^'\"]{8,}['\"]"
|
||||
"token.*=.*['\"][^'\"]{8,}['\"]"
|
||||
)
|
||||
|
||||
for pattern in "${secret_patterns[@]}"; do
|
||||
if grep -r -E "$pattern" /ansible --exclude-dir=.git --exclude="*.encrypted" --exclude="vault/.vault" 2>/dev/null; then
|
||||
echo "❌ Найдены открытые секреты в коде!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✅ Открытые секреты не найдены"
|
||||
|
||||
# Проверка 4: Права доступа к vault файлам
|
||||
echo "[secrets] Проверяем права доступа..."
|
||||
if [ -f "/ansible/vault/.vault" ]; then
|
||||
perms=$(stat -c "%a" "/ansible/vault/.vault")
|
||||
if [ "$perms" != "600" ]; then
|
||||
echo "❌ Vault пароль имеет неправильные права: $perms (должно быть 600)"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Vault пароль имеет правильные права: $perms"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Все проверки безопасности пройдены!"
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OUT_DIR="snapshots"
|
||||
OUT_DIR="/ansible/snapshots"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# Найти все контейнеры лаборатории
|
||||
|
||||
0
snapshots/.gitkeep
Normal file
0
snapshots/.gitkeep
Normal file
@@ -1 +0,0 @@
|
||||
test
|
||||
0
vault/.gitkeep
Normal file
0
vault/.gitkeep
Normal file
1
vault/.vault
Normal file
1
vault/.vault
Normal file
@@ -0,0 +1 @@
|
||||
test_password
|
||||
36
vault/secrets.yml
Normal file
36
vault/secrets.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
37313930666665366564356631646336636130366562343435376262666131373338616633646165
|
||||
6232383865363562346664363334666438333438316630370a326532623133653963343230613434
|
||||
38356337383966343732313930616632656635653063343961396539623130636231663433373565
|
||||
6237303562303839630a646530653434616566303136643438356239626561326532383839663534
|
||||
61393164643337653137373437393834623430313937613866303131343061326665333362316333
|
||||
36303435353431313766653563653037393934373537643365313931373336333133633635386633
|
||||
66616331653337333531356432613431653135303134643261336339346538653838303235393332
|
||||
39373538643861653634613231323661366131303237393133653035326431386436653265306437
|
||||
62643266313862623737656164643437616535633438383533346237313364313834383237623265
|
||||
39303064356263666566386532323061646131336632616335626462373264633662616335353462
|
||||
30393664313565396532383965396337616237373864626631333237633263653065626265393264
|
||||
64396464356633333366353537633364643735323439336434386437643430316136613335646232
|
||||
36313462666438626136363334343439333537646461653166313535366361643235326137333163
|
||||
30363632613839653034626664653764376366653064613936353739363663326466303462356533
|
||||
36393932303135643531373432326236653163653835306361363261393137373835623639346464
|
||||
33616238633232373237643564626439653363356635373939333664653864643061643534336565
|
||||
39303366616635313466623634336234386438353262653031356633323036306636333437623263
|
||||
33343863316338356466323334316334313933393730626332373736396234376135623437393662
|
||||
30626263613738373461613933373166353737353538316337633062633861633135643638383031
|
||||
37626464323763376334656363373634343431383936386363623761366536653166353239343332
|
||||
33313435366430666531316131306239643632376262656631396162636233343631336566613531
|
||||
64313136383865326331366466316365646136623736303164373735636366643430343138373138
|
||||
39653533336434333939656361366633376361663266653063666537633261653663363134333562
|
||||
63663562303432323230303065303930343435356433326235323366373662666261313966616639
|
||||
39376131623237323836663735313839333034626163363236313939396638623565363038333432
|
||||
39643630366263613732636462353166626332653234336332366363346262316465353130623130
|
||||
32663061633830373038656539653238393732333964343836653965383131656534386337393335
|
||||
35383135316365393734666136343964393630346137393661643735613863613764313238663665
|
||||
35323664353939303631653835636231323531353863333839306531376337653063373536623833
|
||||
34326534303364383031346137323966353133333138306631323735376561656136376333616261
|
||||
63343435623233623338666337383265353766323666396139633964643563393366656339633736
|
||||
39326261316430313637313230656536323362666361353930353135383737313037316139653964
|
||||
32326230396263383939393961353763323138613230353364313038366165646130303363643239
|
||||
31303930653862323839653330373532646630336565303535306361346235306565613635396366
|
||||
316438396434306663316134316230636462
|
||||
Reference in New Issue
Block a user