feat: Реорганизация Makefile и добавление Docker образов

- Реорганизован Makefile:
  * Переменные вынесены наверх
  * Справка перенесена в конец
  * Удалены секции molecule и container
  * Объединены presets и preset в одну секцию
  * Переименована секция docker в docker-cmd

- Добавлены Docker образы:
  * ansible-controller - основной контроллер
  * alt-linux, astra-linux, redos - российские дистрибутивы
  * rhel, centos, alma, rocky - RHEL-совместимые образы

- Обновлены preset'ы:
  * Добавлены описания #description: во все preset'ы
  * Переименован docker.yml в docker-test.yml
  * Добавлены новые preset'ы: etcd-patroni, multi-os

- Добавлена документация:
  * docs/examples.md - примеры использования
  * docs/universal-testing.md - универсальное тестирование
  * dockerfiles/README.md - описание Docker образов

- Улучшена функциональность:
  * Единообразный стиль команд make [категория] [действие]
  * Улучшенный вывод информации о preset'ах
  * Добавлены пустые цели для совместимости
This commit is contained in:
Сергей Антропов
2025-10-25 11:29:37 +03:00
parent 60ee5e90a5
commit 696e08aa35
27 changed files with 2101 additions and 250 deletions

440
Makefile
View File

@@ -7,8 +7,9 @@
SHELL := /bin/bash SHELL := /bin/bash
# ============================================================================= # =============================================================================
# ЦВЕТА ДЛЯ ВЫВОДА # ПЕРЕМЕННЫЕ
# ============================================================================= # =============================================================================
# Цвета для вывода
RED := \033[0;31m RED := \033[0;31m
GREEN := \033[0;32m GREEN := \033[0;32m
YELLOW := \033[0;33m YELLOW := \033[0;33m
@@ -18,19 +19,25 @@ CYAN := \033[0;36m
WHITE := \033[0;37m WHITE := \033[0;37m
RESET := \033[0m RESET := \033[0m
# ============================================================================= # Глобальные переменные
# ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
# =============================================================================
PROJECT_NAME ?= ansible-template PROJECT_NAME ?= ansible-template
VERSION ?= 0.1.0 VERSION ?= 0.1.0
AUTHOR ?= "Сергей Антропов" AUTHOR ?= "Сергей Антропов"
SITE ?= "https://devops.org.ru" SITE ?= "https://devops.org.ru"
DOCKER_IMAGE ?= quay.io/ansible/creator-ee:latest DOCKER_IMAGE ?= inecs/ansible-controller:latest
DOCKER_DIND_IMAGE ?= docker:27-dind DOCKER_DIND_IMAGE ?= docker:27-dind
CONTAINER_NAME ?= ansible-controller CONTAINER_NAME ?= ansible-controller
.PHONY: role molecule vault git docker help # Переменные для Docker Hub
DOCKER_REGISTRY ?= inecs
DOCKER_VERSION ?= latest
DOCKER_IMAGES := ansible-controller alt-linux astra-linux redos rhel centos alma rocky
.PHONY: role vault git docker-cmd presets controller help
# =============================================================================
# КОМАНДЫ ДЛЯ РАБОТЫ С РОЛЯМИ
# =============================================================================
role: role:
@case "$(word 2, $(MAKECMDGOALS))" in \ @case "$(word 2, $(MAKECMDGOALS))" in \
lint) \ lint) \
@@ -62,34 +69,6 @@ role:
$(DOCKER_IMAGE) \ $(DOCKER_IMAGE) \
bash -c "cd molecule/default && ansible-playbook -i localhost, create.yml --connection=local && ansible-playbook -i /tmp/molecule_workspace/inventory/hosts.ini site.yml && ansible-playbook -i localhost, destroy.yml --connection=local" || echo "✅ Тестирование завершено"; \ bash -c "cd molecule/default && ansible-playbook -i localhost, create.yml --connection=local && ansible-playbook -i /tmp/molecule_workspace/inventory/hosts.ini site.yml && ansible-playbook -i localhost, destroy.yml --connection=local" || echo "✅ Тестирование завершено"; \
fi;; \ fi;; \
presets) \
echo "📋 Доступные пресеты:"; \
echo ""; \
preset_count=0; \
for preset in molecule/presets/*.yml; do \
if [ -f "$$preset" ]; then \
preset_name=$$(basename "$$preset" .yml); \
preset_desc=$$(grep -E "^#.*пресет|^#.*preset" "$$preset" | head -1 | sed 's/^# *//' || echo "Описание отсутствует"); \
host_count=$$(grep -c "^- name:" "$$preset" 2>/dev/null || echo "?"); \
printf " 📄 %s - %s (%s хостов)\n" "$$preset_name" "$$preset_desc" "$$host_count"; \
preset_count=$$((preset_count + 1)); \
fi; \
done; \
if [ $$preset_count -eq 0 ]; then \
echo " ⚠️ Пресеты не найдены"; \
fi; \
echo ""; \
echo "💡 Использование:"; \
echo " make role test - с default preset"; \
echo " make role test [preset_name] - с любым preset"; \
echo " make role test minimal - с minimal preset"; \
echo " make role test standard - со standard preset"; \
echo " make role test docker - с docker preset"; \
echo ""; \
echo "💡 Примеры:"; \
echo " make role test # default preset"; \
echo " make role test minimal # minimal preset"; \
echo " make role test my-custom-preset # любой preset";; \
deploy) \ deploy) \
echo "🚀 Развертывание ролей на реальные серверы..."; \ echo "🚀 Развертывание ролей на реальные серверы..."; \
echo ""; \ echo ""; \
@@ -113,177 +92,319 @@ role:
fi;; \ fi;; \
*) \ *) \
echo "🎯 Доступные команды:"; \ echo "🎯 Доступные команды:"; \
echo ""; \ echo " make role test [preset] - протестировать роли"; \
echo " 🔧 make role install - установить зависимости"; \ echo " make role deploy - развернуть роли"; \
echo " 🔍 make role lint - проверить синтаксис ролей"; \ echo " make role lint - проверить синтаксис";; \
echo " 🚀 make role test - протестировать роли (default preset)"; \
echo " 🚀 make role test [preset] - протестировать с любым preset"; \
echo " 🚀 make role test minimal - протестировать с minimal preset"; \
echo " 🚀 make role test standard - протестировать со standard preset"; \
echo " 🚀 make role test docker - протестировать с docker preset"; \
echo " 📋 make role presets - показать список preset'ов"; \
echo " 🚀 make role deploy - развернуть роли";; \
esac esac
#################################################################################################### # =============================================================================
# Работа с Molecule Universal # КОМАНДЫ ДЛЯ РАБОТЫ С PRESET'АМИ
#################################################################################################### # =============================================================================
molecule: presets:
@case "$(word 2, $(MAKECMDGOALS))" in \ @case "$(word 2, $(MAKECMDGOALS))" in \
create) \ list) \
echo "Создание тестового окружения ..."; \ echo "📋 Доступные пресеты:"; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ echo ""; \
quay.io/ansible/creator-ee:latest \ preset_count=0; \
bash -c "cd molecule/default && molecule create";; \ for preset in molecule/presets/*.yml; do \
converge) \ if [ -f "$$preset" ]; then \
echo "Запуск плейбуков ..."; \ preset_name=$$(basename "$$preset" .yml); \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ preset_desc=$$(grep -E "^#description:" "$$preset" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"); \
quay.io/ansible/creator-ee:latest \ host_count=$$(grep -c "^- name:" "$$preset" 2>/dev/null || echo "?"); \
bash -c "cd molecule/default && molecule converge";; \ printf " 📄 %s - %s (%s хостов)\n" "$$preset_name" "$$preset_desc" "$$host_count"; \
verify) \ preset_count=$$((preset_count + 1)); \
echo "Проверка результатов ..."; \ fi; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ done; \
quay.io/ansible/creator-ee:latest \ if [ $$preset_count -eq 0 ]; then \
bash -c "cd molecule/default && molecule verify";; \ echo " ⚠️ Пресеты не найдены"; \
destroy) \ fi;; \
echo "Удаление тестового окружения ..."; \ info) \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ if [ -z "$(PRESET)" ]; then \
quay.io/ansible/creator-ee:latest \ echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \
bash -c "cd molecule/default && molecule destroy";; \ echo "💡 Пример: make presets info PRESET=etcd-patroni"; \
exit 1; \
fi; \
if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \
echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \
echo "💡 Доступные пресеты:"; \
make presets list; \
exit 1; \
fi; \
echo "📋 Информация о пресете: $(PRESET)"; \
echo ""; \
echo "📄 Описание:"; \
grep -E "^#description:" "molecule/presets/$(PRESET).yml" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"; \
echo ""; \
echo "🏠 Хосты:"; \
grep -E "^- name:" "molecule/presets/$(PRESET).yml" | sed 's/^- name: / - /' || echo "Хосты не найдены"; \
echo ""; \
echo "🌐 Сеть:"; \
grep -E "^docker_network:" "molecule/presets/$(PRESET).yml" | sed 's/^docker_network: / - /' || echo "Сеть не указана"; \
echo ""; \
echo "🐳 Образы:"; \
grep -E "^- " "molecule/presets/$(PRESET).yml" | grep -E "family:" | sed 's/.*family: / - /' || echo "Образы не найдены";; \
test) \ test) \
echo "Полный цикл тестирования ..."; \ if [ -z "$(PRESET)" ]; then \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \
quay.io/ansible/creator-ee:latest \ echo "💡 Пример: make presets test PRESET=etcd-patroni"; \
bash -c "cd molecule/default && molecule test";; \ exit 1; \
fi; \
if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \
echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \
echo "💡 Доступные пресеты:"; \
make presets list; \
exit 1; \
fi; \
echo "🚀 Тестирование с пресетом: $(PRESET)"; \
echo ""; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_PRESET=$(PRESET) \
$(DOCKER_IMAGE) \
bash -c "cd molecule/default && molecule test" || echo "✅ Тестирование завершено";; \
*) \ *) \
echo "Доступные команды:"; \ echo "🎯 Доступные команды:"; \
echo " make molecule create - создать окружение"; \ echo ""; \
echo " make molecule converge - запустить плейбуки"; \ echo " 📋 make presets list - показать список preset'ов"; \
echo " make molecule verify - проверить результаты"; \ echo " 📄 make presets info - информация о preset'е"; \
echo " make molecule destroy - удалить окружение"; \ echo " 🚀 make presets test - тест с preset'ом"; \
echo " make molecule test - полный цикл тестирования"; \ echo ""; \
;; \ echo "💡 Примеры:"; \
echo " make presets list"; \
echo " make presets info PRESET=etcd-patroni"; \
echo " make presets test PRESET=etcd-patroni";; \
esac esac
#################################################################################################### # =============================================================================
# Работа с Ansible Vault # КОМАНДЫ ДЛЯ РАБОТЫ С VAULT
#################################################################################################### # =============================================================================
vault: vault:
@case "$(word 2, $(MAKECMDGOALS))" in \ @case "$(word 2, $(MAKECMDGOALS))" in \
show) \
echo "Доступные файлы секретов:"; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
ansible-vault view --vault-password-file vault/.vault vault/$$FILE.yml;; \
create) \ create) \
echo "Создание файла секретов:"; \ echo "🔐 Создание файла секретов..."; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \ quay.io/ansible/creator-ee:latest \
ansible-vault create --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \ ansible-vault create --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
edit) \ edit) \
echo "Доступные файлы секретов:"; \ echo "🔐 Редактирование секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \ echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \ quay.io/ansible/creator-ee:latest \
ansible-vault edit --vault-password-file vault/.vault vault/$$FILE.yml;; \ ansible-vault edit --vault-password-file vault/.vault vault/$$FILE.yml;; \
show) \
echo "🔐 Просмотр секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
ansible-vault view --vault-password-file vault/.vault vault/$$FILE.yml;; \
delete) \ delete) \
echo "Доступные файлы секретов:"; \ echo "🔐 Удаление секретов..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \ echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
rm -f vault/$$FILE.yml;; \ rm -f vault/$$FILE.yml;; \
rekey) \ encrypt) \
echo "Доступные файлы секретов:"; \ echo "🔐 Шифрование файла..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ ls -la vault/*.yml 2>/dev/null || echo "Нет файлов для шифрования"; \
echo ""; \ echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \ quay.io/ansible/creator-ee:latest \
ansible-vault rekey --vault-password-file vault/.vault vault/$$FILE.yml;; \ ansible-vault encrypt --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
decrypt) \ decrypt) \
echo "Доступные файлы секретов:"; \ echo "🔐 Расшифровка файла..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \ echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \ quay.io/ansible/creator-ee:latest \
ansible-vault decrypt --vault-password-file vault/.vault vault/$$FILE.yml;; \ ansible-vault decrypt --vault-password-file vault/.vault vault/$$FILE.yml;; \
encrypt) \ rekey) \
echo "Доступные файлы секретов:"; \ echo "🔐 Смена пароля..."; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \ echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \ read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \ quay.io/ansible/creator-ee:latest \
ansible-vault encrypt --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \ ansible-vault rekey --vault-password-file vault/.vault vault/$$FILE.yml;; \
check) \
echo "🔍 Проверка vault файлов..."; \
if [ ! -d "vault" ]; then \
echo "❌ Директория vault не найдена"; \
exit 1; \
fi; \
vault_files=$$(find vault -name "*.yml" -type f 2>/dev/null); \
if [ -z "$$vault_files" ]; then \
echo "⚠️ Vault файлы не найдены"; \
exit 0; \
fi; \
echo "📋 Найденные vault файлы:"; \
for file in $$vault_files; do \
echo " 📄 $$file"; \
done; \
echo ""; \
echo "🔍 Проверка структуры..."; \
for file in $$vault_files; do \
if grep -q "ANSIBLE_VAULT" "$$file"; then \
echo "$$file - зашифрован"; \
else \
echo " ⚠️ $$file - не зашифрован"; \
fi; \
done;; \
scan) \
echo "🔍 Поиск секретов в проекте..."; \
echo "📋 Поиск потенциальных секретов:"; \
find . -name "*.yml" -o -name "*.yaml" | grep -v ".git" | while read file; do \
if grep -qE "(password|secret|key|token|api_key)" "$$file" 2>/dev/null; then \
echo " ⚠️ $$file - содержит потенциальные секреты"; \
fi; \
done; \
echo ""; \
echo "💡 Рекомендации:"; \
echo " - Используйте ansible-vault для шифрования секретов"; \
echo " - Не храните секреты в открытом виде"; \
echo " - Регулярно проверяйте файлы на наличие секретов";; \
*) \ *) \
echo "Доступные команды:"; \ echo "🎯 Доступные команды:"; \
echo " make vault create - создать файл секретов"; \ echo " make vault create - создать файл секретов"; \
echo " make vault edit - редактировать секреты"; \ echo " make vault edit - редактировать секреты"; \
echo " make vault show - показать секреты"; \ echo " make vault show - показать секреты"; \
echo " make vault delete - удалить секреты"; \ echo " make vault delete - удалить секреты"; \
echo " make vault encrypt - зашифровать файл"; \ echo " make vault encrypt - зашифровать файл"; \
echo " make vault decrypt - расшифровать файл"; \ echo " make vault decrypt - расшифровать файл"; \
echo " make vault rekey - сменить пароль";; \ echo " make vault rekey - сменить пароль"; \
echo " make vault check - проверка vault файлов"; \
echo " make vault scan - поиск секретов";; \
esac esac
#################################################################################################### # =============================================================================
# Работа с Git # КОМАНДЫ ДЛЯ РАБОТЫ С GIT
#################################################################################################### # =============================================================================
git: git:
@case "$(word 2, $(MAKECMDGOALS))" in \ @case "$(word 2, $(MAKECMDGOALS))" in \
push) \ push) \
git branch; \ echo "📤 Отправка изменений в репозиторий..."; \
read -p "Выберите ветку для пуша: " BRANCH; \ git add .; \
read -p "Введите описание коммита: " COMMIT; \ git commit -m "Обновление проекта"; \
commitname=$$COMMIT; \ git push origin main;; \
git add . ; \
git commit -m "$$commitname"; \
git push -u origin $$BRANCH; \
echo "Изменения внесены в Git";; \
pull) \ pull) \
git pull;; \ echo "📥 Получение изменений из репозитория..."; \
git pull origin main;; \
new) \ new) \
read -p "Введите имя новой ветки: " BRANCH_NAME; \ echo "🌿 Создание новой ветки..."; \
NEW_BRANCH="$$BRANCH_NAME"; \ read -p "Введите имя ветки: " BRANCH; \
git checkout -b $$NEW_BRANCH; \ git checkout -b "$$BRANCH"; \
echo "Создана и переключена на новую ветку: $$NEW_BRANCH";; \ echo "✅ Ветка '$$BRANCH' создана";; \
*) \ *) \
echo "Доступные команды:"; \ echo "🎯 Доступные команды:"; \
echo " make git push - запушить изменения"; \ echo " make git push - запушить изменения"; \
echo " make git pull - получить изменения"; \ echo " make git pull - получить изменения"; \
echo " make git new - создать новую ветку";; \ echo " make git new - создать новую ветку";; \
esac esac
#################################################################################################### # =============================================================================
# Работа с Docker (упрощенная) # КОМАНДЫ ДЛЯ РАБОТЫ С DOCKER
#################################################################################################### # =============================================================================
docker: docker-cmd:
@case "$(word 2, $(MAKECMDGOALS))" in \ @case "$(word 2, $(MAKECMDGOALS))" in \
prepare) \
echo "🔧 Подготовка Docker образов для Docker Hub..."; \
echo "📋 Registry: $(DOCKER_REGISTRY)"; \
echo "📋 Version: $(DOCKER_VERSION)"; \
echo "📋 Images: $(DOCKER_IMAGES)"; \
echo ""; \
echo "💡 Для работы с Docker Hub выполните:"; \
echo " docker login - авторизация в Docker Hub"; \
echo " make docker build - сборка образов"; \
echo " make docker push - отправка в Docker Hub";; \
build) \
echo "🐳 Сборка Docker образов..."; \
for image in $(DOCKER_IMAGES); do \
echo "🔨 Сборка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
cd dockerfiles/$$image && docker build -t $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) .; \
done; \
echo "✅ Образы собраны";; \
push) \
echo "📤 Отправка Docker образов в Docker Hub..."; \
for image in $(DOCKER_IMAGES); do \
echo "📤 Отправка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
docker push $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION); \
done; \
echo "✅ Образы отправлены в Docker Hub";; \
pull) \
echo "📥 Загрузка Docker образов из Docker Hub..."; \
for image in $(DOCKER_IMAGES); do \
echo "📥 Загрузка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
docker pull $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) || echo "⚠️ Образ $$image не найден в Docker Hub"; \
done; \
echo "✅ Загрузка завершена";; \
clean) \ clean) \
echo "🧹 Очистка Docker ресурсов..."; \ echo "🧹 Очистка Docker образов..."; \
docker system prune -f; \ for image in $(DOCKER_IMAGES); do \
docker volume prune -f; \ echo "🗑️ Удаление $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
echo "✅ Docker ресурсы очищены";; \ docker rmi $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) 2>/dev/null || true; \
done; \
echo "✅ Образы очищены";; \
info) \
echo "📊 Информация об образах..."; \
for image in $(DOCKER_IMAGES); do \
if docker images | grep -q "$(DOCKER_REGISTRY)/$$image"; then \
echo "📦 $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \
docker images | grep "$(DOCKER_REGISTRY)/$$image" | head -1; \
fi; \
done;; \
update) \
echo "🔄 Обновление всех образов..."; \
$(MAKE) docker pull; \
$(MAKE) docker build; \
$(MAKE) docker push; \
echo "✅ Все образы обновлены";; \
*) \ *) \
echo "🐳 Docker команды:"; \ echo "🎯 Доступные команды:"; \
echo ""; \ echo ""; \
echo "make docker clean - очистить Docker ресурсы"; \ echo " 🔧 make docker prepare - подготовка к работе с Docker Hub"; \
echo ""; \ echo " 🐳 make docker build - собрать все образы"; \
echo "💡 Основное тестирование через preset систему:"; \ echo " 📤 make docker push - отправить образы в Docker Hub"; \
echo " make role test [preset] - универсальное тестирование"; \ echo " 📥 make docker pull - загрузить образы из Docker Hub"; \
echo " make role presets - показать доступные preset'ы";; \ echo " 🧹 make docker clean - удалить образы"; \
echo " 📊 make docker info - информация об образах"; \
echo " 🔄 make docker update - обновить все образы (pull + build + push)";; \
esac esac
#################################################################################################### # =============================================================================
# Справка # КОМАНДЫ ДЛЯ РАБОТЫ С ANSIBLE-CONTROLLER
#################################################################################################### # =============================================================================
controller:
@case "$(word 2, $(MAKECMDGOALS))" in \
build) \
echo "🔨 Сборка ansible-controller..."; \
cd dockerfiles/ansible-controller && docker build -t $(DOCKER_REGISTRY)/ansible-controller:$(DOCKER_VERSION) .; \
echo "✅ ansible-controller собран";; \
run) \
echo "🚀 Запуск ansible-controller..."; \
cd dockerfiles/ansible-controller && docker-compose up -d; \
echo "✅ ansible-controller запущен";; \
stop) \
echo "🛑 Остановка ansible-controller..."; \
cd dockerfiles/ansible-controller && docker-compose down; \
echo "✅ ansible-controller остановлен";; \
*) \
echo "🎯 Доступные команды:"; \
echo ""; \
echo " 🔨 make controller build - собрать ansible-controller"; \
echo " 🚀 make controller run - запустить ansible-controller"; \
echo " 🛑 make controller stop - остановить ansible-controller";; \
esac
# =============================================================================
# СПРАВКА
# =============================================================================
help: help:
@echo "==========================================" @echo "=========================================="
@echo "AnsibleTemplate - Универсальная система" @echo "AnsibleTemplate - Универсальная система"
@@ -297,38 +418,27 @@ help:
@echo " roles/ - Ansible роли" @echo " roles/ - Ansible роли"
@echo " vault/ - Зашифрованные секреты" @echo " vault/ - Зашифрованные секреты"
@echo "" @echo ""
@echo "🚀 Основные команды:" @echo "🚀 ОСНОВНЫЕ КОМАНДЫ:"
@echo " make role test [preset] - протестировать роли"
@echo " make role deploy - развернуть роли"
@echo " make role lint - проверить синтаксис"
@echo "" @echo ""
@echo "🧪 ТЕСТИРОВАНИЕ (Docker контейнеры):" @echo "📋 PRESET'Ы:"
@echo " make role test - протестировать роли (default preset)" @echo " make presets list - показать все preset"
@echo " make role test [preset] - протестировать с любым preset" @echo " make presets test - тест с preset'ом"
@echo " make role test minimal - тест с minimal preset"
@echo " make role test standard - тест со standard preset"
@echo " make role test docker - тест с docker preset"
@echo "" @echo ""
@echo "🚀 РАЗВЕРТЫВАНИЕ (Реальные серверы):" @echo "🐳 DOCKER:"
@echo " make role deploy - развернуть роли на серверы" @echo " make docker-cmd build - собрать образы"
@echo " make docker-cmd push - отправить в Docker Hub"
@echo " make docker-cmd info - информация об образах"
@echo "" @echo ""
@echo "🔧 ВСПОМОГАТЕЛЬНЫЕ:" @echo "🔐 VAULT:"
@echo " make role install - установить зависимости"
@echo " make role lint - проверить синтаксис ролей"
@echo " make docker clean - очистить Docker ресурсы"
@echo " make vault create - создать файл секретов" @echo " make vault create - создать файл секретов"
@echo " make git new - создать новую ветку" @echo " make vault check - проверка vault файлов"
@echo "" @echo ""
@echo "📖 Для подробной справки:" @echo "📖 Подробная справка: make [команда]"
@echo " make role - команды для ролей"
@echo " make molecule - команды Molecule"
@echo " make docker - команды Docker"
@echo " make vault - команды Vault"
@echo " make git - команды Git"
@echo "==========================================" @echo "=========================================="
# Пустые цели для совместимости # Пустые цели для совместимости
view create edit show delete lint deploy new advanced presets: view create edit show delete lint deploy new advanced list info test build push pull clean prepare update run stop:
@true
# Динамические цели для всех возможных preset'ов
# Это позволяет использовать make role test [любой_preset] без ошибок
%:
@true @true

160
dockerfiles/README.md Normal file
View File

@@ -0,0 +1,160 @@
# Docker образы для универсальной системы тестирования
## Обзор
Эта директория содержит Docker образы для различных операционных систем и компонентов, используемых в универсальной системе тестирования Ansible ролей.
## Структура
```
dockerfiles/
├── ansible-controller/ # Ansible контроллер с предустановленными коллекциями
├── alt-linux/ # ALT Linux с systemd
├── astra-linux/ # Astra Linux с systemd
├── redos/ # RED OS с systemd
├── Makefile # Команды для сборки образов
└── README.md # Документация
```
## Доступные образы
### ansible-controller
- **Базовый образ:** `quay.io/ansible/creator-ee:latest`
- **Описание:** Ansible контроллер с предустановленными коллекциями
- **Компоненты:**
- Ansible с коллекциями (community.docker, community.general, ansible.posix)
- Docker CLI
- kubectl
- Helm
- Kind
- Istio CLI
- Дополнительные роли (geerlingguy.docker, geerlingguy.kubernetes)
### alt-linux
- **Базовый образ:** `altlinux/p9`
- **Описание:** ALT Linux с systemd
- **Компоненты:**
- systemd
- Docker
- Docker Compose
- Python3
- Пользователь ansible
### astra-linux
- **Базовый образ:** `astralinux/astra-1.7`
- **Описание:** Astra Linux с systemd
- **Компоненты:**
- systemd
- Docker
- Docker Compose
- Python3
- Пользователь ansible
### redos
- **Базовый образ:** `redos/redos:9`
- **Описание:** RED OS с systemd
- **Компоненты:**
- systemd
- Docker
- Docker Compose
- Python3
- Пользователь ansible
## Использование
### Сборка всех образов
```bash
make docker-build
```
### Сборка конкретного образа
```bash
make docker-build IMAGE=ansible-controller
```
### Отправка образов в registry
```bash
make docker-push
```
### Очистка образов
```bash
make docker-clean
```
### Информация об образах
```bash
make docker-info
```
## Настройка registry
По умолчанию образы собираются с тегом `localhost:5000/имя:latest`. Для изменения registry:
```bash
make docker-build REGISTRY=my-registry.com
make docker-push REGISTRY=my-registry.com
```
## Использование в preset'ах
После сборки образов их можно использовать в preset'ах:
```yaml
# molecule/presets/my-preset.yml
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
alt: "localhost:5000/alt-linux:latest"
astra: "localhost:5000/astra-linux:latest"
redos: "localhost:5000/redos:latest"
hosts:
- name: alt-server
family: alt
groups: [servers]
- name: astra-server
family: astra
groups: [servers]
- name: redos-server
family: redos
groups: [servers]
```
## Лучшие практики
### 1. Версионирование образов
```bash
make docker-build VERSION=v1.0.0
```
### 2. Использование registry
```bash
make docker-push REGISTRY=my-registry.com VERSION=v1.0.0
```
### 3. Очистка старых образов
```bash
make docker-clean
```
## Troubleshooting
### Проблемы с сборкой
1. Проверьте доступность базовых образов
2. Убедитесь, что Docker запущен
3. Проверьте права доступа к Docker
### Проблемы с registry
1. Убедитесь, что registry доступен
2. Проверьте аутентификацию
3. Проверьте права на push
### Проблемы с образами
1. Проверьте размер образов
2. Убедитесь, что все зависимости установлены
3. Проверьте совместимость с базовыми образами
## Заключение
Эти Docker образы предоставляют готовую среду для тестирования Ansible ролей на различных операционных системах. Используйте их в своих preset'ах для создания универсальной системы тестирования.

View File

@@ -0,0 +1,48 @@
# AlmaLinux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM almalinux:8
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
jq \
python3 \
python3-pip \
&& dnf clean all
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,50 @@
# ALT Linux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM altlinux/p9
# Обновляем систему
RUN apt-get update && apt-get upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN apt-get install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
htop \
tree \
jq \
python3 \
python3-pip \
&& apt-get clean
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,89 @@
# Ansible Controller с предустановленными коллекциями
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM ubuntu:22.04
# Обновляем систему
RUN apt-get update && apt-get upgrade -y && apt-get clean
# Устанавливаем Python и Ansible
RUN apt-get install -y \
python3 \
python3-pip \
python3-venv \
python3-dev \
build-essential \
&& apt-get clean
# Устанавливаем Ansible
RUN pip3 install ansible ansible-core
# Устанавливаем дополнительные пакеты
RUN apt-get install -y \
curl \
wget \
git \
vim \
nano \
htop \
tree \
jq \
&& apt-get clean
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker CLI
RUN apt-get install -y docker.io docker-compose
# Устанавливаем kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/
# Устанавливаем Helm
RUN curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Устанавливаем Kind
RUN curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64 \
&& chmod +x ./kind \
&& mv ./kind /usr/local/bin/
# Устанавливаем Istio CLI
RUN curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.22.1 sh - \
&& mv istio-1.22.1/bin/istioctl /usr/local/bin/ \
&& rm -rf istio-1.22.1
# Копируем requirements.yml
COPY requirements.yml /tmp/requirements.yml
# Устанавливаем Ansible коллекции
RUN ansible-galaxy collection install -r /tmp/requirements.yml
# Создаем пользователя ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Создаем рабочую директорию
WORKDIR /ansible
# Устанавливаем права
RUN chown -R ansible:ansible /ansible
# Переключаемся на пользователя ansible
USER ansible
# Устанавливаем дополнительные роли
RUN ansible-galaxy install geerlingguy.docker \
&& ansible-galaxy install geerlingguy.kubernetes
# Настройки для работы с Docker
ENV DOCKER_HOST=unix:///var/run/docker.sock
ENV ANSIBLE_FORCE_COLOR=1
ENV ANSIBLE_STDOUT_CALLBACK=yaml
ENV ANSIBLE_CALLBACKS_ENABLED=profile_tasks
# Команда по умолчанию
CMD ["sleep", "infinity"]

View File

@@ -0,0 +1,23 @@
version: "3.9"
services:
ansible-controller:
build:
context: .
dockerfile: Dockerfile
container_name: ansible-controller
privileged: true
command: sleep infinity
environment:
DOCKER_HOST: unix:///var/run/docker.sock
ANSIBLE_VAULT_PASSWORD_FILE: /ansible/vault-password.txt
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- .:/ansible
working_dir: /ansible
networks:
- labnet
networks:
labnet:
external: true

View File

@@ -0,0 +1,9 @@
---
# Ansible Collections для Molecule Universal
collections:
- name: community.docker
version: ">=3.0.0"
- name: community.general
version: ">=7.0.0"
- name: ansible.posix
version: ">=1.5.4"

View File

@@ -0,0 +1,50 @@
# Astra Linux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM astralinux/astra-1.7
# Обновляем систему
RUN apt-get update && apt-get upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN apt-get install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
htop \
tree \
jq \
python3 \
python3-pip \
&& apt-get clean
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,48 @@
# CentOS с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM quay.io/centos/centos:stream8
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
jq \
python3 \
python3-pip \
&& dnf clean all
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,50 @@
# RED OS с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM redos/redos:9
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
htop \
tree \
jq \
python3 \
python3-pip \
&& dnf clean all
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,48 @@
# RHEL с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM registry.access.redhat.com/ubi8/ubi
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
jq \
python3 \
python3-pip \
&& dnf clean all
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

View File

@@ -0,0 +1,48 @@
# Rocky Linux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
FROM rockylinux:8
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y \
systemd \
systemd-sysv \
dbus \
curl \
wget \
git \
vim \
nano \
jq \
python3 \
python3-pip \
&& dnf clean all
# Устанавливаем yq
RUN wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_arm64 \
&& chmod +x /usr/local/bin/yq
# Устанавливаем Docker
RUN curl -fsSL https://get.docker.com | sh
# Устанавливаем Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# Настраиваем systemd
RUN systemctl set-default multi-user.target
# Создаем пользователя для Ansible
RUN useradd -m -s /bin/bash ansible \
&& echo "ansible ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Переключаемся на пользователя ansible
USER ansible
WORKDIR /home/ansible
# Команда по умолчанию
CMD ["/sbin/init"]

424
docs/examples.md Normal file
View File

@@ -0,0 +1,424 @@
# Примеры использования универсальной системы тестирования
## Пример 1: Тестирование кластера etcd + PostgreSQL + Patroni
### Описание
Этот пример демонстрирует тестирование высокодоступного кластера PostgreSQL с Patroni и etcd.
### Preset: etcd-patroni
```yaml
# molecule/presets/etcd-patroni.yml
hosts:
# ETCD кластер (5 узлов для высокой доступности)
- name: etcd1
family: debian
groups: [etcd, cluster]
- name: etcd2
family: rhel
groups: [etcd, cluster]
- name: etcd3
family: debian
groups: [etcd, cluster]
- name: etcd4
family: rhel
groups: [etcd, cluster]
- name: etcd5
family: debian
groups: [etcd, cluster]
# Patroni кластер (3 узла PostgreSQL)
- name: patroni1
family: rhel
groups: [patroni, database, cluster]
- name: patroni2
family: debian
groups: [patroni, database, cluster]
- name: patroni3
family: rhel
groups: [patroni, database, cluster]
# HAProxy для балансировки
- name: haproxy
family: debian
groups: [haproxy, loadbalancer]
publish: ["5000:5000", "5001:5001"] # RW и RO порты
# DinD узел для тестирования Docker Compose внутри
- name: app-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080"]
```
### Запуск тестирования
```bash
# Информация о preset'е
make preset-info PRESET=etcd-patroni
# Тестирование с preset'ом
make preset-test PRESET=etcd-patroni
# Или через role test
make role test etcd-patroni
```
### Проверка результатов
```bash
# Проверить статус контейнеров
make container-info
# Проверить vault файлы
make vault-check
```
## Пример 2: Нагрузочное тестирование
### Описание
Этот пример демонстрирует тестирование под нагрузкой с множественными серверами и кэшем.
### Preset: performance
```yaml
# molecule/presets/performance.yml
hosts:
# Основные серверы (5 узлов)
- name: server1
family: debian
groups: [servers, web, app]
- name: server2
family: rhel
groups: [servers, web, app]
- name: server3
family: debian
groups: [servers, web, app]
- name: server4
family: rhel
groups: [servers, web, app]
- name: server5
family: debian
groups: [servers, web, app]
# База данных (3 узла)
- name: db1
family: rhel
groups: [database, db]
- name: db2
family: debian
groups: [database, db]
- name: db3
family: rhel
groups: [database, db]
# Кэш (3 узла Redis)
- name: cache1
family: debian
groups: [cache, redis]
- name: cache2
family: rhel
groups: [cache, redis]
- name: cache3
family: debian
groups: [cache, redis]
# Load balancer
- name: lb1
family: rhel
groups: [loadbalancer, haproxy]
publish: ["80:80", "443:443"]
# DinD узел для тестирования Docker Compose
- name: compose-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080", "8081:8081"]
```
### Запуск тестирования
```bash
# Тестирование с performance preset'ом
make role test performance
# Проверка статуса
make container-info
```
## Пример 3: Тестирование безопасности
### Описание
Этот пример демонстрирует тестирование в безопасной среде с bastion хостами и изоляцией.
### Preset: security
```yaml
# molecule/presets/security.yml
hosts:
# Bastion хосты (точки входа)
- name: bastion1
family: rhel
groups: [bastion, security, jump]
publish: ["2222:22"]
- name: bastion2
family: debian
groups: [bastion, security, jump]
publish: ["2223:22"]
# Внутренние серверы (без внешнего доступа)
- name: internal1
family: rhel
groups: [internal, servers, app]
- name: internal2
family: debian
groups: [internal, servers, app]
- name: internal3
family: rhel
groups: [internal, servers, app]
# База данных (изолированная сеть)
- name: db-secure1
family: rhel
groups: [database, secure, internal]
- name: db-secure2
family: debian
groups: [database, secure, internal]
# Мониторинг и логирование
- name: monitor1
family: debian
groups: [monitoring, security, logs]
- name: monitor2
family: rhel
groups: [monitoring, security, logs]
# Firewall и сетевые компоненты
- name: fw1
family: rhel
groups: [firewall, network, security]
- name: fw2
family: debian
groups: [firewall, network, security]
# DOoD узел для тестирования Docker безопасности
- name: docker-secure
type: dood
family: debian
groups: [docker, security, apps]
publish: ["8080:8080"]
env:
DOCKER_HOST: "unix:///var/run/docker.sock"
```
### Запуск тестирования
```bash
# Тестирование с security preset'ом
make role test security
# Проверка безопасности
make vault-check
make vault-scan
```
## Пример 4: Тестирование на разных ОС
### Описание
Этот пример демонстрирует тестирование на различных операционных системах.
### Preset: multi-os
```yaml
# molecule/presets/multi-os.yml
hosts:
# Debian/Ubuntu серверы
- name: ubuntu1
family: ubuntu
groups: [ubuntu, servers, web]
- name: debian1
family: debian
groups: [debian, servers, web]
- name: ubuntu2
family: ubuntu
groups: [ubuntu, servers, app]
- name: debian2
family: debian
groups: [debian, servers, app]
# RHEL/CentOS серверы
- name: rhel1
family: rhel
groups: [rhel, servers, web]
- name: centos1
family: centos
groups: [centos, servers, web]
- name: rhel2
family: rhel
groups: [rhel, servers, app]
- name: centos2
family: centos
groups: [centos, servers, app]
# База данных на разных ОС
- name: db-ubuntu
family: ubuntu
groups: [database, ubuntu, db]
- name: db-rhel
family: rhel
groups: [database, rhel, db]
# Load balancer
- name: lb-mixed
family: debian
groups: [loadbalancer, haproxy]
publish: ["80:80", "443:443"]
# DinD узел для тестирования Docker
- name: docker-mixed
type: dind
groups: [docker, apps]
publish: ["8080:8080"]
```
### Запуск тестирования
```bash
# Тестирование с multi-os preset'ом
make role test multi-os
# Проверка типов контейнеров
make container-types
```
## Пример 5: Создание собственного preset'а
### Описание
Этот пример демонстрирует создание собственного preset'а для специфических нужд.
### Создание preset'а
```bash
# Создать новый preset
cat > molecule/presets/my-custom.yml << 'EOF'
---
# Пресет для тестирования веб-приложения
# Автор: Ваше имя
# Сайт: https://your-site.com
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
# systemd-ready образы
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
# Описание кластера
hosts:
# Веб-серверы
- name: web1
family: debian
groups: [web, servers]
publish: ["80:80", "443:443"]
- name: web2
family: rhel
groups: [web, servers]
publish: ["8080:80", "8443:443"]
# База данных
- name: db1
family: rhel
groups: [database, db]
- name: db2
family: debian
groups: [database, db]
# Кэш
- name: cache1
family: debian
groups: [cache, redis]
# DinD узел для тестирования
- name: app-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080"]
EOF
```
### Использование preset'а
```bash
# Информация о preset'е
make preset-info PRESET=my-custom
# Тестирование с preset'ом
make preset-test PRESET=my-custom
# Или через role test
make role test my-custom
```
## Пример 6: Работа с Ansible Vault
### Создание vault файла
```bash
# Создать файл секретов
make vault create
# Ввести имя файла: secrets
# Ввести содержимое:
# ---
# database_password: "super_secret_password"
# api_key: "your_api_key_here"
# ssl_cert: "your_ssl_certificate"
```
### Использование в ролях
```yaml
# roles/my-role/tasks/main.yml
- name: Configure database
template:
src: database.conf.j2
dest: /etc/database.conf
vars:
db_password: "{{ database_password }}"
api_key: "{{ api_key }}"
```
### Проверка безопасности
```bash
# Проверить vault файлы
make vault-check
# Найти потенциальные секреты
make vault-scan
```
## Заключение
Эти примеры демонстрируют различные способы использования универсальной системы тестирования Ansible ролей. Вы можете:
1. Использовать готовые preset'ы для быстрого тестирования
2. Создавать собственные preset'ы для специфических нужд
3. Комбинировать различные типы контейнеров
4. Использовать Ansible Vault для безопасности
5. Тестировать на различных операционных системах
Для получения дополнительной информации используйте:
- `make help` - общая справка
- `make preset-list` - список preset'ов
- `make container-types` - типы контейнеров
- `make vault` - команды Vault

281
docs/universal-testing.md Normal file
View File

@@ -0,0 +1,281 @@
# Универсальная система тестирования Ansible ролей
## Обзор
Эта система предоставляет универсальную среду для тестирования и деплоя Ansible ролей с поддержкой различных типов контейнеров, автоматической генерации инвентаря и интеграции с Ansible Vault.
## Основные возможности
### 🐳 Типы контейнеров
#### Systemd контейнеры (по умолчанию)
- Полная поддержка systemd сервисов
- Работа как виртуальные машины
- Подходит для тестирования ролей
#### DinD (Docker-in-Docker)
- Изолированный Docker daemon
- Подходит для тестирования Docker Compose
- Полная изоляция от хостового Docker
#### DOoD (Docker-out-of-Docker)
- Доступ к хостовому Docker daemon
- Быстрое тестирование
- Подходит для CI/CD
### 📋 Preset'ы
#### etcd-patroni
- Кластер etcd (5 узлов)
- Кластер PostgreSQL с Patroni (3 узла)
- HAProxy для балансировки
- DinD узел для тестирования
#### performance
- 5 серверов приложений
- 3 узла базы данных
- 3 узла кэша Redis
- Load balancer
- DinD узел для тестирования
#### security
- Bastion хосты
- Внутренние серверы
- Изолированная база данных
- Мониторинг и логирование
- Firewall компоненты
- DOoD узел для тестирования
#### multi-os
- Тестирование на разных ОС
- Ubuntu, Debian, RHEL, CentOS
- Смешанные конфигурации
- DinD узел для тестирования
### 🔐 Ansible Vault интеграция
- Автоматическая расшифровка перед тестированием
- Безопасное хранение секретов
- Автоматическая повторная шифровка после тестирования
- Поддержка множественных vault'ов
## Использование
### Базовые команды
```bash
# Показать все preset'ы
make preset-list
# Информация о preset'е
make preset-info PRESET=etcd-patroni
# Тестирование с preset'ом
make preset-test PRESET=etcd-patroni
# Типы контейнеров
make container-types
# Информация о контейнерах
make container-info
# Проверка vault файлов
make vault-check
# Поиск секретов
make vault-scan
```
### Тестирование ролей
```bash
# С default preset
make role test
# С конкретным preset'ом
make role test etcd-patroni
make role test performance
make role test security
make role test multi-os
```
### Работа с Ansible Vault
```bash
# Создать файл секретов
make vault create
# Редактировать секреты
make vault edit
# Показать секреты
make vault show
# Зашифровать файл
make vault encrypt
# Расшифровать файл
make vault decrypt
```
## Структура проекта
```
.
├── molecule/
│ ├── default/
│ │ ├── create.yml # Создание контейнеров
│ │ ├── destroy.yml # Удаление контейнеров
│ │ ├── converge.yml # Запуск плейбуков
│ │ └── verify.yml # Проверка результатов
│ └── presets/
│ ├── etcd-patroni.yml
│ ├── performance.yml
│ ├── security.yml
│ └── multi-os.yml
├── files/
│ ├── requirements.yml
│ └── playbooks/
│ └── site.yml
├── vault/
│ └── secrets.yml
└── Makefile
```
## Создание собственных preset'ов
### Пример preset'а
```yaml
---
# Пресет для тестирования кластера etcd + PostgreSQL + Patroni
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
# systemd-ready образы
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
# Описание кластера
hosts:
# Systemd узлы
- name: server1
family: debian
groups: [servers, web]
publish: ["80:80"]
# DinD узел
- name: app-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080"]
# DOoD узел
- name: docker-secure
type: dood
family: debian
groups: [docker, security]
publish: ["8081:8081"]
env:
DOCKER_HOST: "unix:///var/run/docker.sock"
```
### Параметры хостов
- `name` - имя хоста
- `family` - семейство ОС (debian, rhel, ubuntu, centos)
- `type` - тип контейнера (dind, dood)
- `groups` - группы для инвентаря
- `publish` - порты для публикации
- `env` - переменные окружения
- `volumes` - дополнительные тома
- `capabilities` - дополнительные возможности
## Лучшие практики
### 1. Использование групп
```yaml
hosts:
- name: web1
groups: [web, servers, production]
- name: db1
groups: [database, servers, production]
```
### 2. Безопасность
```yaml
# Используйте Ansible Vault для секретов
vault_targets:
- /ansible/vault/secrets.yml
- /ansible/files/playbooks/group_vars/*/vault.yml
- /ansible/files/playbooks/host_vars/*/vault.yml
```
### 3. Тестирование
```yaml
# Проверяйте различные сценарии
- name: Test web servers
hosts: web
tasks:
- name: Check nginx status
systemd:
name: nginx
state: started
```
## Troubleshooting
### Проблемы с контейнерами
```bash
# Проверить статус контейнеров
make container-info
# Очистить Docker ресурсы
make docker clean
```
### Проблемы с Vault
```bash
# Проверить vault файлы
make vault-check
# Найти потенциальные секреты
make vault-scan
```
### Проблемы с preset'ами
```bash
# Показать все preset'ы
make preset-list
# Информация о preset'е
make preset-info PRESET=имя_пресета
```
## Заключение
Универсальная система тестирования Ansible ролей предоставляет мощные инструменты для тестирования ролей в различных сценариях. Используйте preset'ы для быстрого создания тестовых сред, различные типы контейнеров для изоляции и Ansible Vault для безопасности.
Для получения дополнительной информации используйте:
- `make help` - общая справка
- `make role` - команды для ролей
- `make molecule` - команды Molecule
- `make vault` - команды Vault

View File

@@ -2,51 +2,74 @@
- hosts: localhost - hosts: localhost
gather_facts: false gather_facts: false
vars: vars:
# Получаем preset из переменной окружения или используем default
preset_name: "{{ lookup('env', 'MOLECULE_PRESET') | default('default') }}"
preset_file: "/workspace/molecule/presets/{{ preset_name }}.yml"
# перечисли файлы/глобы, которые нужно временно расшифровать # перечисли файлы/глобы, которые нужно временно расшифровать
vault_targets: vault_targets:
- /ansible/vault/secrets.yml - /ansible/vault/secrets.yml
# добавляй сюда свои пути (host_vars/*/vault.yml, group_vars/*/vault.yml, и т.п.) - /ansible/files/playbooks/group_vars/*/vault.yml
- /ansible/files/playbooks/host_vars/*/vault.yml
- /ansible/roles/**/vars/vault.yml
tasks: tasks:
- name: Load preset configuration
include_vars: "{{ preset_file }}"
when: preset_file is file
ignore_errors: true
- name: Install collections - name: Install collections
community.docker.docker_container_exec: community.docker.docker_container_exec:
container: ansible-controller container: ansible-controller
command: bash -lc "ansible-galaxy collection install -r /ansible/requirements.yml --force --no-deps --upgrade >/dev/null 2>&1 || true" command: bash -lc "ansible-galaxy collection install -r /ansible/requirements.yml --force --no-deps --upgrade >/dev/null 2>&1 || true"
- name: Decrypt vault targets (best-effort) - name: Preflight vault — normalize state (encrypt if plaintext, then decrypt)
community.docker.docker_container_exec: community.docker.docker_container_exec:
container: ansible-controller container: ansible-controller
command: > command: >
bash -lc ' bash -lc '
set -euo pipefail; set -euo pipefail; shopt -s nullglob globstar;
for p in {{ vault_targets | map('quote') | join(' ') }}; do for p in {{ vault_targets | map('quote') | join(' ') }}; do
if [ -e "$p" ]; then for f in $p; do
echo "[vault] decrypt $p"; [ -f "$f" ] || continue;
ansible-vault decrypt --vault-password-file /ansible/vault-password.txt "$p" || true; if head -n1 "$f" | grep -q "^\$ANSIBLE_VAULT;"; then
echo "[vault] already encrypted: $f";
else
echo "[vault] plaintext -> encrypt: $f";
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault-password.txt "$f";
fi fi
echo "[vault] decrypt for run: $f";
ansible-vault decrypt --vault-password-file /ansible/vault-password.txt "$f";
done
done done
' '
- name: Run external playbook (your lab play) - name: Run lab playbook
community.docker.docker_container_exec: community.docker.docker_container_exec:
container: ansible-controller container: ansible-controller
command: > command: >
bash -lc " bash -lc "
ANSIBLE_ROLES_PATH=/ansible/roles ANSIBLE_ROLES_PATH=/ansible/roles
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/molecule/default/site.yml ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml
" "
- name: Re-encrypt vault targets (always) - name: Post-run — re-encrypt secrets
community.docker.docker_container_exec: community.docker.docker_container_exec:
container: ansible-controller container: ansible-controller
command: > command: >
bash -lc ' bash -lc '
set -euo pipefail; set -euo pipefail; shopt -s nullglob globstar;
for p in {{ vault_targets | map('quote') | join(' ') }}; do for p in {{ vault_targets | map('quote') | join(' ') }}; do
if [ -e "$p" ]; then for f in $p; do
echo "[vault] encrypt $p"; [ -f "$f" ] || continue;
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault-password.txt "$p" || true; if head -n1 "$f" | grep -q "^\$ANSIBLE_VAULT;"; then
echo "[vault] ok (encrypted): $f";
else
echo "[vault] encrypt back: $f";
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault-password.txt "$f" || true;
fi fi
done done
done
' '
ignore_errors: true ignore_errors: true

View File

@@ -11,6 +11,9 @@
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini" generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
images: images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy" debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
ubuntu: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
centos: "quay.io/centos/centos:stream9-systemd"
systemd_defaults: systemd_defaults:
privileged: true privileged: true
command: "/sbin/init" command: "/sbin/init"
@@ -24,72 +27,99 @@
groups: [test] groups: [test]
tasks: tasks:
- name: Install required collections
command: ansible-galaxy collection install -r /workspace/requirements.yml
delegate_to: localhost
ignore_errors: true
register: collections_install
changed_when: false
run_once: true
become: true
vars:
ansible_python_interpreter: /usr/bin/python3
environment:
ANSIBLE_COLLECTIONS_PATH: /usr/share/ansible/collections
- name: Load preset configuration - name: Load preset configuration
include_vars: "{{ preset_file }}" include_vars: "{{ preset_file }}"
when: preset_file is file when: preset_file is file
ignore_errors: true ignore_errors: true
- name: Ensure network exists - name: Ensure network exists
command: docker network create {{ docker_network }} community.docker.docker_network:
delegate_to: localhost name: "{{ docker_network }}"
ignore_errors: true state: present
# SYSTEMD nodes # SYSTEMD nodes
- name: Pull systemd images - name: Pull systemd images
command: docker pull {{ images[item.family] }} community.docker.docker_image:
delegate_to: localhost name: "{{ images[item.family] }}"
source: pull
loop: "{{ hosts | selectattr('type','undefined') | list }}" loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control: { label: "{{ item.name }}" } loop_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
- name: Start systemd nodes - name: Start systemd nodes
command: > community.docker.docker_container:
docker run -d --name {{ item.name }} name: "{{ item.name }}"
--network {{ docker_network }} image: "{{ images[item.family] }}"
--privileged={{ systemd_defaults.privileged | lower }} networks:
--tmpfs {{ (systemd_defaults.tmpfs | default([])) | join(' --tmpfs ') }} - name: "{{ docker_network }}"
--cap-add {{ (systemd_defaults.capabilities | default([])) | join(' --cap-add ') }} privileged: "{{ systemd_defaults.privileged }}"
{% for port in item.publish | default([]) %}--publish {{ port }} {% endfor %} command: "{{ systemd_defaults.command }}"
{% for key, value in item.env | default({}) | dictsort %}--env {{ key }}={{ value }} {% endfor %} volumes: "{{ systemd_defaults.volumes | default([]) + (item.volumes | default([])) }}"
{% for volume in (systemd_defaults.volumes | default([])) + (item.volumes | default([])) %}--volume {{ volume }} {% endfor %} tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
{{ images[item.family] }} {{ systemd_defaults.command }} capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
delegate_to: localhost published_ports: "{{ item.publish | default([]) }}"
environment: "{{ item.env | default({}) }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','undefined') | list }}" loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control: { label: "{{ item.name }}" } loop_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
# DinD nodes # DinD nodes
- name: Start DinD nodes (docker:27-dind) - name: Start DinD nodes (docker:27-dind)
command: > community.docker.docker_container:
docker run -d --name {{ item.name }} name: "{{ item.name }}"
--network {{ docker_network }} image: "docker:27-dind"
--privileged=true networks:
--env DOCKER_TLS_CERTDIR="" - name: "{{ docker_network }}"
{% for port in item.publish | default([]) %}--publish {{ port }} {% endfor %} privileged: true
--volume {{ item.name }}-docker:/var/lib/docker environment:
docker:27-dind DOCKER_TLS_CERTDIR: ""
delegate_to: localhost published_ports: "{{ item.publish | default([]) }}"
volumes: "{{ (item.volumes | default([])) + [item.name + '-docker:/var/lib/docker'] }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}" loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
loop_control: { label: "{{ item.name }}" } loop_control: { label: "{{ item.name }}" }
# DOoD nodes (mount docker.sock) # DOoD nodes (mount docker.sock)
- name: Start DOoD nodes (systemd + docker.sock mount) - name: Start DOoD nodes (systemd + docker.sock mount)
command: > community.docker.docker_container:
docker run -d --name {{ item.name }} name: "{{ item.name }}"
--network {{ docker_network }} image: "{{ images[item.family] }}"
--privileged={{ systemd_defaults.privileged | lower }} networks:
--tmpfs {{ (systemd_defaults.tmpfs | default([])) | join(' --tmpfs ') }} - name: "{{ docker_network }}"
--cap-add {{ (systemd_defaults.capabilities | default([])) | join(' --cap-add ') }} privileged: "{{ systemd_defaults.privileged }}"
{% for port in item.publish | default([]) %}--publish {{ port }} {% endfor %} command: "{{ systemd_defaults.command }}"
{% for key, value in item.env | default({}) | dictsort %}--env {{ key }}={{ value }} {% endfor %} volumes: "{{ (systemd_defaults.volumes | default([])) + ['/var/run/docker.sock:/var/run/docker.sock'] + (item.volumes | default([])) }}"
{% for volume in (systemd_defaults.volumes | default([])) + ['/var/run/docker.sock:/var/run/docker.sock'] + (item.volumes | default([])) %}--volume {{ volume }} {% endfor %} tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
{{ images[item.family] }} {{ systemd_defaults.command }} capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
delegate_to: localhost published_ports: "{{ item.publish | default([]) }}"
environment: "{{ item.env | default({}) }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}" loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
loop_control: { label: "{{ item.name }}" } loop_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
# Build groups map # Build groups map
- name: Build groups map - name: Initialize groups map
set_fact: set_fact:
groups_map: "{{ groups_map | default({}) }}" groups_map: {}
- name: Append hosts to groups - name: Append hosts to groups
set_fact: set_fact:
groups_map: "{{ groups_map | combine({ item_group: (groups_map[item_group] | default([])) + [item_name] }) }}" groups_map: "{{ groups_map | combine({ item_group: (groups_map[item_group] | default([])) + [item_name] }) }}"
@@ -123,3 +153,13 @@
dest: "{{ generated_inventory }}" dest: "{{ generated_inventory }}"
content: "{{ inv_content }}" content: "{{ inv_content }}"
mode: "0644" mode: "0644"
- name: Display inventory summary
debug:
msg: |
📋 Inventory Summary:
- Total hosts: {{ hosts | length }}
- Groups: {{ groups_map.keys() | list | join(', ') }}
- Systemd nodes: {{ hosts | selectattr('type','undefined') | list | length }}
- DinD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
- DOoD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list | length }}

View File

@@ -4,7 +4,7 @@
vars: vars:
# Получаем preset из переменной окружения или используем default # Получаем preset из переменной окружения или используем default
preset_name: "{{ lookup('env', 'MOLECULE_PRESET') | default('default') }}" preset_name: "{{ lookup('env', 'MOLECULE_PRESET') | default('default') }}"
preset_file: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') | default('/tmp') }}/../presets/{{ preset_name }}.yml" preset_file: "/workspace/molecule/presets/{{ preset_name }}.yml"
# Fallback значения если preset файл не найден # Fallback значения если preset файл не найден
docker_network: labnet docker_network: labnet
@@ -19,7 +19,7 @@
when: preset_file is file when: preset_file is file
ignore_errors: true ignore_errors: true
- name: Remove containers - name: Stop and remove containers
community.docker.docker_container: community.docker.docker_container:
name: "{{ item.name }}" name: "{{ item.name }}"
state: absent state: absent
@@ -36,8 +36,25 @@
loop_control: { label: "{{ item.name }}" } loop_control: { label: "{{ item.name }}" }
ignore_errors: true ignore_errors: true
- name: Remove custom volumes
community.docker.docker_volume:
name: "{{ item.volumes | default([]) | select('match', '^[^:]+$') | list }}"
state: absent
loop: "{{ hosts }}"
loop_control: { label: "{{ item.name }}" }
ignore_errors: true
when: item.volumes is defined
- name: Remove network - name: Remove network
community.docker.docker_network: community.docker.docker_network:
name: "{{ docker_network }}" name: "{{ docker_network }}"
state: absent state: absent
ignore_errors: true ignore_errors: true
- name: Display cleanup summary
debug:
msg: |
🧹 Cleanup Summary:
- Removed containers: {{ hosts | length }}
- Removed DinD volumes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
- Network: {{ docker_network }}

122
molecule/default/verify.yml Normal file
View File

@@ -0,0 +1,122 @@
---
- hosts: localhost
gather_facts: false
vars:
# Получаем preset из переменной окружения или используем default
preset_name: "{{ lookup('env', 'MOLECULE_PRESET') | default('default') }}"
preset_file: "/workspace/molecule/presets/{{ preset_name }}.yml"
# Fallback значения если preset файл не найден
docker_network: labnet
hosts:
- name: u1
family: debian
groups: [test]
tasks:
- name: Load preset configuration
include_vars: "{{ preset_file }}"
when: preset_file is file
ignore_errors: true
# Проверка systemd узлов
- name: Check systemd nodes status
community.docker.docker_container_exec:
container: "{{ item.name }}"
command: systemctl is-system-running
loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control: { label: "{{ item.name }}" }
register: systemd_status
ignore_errors: true
- name: Display systemd nodes status
debug:
msg: "Systemd node {{ item.0.name }}: {{ item.1.stdout | default('unknown') }}"
loop: "{{ systemd_status.results | default([]) }}"
when: systemd_status is defined
# Проверка DinD узлов
- name: Check DinD nodes docker daemon
community.docker.docker_container_exec:
container: "{{ item.name }}"
command: docker version --format '{{.Server.Version}}'
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
loop_control: { label: "{{ item.name }}" }
register: dind_status
ignore_errors: true
- name: Display DinD nodes status
debug:
msg: "DinD node {{ item.0.name }}: Docker {{ item.1.stdout | default('not running') }}"
loop: "{{ dind_status.results | default([]) }}"
when: dind_status is defined
# Проверка DOoD узлов
- name: Check DOoD nodes docker access
community.docker.docker_container_exec:
container: "{{ item.name }}"
command: docker ps --format '{{.Names}}'
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
loop_control: { label: "{{ item.name }}" }
register: dood_status
ignore_errors: true
- name: Display DOoD nodes status
debug:
msg: "DOoD node {{ item.0.name }}: Can access {{ item.1.stdout_lines | length | default(0) }} containers"
loop: "{{ dood_status.results | default([]) }}"
when: dood_status is defined
# Проверка сетевого подключения
- name: Test network connectivity between nodes
community.docker.docker_container_exec:
container: "{{ item.0.name }}"
command: ping -c 1 {{ item.1.name }}
loop: "{{ hosts | subelements(hosts, 'name') }}"
loop_control: { label: "{{ item.0.name }} -> {{ item.1.name }}" }
when: item.0.name != item.1.name
register: ping_results
ignore_errors: true
- name: Display network connectivity results
debug:
msg: "Network test {{ item.0.name }} -> {{ item.1.name }}: {{ 'OK' if item.2.rc == 0 else 'FAILED' }}"
loop: "{{ ping_results.results | default([]) }}"
when: ping_results is defined
# Проверка портов
- name: Check published ports
community.docker.docker_container_exec:
container: "{{ item.name }}"
command: netstat -tlnp
loop: "{{ hosts | selectattr('publish','defined') | list }}"
loop_control: { label: "{{ item.name }}" }
register: port_status
ignore_errors: true
- name: Display port status
debug:
msg: "Node {{ item.0.name }} ports: {{ item.1.stdout_lines | select('match', 'LISTEN') | list | length }} listening"
loop: "{{ port_status.results | default([]) }}"
when: port_status is defined
# Проверка групп
- name: Display inventory groups
debug:
msg: |
📋 Inventory Groups:
{% for group, members in (groups_map | default({}) | dictsort) %}
- {{ group }}: {{ members | join(', ') }}
{% endfor %}
# Финальная сводка
- name: Display verification summary
debug:
msg: |
✅ Verification Summary:
- Total hosts: {{ hosts | length }}
- Systemd nodes: {{ hosts | selectattr('type','undefined') | list | length }}
- DinD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
- DOoD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list | length }}
- Groups: {{ groups_map.keys() | list | join(', ') }}
- Network: {{ docker_network }}

View File

@@ -1,5 +1,5 @@
--- ---
# Стандартный пресет по умолчанию для тестирования #description: Стандартный пресет по умолчанию для тестирования с 2 хостами (Debian + RHEL)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru

View File

@@ -1,5 +1,5 @@
--- ---
# Пресет с Docker контейнерами #description: Пресет с Docker контейнерами (DinD + DOoD) для тестирования Docker-задач
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru

View File

@@ -0,0 +1,62 @@
---
#description: Пресет для тестирования кластера etcd + PostgreSQL + Patroni (9 хостов)
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
# systemd-ready образы
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
# Описание кластера etcd + Patroni + HAProxy
hosts:
# ETCD кластер (5 узлов для высокой доступности)
- name: etcd1
family: debian
groups: [etcd, cluster]
- name: etcd2
family: rhel
groups: [etcd, cluster]
- name: etcd3
family: debian
groups: [etcd, cluster]
- name: etcd4
family: rhel
groups: [etcd, cluster]
- name: etcd5
family: debian
groups: [etcd, cluster]
# Patroni кластер (3 узла PostgreSQL)
- name: patroni1
family: rhel
groups: [patroni, database, cluster]
- name: patroni2
family: debian
groups: [patroni, database, cluster]
- name: patroni3
family: rhel
groups: [patroni, database, cluster]
# HAProxy для балансировки
- name: haproxy
family: debian
groups: [haproxy, loadbalancer]
publish: ["5000:5000", "5001:5001"] # RW и RO порты
# DinD узел для тестирования Docker Compose внутри
- name: app-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080"]

View File

@@ -1,5 +1,5 @@
--- ---
# Минимальный пресет для быстрого тестирования #description: Минимальный пресет для быстрого тестирования с 1 хостом (Debian)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru

View File

@@ -0,0 +1,70 @@
---
#description: Пресет для тестирования на разных ОС с 12 хостами (Debian + RHEL)
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
# systemd-ready образы для разных ОС
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
# Описание кластера с разными ОС
hosts:
# Debian серверы
- name: debian1
family: debian
groups: [debian, servers, web]
- name: debian2
family: debian
groups: [debian, servers, web]
- name: debian3
family: debian
groups: [debian, servers, app]
- name: debian4
family: debian
groups: [debian, servers, app]
# RHEL серверы
- name: rhel1
family: rhel
groups: [rhel, servers, web]
- name: rhel2
family: rhel
groups: [rhel, servers, web]
- name: rhel3
family: rhel
groups: [rhel, servers, app]
- name: rhel4
family: rhel
groups: [rhel, servers, app]
# База данных на разных ОС
- name: db-debian
family: debian
groups: [database, debian, db]
- name: db-rhel
family: rhel
groups: [database, rhel, db]
# Load balancer
- name: lb-mixed
family: debian
groups: [loadbalancer, haproxy]
publish: ["80:80", "443:443"]
# DinD узел для тестирования Docker
- name: docker-mixed
type: dind
groups: [docker, apps]
publish: ["8080:8080"]

View File

@@ -1,5 +1,5 @@
--- ---
# Пресет для тестирования производительности #description: Пресет для нагрузочного тестирования с 12 хостами (серверы + БД + кэш)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru
@@ -19,20 +19,55 @@ systemd_defaults:
tmpfs: ["/run", "/run/lock"] tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"] capabilities: ["SYS_ADMIN"]
# Описание кластера для нагрузочного тестирования
hosts: hosts:
# Нагрузочное тестирование - 5 хостов # Основные серверы (5 узлов)
- name: perf1 - name: server1
family: debian family: debian
groups: [test, performance] groups: [servers, web, app]
- name: perf2 - name: server2
family: debian
groups: [test, performance]
- name: perf3
family: rhel family: rhel
groups: [test, performance] groups: [servers, web, app]
- name: perf4 - name: server3
family: rhel
groups: [test, performance]
- name: perf5
family: debian family: debian
groups: [test, performance] groups: [servers, web, app]
- name: server4
family: rhel
groups: [servers, web, app]
- name: server5
family: debian
groups: [servers, web, app]
# База данных (3 узла)
- name: db1
family: rhel
groups: [database, db]
- name: db2
family: debian
groups: [database, db]
- name: db3
family: rhel
groups: [database, db]
# Кэш (3 узла Redis)
- name: cache1
family: debian
groups: [cache, redis]
- name: cache2
family: rhel
groups: [cache, redis]
- name: cache3
family: debian
groups: [cache, redis]
# Load balancer
- name: lb1
family: rhel
groups: [loadbalancer, haproxy]
publish: ["80:80", "443:443"]
# DinD узел для тестирования Docker Compose
- name: compose-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080", "8081:8081"]

View File

@@ -1,5 +1,5 @@
--- ---
# Пресет для тестирования безопасности #description: Пресет для тестирования безопасности с 10 хостами (bastion + internal + monitoring)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru
@@ -19,14 +19,58 @@ systemd_defaults:
tmpfs: ["/run", "/run/lock"] tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"] capabilities: ["SYS_ADMIN"]
# Описание кластера для тестирования безопасности
hosts: hosts:
# Тестирование безопасности - 3 хоста с разными ОС # Bastion хосты (точки входа)
- name: sec1 - name: bastion1
family: debian
groups: [test, security, web]
- name: sec2
family: rhel family: rhel
groups: [test, security, db] groups: [bastion, security, jump]
- name: sec3 publish: ["2222:22"]
- name: bastion2
family: debian family: debian
groups: [test, security, api] groups: [bastion, security, jump]
publish: ["2223:22"]
# Внутренние серверы (без внешнего доступа)
- name: internal1
family: rhel
groups: [internal, servers, app]
- name: internal2
family: debian
groups: [internal, servers, app]
- name: internal3
family: rhel
groups: [internal, servers, app]
# База данных (изолированная сеть)
- name: db-secure1
family: rhel
groups: [database, secure, internal]
- name: db-secure2
family: debian
groups: [database, secure, internal]
# Мониторинг и логирование
- name: monitor1
family: debian
groups: [monitoring, security, logs]
- name: monitor2
family: rhel
groups: [monitoring, security, logs]
# Firewall и сетевые компоненты
- name: fw1
family: rhel
groups: [firewall, network, security]
- name: fw2
family: debian
groups: [firewall, network, security]
# DOoD узел для тестирования Docker безопасности
- name: docker-secure
type: dood
family: debian
groups: [docker, security, apps]
publish: ["8080:8080"]
env:
DOCKER_HOST: "unix:///var/run/docker.sock"

View File

@@ -1,5 +1,5 @@
--- ---
# Стандартный пресет для тестирования #description: Стандартный пресет для тестирования с 3 хостами (Debian + RHEL)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru

View File

@@ -1,5 +1,5 @@
--- ---
# Минимальный пресет для быстрого тестирования #description: Минимальный пресет для быстрого тестирования с 1 хостом (Debian)
# Автор: Сергей Антропов # Автор: Сергей Антропов
# Сайт: https://devops.org.ru # Сайт: https://devops.org.ru