Compare commits

..

17 Commits

Author SHA1 Message Date
Сергей Антропов
3caa0078e1 feat: оптимизирована команда docker clean-builder
- Добавлено удаление кеша builds в команду docker clean
- Оптимизирована команда docker clean-builder с таймаутами
- Добавлена принудительная остановка контейнеров builder'а
- Убрана проблемная проверка docker buildx inspect
- Добавлены таймауты 10 сек для docker buildx rm и prune
- Обновлена справка с описанием новых возможностей
- Команда теперь работает быстро и надежно
2025-10-25 15:00:46 +03:00
Сергей Антропов
2652d8376f feat: обновлен Docker registry на inecs/ansible-lab
- Изменен DOCKER_REGISTRY с inecs/ansible на inecs/ansible-lab
- Обновлен формат тегов с registry/image:tag на registry:image-tag
- Исправлены все команды docker (build, push, pull, clean, info)
- Улучшен вывод информации о сборке образов с четким выделением
- Все образы теперь будут собираться в публичный репозиторий inecs/ansible-lab
2025-10-25 14:38:40 +03:00
Сергей Антропов
7f6d9c9268 docs: Обновлена документация с командой docker rebuild
- Добавлена команда make docker rebuild в основную справку
- Обновлены примеры использования с новой командой
- Команда rebuild выполняет полную пересборку с очисткой кеша
- Полезно при проблемах с кешем или зависимостями

Новая команда:
- make docker rebuild - полная пересборка с очисткой кеша
- Выполняет: clean + clean-builder + setup-builder + build
- Собирает все образы с нуля без использования кеша
2025-10-25 14:11:36 +03:00
Сергей Антропов
bf02745769 fix: Исправлены ошибки в multi-arch сборке
- Исправлены вызовы несуществующих команд docker-setup-builder
- Заменены на правильные вызовы make docker setup-builder
- Упрощена функция docker-get-base-tag (убрана лишняя информация)
- Исправлен путь к requirements.yml в Dockerfile ansible-controller
- Убрана лишняя информация из вывода тегов

Исправления:
- make docker build теперь правильно вызывает setup-builder
- make controller build теперь правильно вызывает setup-builder
- docker-get-base-tag выводит только тег без лишней информации
- requirements.yml копируется из правильного пути

Теперь multi-arch сборка должна работать корректно.
2025-10-25 14:04:48 +03:00
Сергей Антропов
1b323827f6 docs: Обновлен общий help с новыми возможностями Multi-Arch
- Обновлена секция Docker образов с указанием Multi-Arch поддержки
- Добавлена новая секция Docker Builder с командами для работы с builder'ом
- Обновлена секция Controller с указанием Multi-Arch поддержки
- Добавлены новые примеры использования:
  * make docker setup-builder - настройка multi-arch builder
  * make docker build - собрать все образы (amd64 + arm64)
  * make controller build - собрать ansible-controller (multi-arch)
  * make docker clean-builder - очистка builder'а
- Указаны поддерживаемые архитектуры: amd64, arm64, riscv64, ppc64le, s390x, 386, arm/v7, arm/v6

Теперь help отражает все новые возможности:
- Multi-arch сборка для всех Docker образов
- Команды для управления multi-arch builder'ом
- Автоматическое извлечение тегов из базовых образов
- Поддержка множества архитектур
2025-10-25 14:02:20 +03:00
Сергей Антропов
85bb63dd82 refactor: Добавлена команда make docker setup-builder и удалена отдельная команда
- Добавлена команда setup-builder в секцию docker
- Удалена отдельная функция docker-setup-builder
- Обновлена справка с информацией о новой команде
- Исправлена синтаксическая ошибка в Makefile
- Добавлена пустая цель setup-builder для совместимости

Теперь доступны команды для работы с builder'ом:
- make docker setup-builder - настройка multi-arch builder
- make docker clean-builder - очистка multi-arch builder

Удаленная команда больше не работает:
- make docker-setup-builder -  No rule to make target

Это делает интерфейс более последовательным и понятным.
2025-10-25 13:59:47 +03:00
Сергей Антропов
89d39921f6 refactor: Удалена отдельная команда docker-clean-builder
- Удалена функция docker-clean-builder
- Убрано упоминание из справки
- Удалено из .PHONY списка
- Оставлена только команда make docker clean-builder в секции docker
- Упрощена структура команд

Теперь доступна только одна команда для очистки builder'а:
- make docker clean-builder - через секцию docker

Это делает интерфейс более последовательным и понятным.
2025-10-25 13:56:53 +03:00
Сергей Антропов
c2db58c356 feat: Добавлена команда make docker clean-builder
- Добавлена команда clean-builder в секцию docker
- Теперь доступны две команды для очистки builder'а:
  * make docker clean-builder - в секции docker
  * make docker-clean-builder - отдельная команда
- Обновлена справка с информацией о новой команде
- Добавлена пустая цель clean-builder для совместимости
- Команда безопасно удаляет multi-arch builder контейнер

Использование:
- make docker clean-builder - очистка builder'а через секцию docker
- make docker-clean-builder - очистка builder'а как отдельная команда
- Обе команды выполняют одинаковые действия
2025-10-25 13:56:00 +03:00
Сергей Антропов
8f5a9c955c fix: Исправлена настройка buildx для работы в контейнере
- Обновлена функция docker-setup-builder для работы в контейнере
- Добавлен флаг --bootstrap для автоматического запуска builder'а
- Добавлена проверка статуса builder'а после создания
- Добавлена функция docker-clean-builder для очистки builder'а
- Обновлена справка с информацией о новых функциях
- Builder теперь работает в контейнере, а не устанавливается в систему
- Поддержка всех платформ: linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Исправления:
- buildx теперь запускается в контейнере
- Автоматическая проверка статуса builder'а
- Возможность очистки и пересоздания builder'а
- Улучшенная диагностика проблем со сборкой
2025-10-25 13:54:40 +03:00
Сергей Антропов
91e7554d71 feat: Добавлена поддержка multi-arch сборки и автоматическое извлечение тегов
- Добавлена поддержка multi-arch сборки (amd64 и arm64) для всех Docker образов
- Реализовано автоматическое извлечение тегов из базовых образов
- Добавлены вспомогательные функции:
  * docker-setup-builder - настройка multi-arch builder
  * docker-get-base-tag - извлечение тегов из базовых образов
  * docker-build-image - сборка одного образа с multi-arch
- Обновлена сборка ansible-controller с поддержкой multi-arch
- Исправлен путь к requirements.yml для ansible-controller
- Обновлена справка с информацией о новых возможностях
- Все образы теперь автоматически отправляются в Docker Hub при сборке
- Поддержка платформ: linux/amd64,linux/arm64

Новые возможности:
- Автоматическое извлечение тегов из базовых образов
- Multi-arch сборка для всех образов
- Автоматическая отправка в Docker Hub
- Улучшенная справка с подробным описанием функций
2025-10-25 13:49:12 +03:00
Сергей Антропов
cef8290341 feat: Исправлены Docker образы и успешно собраны все 7 образов
- Исправлена установка Docker для Rocky Linux (заменен универсальный скрипт на ручную установку)
- Исправлена установка Docker для AlmaLinux (заменен универсальный скрипт на ручную установку)
- Исправлена установка Docker для ALT Linux (убраны несуществующие пакеты docker/docker-compose)
- Обновлен Makefile с улучшенной справкой и командами
- Все 7 Docker образов успешно собраны:
  * inecs/alt-linux:latest (804MB)
  * inecs/astra-linux:latest (1.06GB)
  * inecs/redos:latest (1.26GB)
  * inecs/centos:latest (1.07GB)
  * inecs/rhel:latest (1.01GB)
  * inecs/rocky:latest (1.32GB)
  * inecs/alma:latest (1.13GB)

Все образы содержат:
- Systemd для полноценного тестирования
- Docker для DinD/DOoD сценариев
- Python и pip для Ansible
- Пользователя ansible с sudo правами
- Все необходимые инструменты разработки

Проект готов к полноценному тестированию Ansible на различных ОС!
2025-10-25 13:46:35 +03:00
Сергей Антропов
646d1bbd00 feat: Переименование docker-cmd в docker и добавление команды purge
- Переименована секция docker-cmd в docker:
  * Обновлены все команды: make docker [действие]
  * Обновлена справка в основной help
  * Обновлены примеры использования
  * Обновлен .PHONY

- Добавлена команда make docker purge:
  * Полная очистка всех Docker данных
  * Останавливает все контейнеры
  * Удаляет все контейнеры, образы, тома, сети
  * Выполняет docker system prune -af --volumes
  * Требует подтверждение пользователя
  * Безопасная отмена при отказе

- Улучшена справка:
  * Добавлено предупреждение для команды purge
  * Обновлены все описания команд
  * Добавлена команда purge в пустые цели
2025-10-25 11:34:36 +03:00
Сергей Антропов
ee0e5b98a3 feat: Улучшена справка Makefile
- Расширена основная справка (make help):
  * Добавлена секция dockerfiles/ в структуру проекта
  * Подробные описания всех команд с примерами
  * Добавлены секции GIT и CONTROLLER
  * Добавлены практические примеры использования

- Улучшены детальные справки для всех команд:
  * role - добавлены примеры и требования
  * presets - подробные описания с примерами
  * vault - детальные описания всех операций
  * git - объяснение выполняемых действий
  * docker-cmd - подробная информация о каждом образе
  * controller - описание процесса сборки и запуска

- Добавлены эмодзи и структурирование:
  * Четкое разделение команд по категориям
  * Подсказки с 💡 для каждой команды
  * Примеры использования в реальных сценариях
2025-10-25 11:32:05 +03:00
Сергей Антропов
696e08aa35 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'ах
  * Добавлены пустые цели для совместимости
2025-10-25 11:29:37 +03:00
Сергей Антропов
60ee5e90a5 Обновление конфигурации Ansible: добавлены новые пресеты, улучшен Makefile, добавлена документация 2025-10-25 10:11:17 +03:00
c99df83bad Рефакторинг: вынес запуск ролей в отдельный файл deploy.yml
- Создан файл roles/deploy.yml с блоком запуска роли nginx
- Обновлен molecule/default/site.yml для импорта deploy.yml
- Улучшена модульность структуры проекта
- Автор: Сергей Антропов
2025-10-22 22:34:07 +03:00
0b981ca61e feat: Добавлена система пресетов для Molecule
- Создана система пресетов для быстрого переключения между конфигурациями
- Добавлены пресеты: minimal, standard, docker, cluster
- Обновлена структура проекта с папками cicd/, vault/, scripts/
- Упрощена система vault с функциональными секретами
- Добавлены скрипты для работы с пресетами
- Обновлен Makefile с командами для пресетов
- Удалены старые файлы и структуры

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-10-22 20:31:23 +03:00
92 changed files with 4399 additions and 7405 deletions

View File

@@ -4,8 +4,4 @@ skip_list:
- yaml[truthy]
- yaml[line-length]
- var-naming[no-role-prefix]
- 'ignore-errors'
exclude_paths:
- molecule/universal/
- files/playbooks/
- 'ignore-errors'

37
.gitignore vendored
View File

@@ -1,6 +1,10 @@
# ---> Ansible
*.retry
# ---> Vault (секретные файлы)
vault/.vault
vault/secrets/*.yml
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -171,36 +175,3 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# ---> Ansible Template Project Specific
# Vault password files
.vault
vault/.vault
vault-password.txt
# IDE directories
.cursor/
.idea/
.vscode/
# Project specific
.env
*.log
*.tmp
*.swp
*.swo
*~
# Docker
.docker/
# Reports and snapshots (keep structure but ignore content)
reports/*.html
reports/*.json
snapshots/*.tar.gz
snapshots/*.zip
# Temporary files
*.retry
*.backup
*.bak

57
Dockerfile Normal file
View File

@@ -0,0 +1,57 @@
# =============================================================================
# AnsibleTemplate - Dockerfile для тестирования
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# =============================================================================
FROM quay.io/ansible/creator-ee:latest
# Установка дополнительных зависимостей
USER root
# Обновление системы и установка необходимых пакетов
RUN dnf update -y && \
dnf install -y \
python3-pip \
git \
curl \
jq \
ca-certificates \
iproute2 \
iputils \
procps-ng \
net-tools \
sudo \
vim \
&& dnf clean all
# Установка Python пакетов
RUN pip3 install --upgrade pip && \
pip3 install \
ansible-lint \
molecule \
molecule-docker \
docker-compose
# Создание рабочей директории
WORKDIR /ansible
# Копирование файлов проекта
COPY . /ansible/
# Установка прав доступа
RUN chmod +x /ansible/scripts/*.sh 2>/dev/null || true
# Переключение на пользователя ansible
USER ansible
# Установка Ansible коллекций
RUN ansible-galaxy collection install -r requirements.yml --force
# Настройка переменных окружения
ENV ANSIBLE_FORCE_COLOR=1
ENV ANSIBLE_STDOUT_CALLBACK=yaml
ENV PYTHONUNBUFFERED=1
# Команда по умолчанию
CMD ["/bin/bash"]

2725
Makefile

File diff suppressed because it is too large Load Diff

347
Makefile.backup Normal file
View File

@@ -0,0 +1,347 @@
# =============================================================================
# AnsibleTemplate - Универсальная система тестирования Ansible ролей
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# =============================================================================
SHELL := /bin/bash
# =============================================================================
# ЦВЕТА ДЛЯ ВЫВОДА
# =============================================================================
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
# =============================================================================
# ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
# =============================================================================
PROJECT_NAME ?= ansible-template
VERSION ?= 0.1.0
AUTHOR ?= "Сергей Антропов"
SITE ?= "https://devops.org.ru"
DOCKER_IMAGE ?= quay.io/ansible/creator-ee:latest
CONTAINER_NAME ?= ansible-controller
.PHONY: role molecule vault git docker help
####################################################################################################
# Работа с ролями
####################################################################################################
role:
@case "$(word 2, $(MAKECMDGOALS))" in \
lint) \
clear; \
echo "$(BLUE)🔍 Проверка синтаксиса ролей ...$(RESET)"; \
echo ""; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace -e ANSIBLE_FORCE_COLOR=1 $(DOCKER_IMAGE) bash -c "ansible-lint roles/ --config-file .ansible-lint || true"; \
echo "$(GREEN)✅ Lint завершен$(RESET)";; \
test) \
clear; \
echo "$(PURPLE)🚀 Тестирование ролей ...$(RESET)"; \
PRESET="default"; \
# Получаем все аргументы после 'test' и берем первый как preset \
ARGS="$(filter-out test,$(MAKECMDGOALS))"; \
if [ -n "$$ARGS" ]; then \
PRESET="$$(echo $$ARGS | cut -d' ' -f1)"; \
fi; \
echo "$(CYAN)📋 Используется пресет: $(YELLOW)$$PRESET$(RESET)"; \
if [ ! -f "molecule/presets/$$PRESET.yml" ]; then \
echo "$(RED)❌ Ошибка: Пресет '$$PRESET' не найден!$(RESET)"; \
echo "$(YELLOW)💡 Доступные пресеты:$(RESET)"; \
ls -1 molecule/presets/*.yml 2>/dev/null | sed 's|molecule/presets/||g' | sed 's|\.yml||g' | sed 's/^/ - /' || echo " $(YELLOW)⚠️ Пресеты не найдены$(RESET)"; \
echo ""; \
echo "$(GREEN)💡 Использование:$(RESET)"; \
echo " $(BLUE)make role test$(RESET) - с default preset"; \
echo " $(BLUE)make role test [preset_name]$(RESET) - с любым preset"; \
echo " $(BLUE)make role test minimal$(RESET) - с minimal preset"; \
echo " $(BLUE)make role test standard$(RESET) - со standard preset"; \
echo " $(BLUE)make role test docker$(RESET) - с docker preset"; \
exit 1; \
fi; \
echo ""; \
docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \
-e ANSIBLE_FORCE_COLOR=1 \
-e MOLECULE_PRESET=$$PRESET \
$(DOCKER_IMAGE) \
bash -c "cd molecule/default && ansible-playbook -i localhost, site.yml --connection=local" || echo "$(GREEN)✅ Тестирование завершено$(RESET)";; \
presets) \
clear; \
echo "$(CYAN)📋 Доступные пресеты:$(RESET)"; \
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 " $(BLUE)📄 %s$(RESET) - %s $(GREEN)(%s хостов)$(RESET)\n" "$$preset_name" "$$preset_desc" "$$host_count"; \
preset_count=$$((preset_count + 1)); \
fi; \
done; \
if [ $$preset_count -eq 0 ]; then \
echo " $(YELLOW)⚠️ Пресеты не найдены$(RESET)"; \
fi; \
echo ""; \
echo "$(GREEN)💡 Использование:$(RESET)"; \
echo " $(BLUE)make role test$(RESET) - с default preset"; \
echo " $(BLUE)make role test [preset_name]$(RESET) - с любым preset"; \
echo " $(BLUE)make role test minimal$(RESET) - с minimal preset"; \
echo " $(BLUE)make role test standard$(RESET) - со standard preset"; \
echo " $(BLUE)make role test docker$(RESET) - с docker preset"; \
echo ""; \
echo "$(YELLOW)💡 Примеры:$(RESET)"; \
echo " $(BLUE)make role test$(RESET) # default preset"; \
echo " $(BLUE)make role test minimal$(RESET) # minimal preset"; \
echo " $(BLUE)make role test my-custom-preset$(RESET) # любой preset";; \
deploy) \
clear; \
echo "$(PURPLE)🚀 Развертывание ролей на реальные серверы...$(RESET)"; \
echo ""; \
echo "$(YELLOW)💡 Примеры использования:$(RESET)"; \
echo " $(GREEN)ansible-playbook -i inventory/hosts.ini deploy.yml$(RESET)"; \
echo " $(GREEN)ansible-playbook -i inventory/hosts.ini deploy.yml --limit web_servers$(RESET)"; \
echo " $(GREEN)ansible-playbook -i inventory/hosts.ini deploy.yml --check$(RESET)"; \
echo ""; \
echo "$(CYAN)📄 Доступные playbook:$(RESET)"; \
ls -la *.yml 2>/dev/null | grep -v molecule || echo " $(BLUE)📄 deploy.yml - основной playbook для развертывания$(RESET)";; \
*) \
clear; \
echo "$(CYAN)🎯 Доступные команды:$(RESET)"; \
echo ""; \
echo " $(BLUE)🔧 make role install$(RESET) - установить зависимости"; \
echo " $(BLUE)🔍 make role lint$(RESET) - проверить синтаксис ролей"; \
echo " $(PURPLE)🚀 make role test$(RESET) - протестировать роли (default preset)"; \
echo " $(PURPLE)🚀 make role test [preset]$(RESET) - протестировать с любым preset"; \
echo " $(PURPLE)🚀 make role test minimal$(RESET) - протестировать с minimal preset"; \
echo " $(PURPLE)🚀 make role test standard$(RESET) - протестировать со standard preset"; \
echo " $(PURPLE)🚀 make role test docker$(RESET) - протестировать с docker preset"; \
echo " $(CYAN)📋 make role presets$(RESET) - показать список preset'ов"; \
echo " $(PURPLE)🚀 make role deploy$(RESET) - развернуть роли";; \
esac
####################################################################################################
# Работа с Molecule Universal
####################################################################################################
molecule:
@case "$(word 2, $(MAKECMDGOALS))" in \
create) \
clear; \
echo "Создание тестового окружения ..."; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
bash -c "cd molecule/default && molecule create";; \
converge) \
clear; \
echo "Запуск плейбуков ..."; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
bash -c "cd molecule/default && molecule converge";; \
verify) \
clear; \
echo "Проверка результатов ..."; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
bash -c "cd molecule/default && molecule verify";; \
destroy) \
clear; \
echo "Удаление тестового окружения ..."; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
bash -c "cd molecule/default && molecule destroy";; \
test) \
clear; \
echo "Полный цикл тестирования ..."; \
docker run --rm -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
bash -c "cd molecule/default && molecule test";; \
*) \
clear; \
echo "Доступные команды:"; \
echo " make molecule create - создать окружение"; \
echo " make molecule converge - запустить плейбуки"; \
echo " make molecule verify - проверить результаты"; \
echo " make molecule destroy - удалить окружение"; \
echo " make molecule test - полный цикл тестирования"; \
;; \
esac
####################################################################################################
# Работа с Ansible Vault
####################################################################################################
vault:
@case "$(word 2, $(MAKECMDGOALS))" in \
show) \
clear; \
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) \
clear; \
echo "Создание файла секретов :"; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
ansible-vault create --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
edit) \
clear; \
echo "Доступные файлы секретов:"; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
ansible-vault edit --vault-password-file vault/.vault vault/$$FILE.yml;; \
delete) \
clear; \
echo "Доступные файлы секретов:"; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
rm -f vault/$$FILE.yml;; \
rekey) \
clear; \
echo "Доступные файлы секретов:"; \
ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \
echo ""; \
read -p "Введите имя файла (без .yml): " FILE; \
docker run --rm -it -v "$(PWD):/workspace" -w /workspace \
quay.io/ansible/creator-ee:latest \
ansible-vault rekey --vault-password-file vault/.vault vault/$$FILE.yml;; \
decrypt) \
clear; \
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 decrypt --vault-password-file vault/.vault vault/$$FILE.yml;; \
encrypt) \
clear; \
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 encrypt --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \
*) \
clear; \
echo "Доступные команды:"; \
echo " make vault create - создать файл секретов"; \
echo " make vault edit - редактировать секреты"; \
echo " make vault show - показать секреты"; \
echo " make vault delete - удалить секреты"; \
echo " make vault encrypt - зашифровать файл"; \
echo " make vault decrypt - расшифровать файл"; \
echo " make vault rekey - сменить пароль";; \
esac
####################################################################################################
# Работа с 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";; \
*) \
clear; \
echo "Доступные команды:"; \
echo " make git push - запушить изменения"; \
echo " make git pull - получить изменения"; \
echo " make git new - создать новую ветку";; \
esac
####################################################################################################
# Работа с Docker (упрощенная)
####################################################################################################
docker:
@case "$(word 2, $(MAKECMDGOALS))" in \
clean) \
clear; \
echo "$(RED)🧹 Очистка Docker ресурсов...$(RESET)"; \
docker system prune -f; \
docker volume prune -f; \
echo "$(GREEN)✅ Docker ресурсы очищены$(RESET)";; \
*) \
clear; \
echo "$(CYAN)🐳 Docker команды:$(RESET)"; \
echo ""; \
echo "$(RED)make docker clean$(RESET) - очистить Docker ресурсы"; \
echo ""; \
echo "$(YELLOW)💡 Основное тестирование через preset систему:$(RESET)"; \
echo " $(BLUE)make role test [preset]$(RESET) - универсальное тестирование"; \
echo " $(BLUE)make role presets$(RESET) - показать доступные preset'ы";; \
esac
####################################################################################################
# Справка
####################################################################################################
help:
@clear
@echo "=========================================="
@echo "AnsibleTemplate - Универсальная система"
@echo "тестирования Ansible ролей"
@echo "=========================================="
@echo ""
@echo "📁 Структура проекта:"
@echo " scripts/ - Скрипты автоматизации"
@echo " inventory/ - Инвентори файлы"
@echo " molecule/default/ - Molecule конфигурация"
@echo " roles/ - Ansible роли"
@echo " vault/ - Зашифрованные секреты"
@echo ""
@echo "🚀 Основные команды:"
@echo " make role install - установить зависимости"
@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 deploy - развернуть роли на серверы"
@echo " make docker clean - очистить Docker ресурсы"
@echo " make vault create - создать файл секретов"
@echo " make git new - создать новую ветку"
@echo ""
@echo "📖 Для подробной справки:"
@echo " make role - команды для ролей"
@echo " make molecule - команды Molecule"
@echo " make docker - команды Docker"
@echo " make vault - команды Vault"
@echo " make git - команды Git"
@echo "=========================================="
# Пустые цели для совместимости
view create edit show delete test lint deploy new advanced presets:
@true
# Динамические цели для всех возможных preset'ов
# Это позволяет использовать make role test [любой_preset] без ошибок
%:
@true

708
README.md
View File

@@ -1,556 +1,224 @@
# Ansible Template - Универсальная лаборатория для тестирования Ansible ролей
# AnsibleTemplate - Универсальная система тестирования Ansible ролей
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Ansible](https://img.shields.io/badge/Ansible-2.15+-blue.svg)](https://www.ansible.com/)
[![Molecule](https://img.shields.io/badge/Molecule-5.0+-green.svg)](https://molecule.readthedocs.io/)
[![Docker](https://img.shields.io/badge/Docker-20.0+-blue.svg)](https://www.docker.com/)
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## 📋 Описание
## 🚀 Описание
**Ansible Template** - это универсальная лаборатория для тестирования Ansible ролей в различных конфигурациях. Проект предоставляет гибкую и мощную среду для тестирования Ansible ролей, включая Docker-in-Docker (DinD), Docker-outside-of-Docker (DOoD), кластеры Kubernetes (Kind), Istio, Kiali, Prometheus и Grafana.
AnsibleTemplate - это универсальная система для тестирования Ansible ролей с использованием Docker и различных preset'ов конфигурации.
### 🎯 Основные возможности
## 🔧 Исправленные проблемы
- **🎯 Интерактивный интерфейс** - полноценный TUI с whiptail для удобного управления
- **🚀 Автоматическая инициализация** - настройка проекта при первом запуске
- **🧪 Универсальная лаборатория** - автоматическое развертывание Docker контейнеров и Kind кластеров
- **☸️ Kubernetes поддержка** - полноценные Kind кластеры с аддонами
- **📋 21 готовый пресет** - от простых до экстремально сложных сценариев
- **🎭 Управление ролями** - интерактивное создание и тестирование Ansible ролей
- **🔐 Безопасность vault** - автоматическое управление секретами
- **📊 Красивые отчеты** - HTML отчеты о результатах тестирования
- **🔧 CI/CD команды** - автоматизированное тестирование, линтинг и развертывание
- **📸 Снапшоты** - сохранение и восстановление состояния лаборатории
- **🌐 Service Mesh** - Istio с Kiali для визуализации
- **📈 Мониторинг** - Prometheus, Grafana для полной наблюдаемости
### 1. **Проблема с preset'ами в Makefile**
- **Исправлено**: Полностью универсальная система - любой preset без изменения Makefile
- **Добавлено**: Динамическое определение preset'ов через `filter-out` и `cut`
- **Улучшено**: Динамическая загрузка preset'ов через `include_vars` в Ansible
- **Добавлено**: Fallback значения и подробная справка при ошибках
## 🚀 Быстрый старт
### 2. **Дублирование файлов preset'ов**
-**Исправлено**: Создан уникальный `default.yml` preset с 2 хостами (Debian + RHEL)
-**Сохранено**: `minimal.yml` для быстрого тестирования с 1 хостом
-**Улучшено**: Различные конфигурации для разных сценариев тестирования
### Предварительные требования
### 3. **Проблемы с именами контейнеров**
-**Исправлено**: Унифицированы имена контейнеров (`ansible-controller`)
-**Обновлено**: Все файлы теперь используют одинаковые имена контейнеров
- Docker 20.0+
- Docker Compose 2.0+
- Make
- Git
### 4. **Проблемы с путями**
- **Исправлено**: Пути в `create.yml` и `destroy.yml` теперь используют `preset.yml`
- **Добавлено**: Fallback значения для случаев отсутствия preset файлов
- **Улучшено**: Более надежная работа с переменными
### Установка
```bash
# Клонировать репозиторий
git clone https://github.com/your-username/ansible-template.git
cd ansible-template
# Запустить проект (автоматическая инициализация)
make
# При первом запуске автоматически запустится интерактивная настройка:
# - Название проекта, версия, автор, сайт
# - Настройки Docker (образ, сеть)
# - Настройки лаборатории (сценарий, пресет)
# - Настройки Kubernetes (контекст, версии Istio/Kind)
# - Пути к папкам и файлам
# После настройки откроется главное меню
# Установить pre-commit хуки (опционально)
make pre-commit-install
```
### Первый запуск
```bash
# Инициализация проекта
make init
# Поднять контроллер
make lab up
# Запустить минимальную лабораторию
make lab test
# Посмотреть отчет
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 role playbook NAME=my-role # Управление playbooks роли
# Проверка всего проекта
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 # Очистить лабораторию
```
## 🎯 Новые возможности
### Интерактивный интерфейс
Проект теперь имеет полноценный TUI (Text User Interface) с whiptail:
```bash
# Главное меню (запускается автоматически)
make
# Интерактивные команды
make preset-create-interactive # Создание пресета через диалоги
make role-create-interactive # Создание роли через диалоги
```
### Автоматическая инициализация
При первом запуске проекта автоматически запускается интерактивная настройка:
- Настройка основных параметров проекта
- Конфигурация Docker и лаборатории
- Настройка Kubernetes и мониторинга
- Создание необходимых файлов и папок
### CI/CD команды
Полный набор команд для автоматизированного тестирования:
```bash
# Основные CI/CD команды
make ci-validate # Валидация проекта
make ci-lint # Проверка синтаксиса
make ci-test # Запуск тестов
make ci-deploy # Развертывание
make ci-security # Проверка безопасности
make ci-report # Генерация отчета
make ci-cleanup # Очистка после тестов
# Комбинированные команды
make ci-full # Полный цикл (lint + test + deploy)
make ci-all # Все проверки
```
### Управление ролями
Интерактивное создание и управление Ansible ролями:
- Автоматическое создание структуры роли
- Универсальные задачи для Debian и RHEL
- Создание handlers, defaults, meta файлов
- Интерактивная настройка параметров
## 📚 Документация
### Основные разделы
- **[Универсальная лаборатория](docs/universal-lab.md)** - полное руководство по работе с лабораторией
- **[Пресеты](docs/presets.md)** - описание всех 21 готового пресета
- **[Роли](docs/roles.md)** - структура и создание Ansible ролей
- **[CI/CD](ci-cd/README.md)** - настройка CI/CD для Ansible ролей
### Дополнительные материалы
- **[Примеры использования](docs/examples.md)** - практические примеры
- **[Troubleshooting](docs/troubleshooting.md)** - решение проблем
- **[API Reference](docs/api.md)** - справочник по API
## 🎛️ Пресеты
### Классические пресеты (systemd контейнеры)
| Пресет | Машины | Описание | Команда |
|--------|--------|----------|---------|
| `minimal.yml` | 1-3 | Базовая конфигурация | `make lab-test LAB_SPEC=molecule/presets/minimal.yml` |
| `webapp.yml` | 3-5 | Веб-приложение | `make lab-test LAB_SPEC=molecule/presets/webapp.yml` |
| `microservices.yml` | 5-8 | Микросервисы | `make lab-test LAB_SPEC=molecule/presets/microservices.yml` |
| `ha.yml` | 6-10 | Высокая доступность | `make lab-test LAB_SPEC=molecule/presets/ha.yml` |
| `k8s-cluster.yml` | 8-12 | Kubernetes кластер | `make lab-test LAB_SPEC=molecule/presets/k8s-cluster.yml` |
| `cicd.yml` | 10-15 | CI/CD пайплайн | `make lab-test LAB_SPEC=molecule/presets/cicd.yml` |
| `bigdata.yml` | 12-18 | Big Data кластер | `make lab-test LAB_SPEC=molecule/presets/bigdata.yml` |
| `servicemesh.yml` | 15-20 | Service Mesh | `make lab-test LAB_SPEC=molecule/presets/servicemesh.yml` |
| `enterprise.yml` | 18-20 | Enterprise | `make lab-test LAB_SPEC=molecule/presets/enterprise.yml` |
| `maximum.yml` | 20 | Максимальный | `make lab-test LAB_SPEC=molecule/presets/maximum.yml` |
### Kubernetes пресеты
| Пресет | Описание | Команда |
|--------|----------|---------|
| `k8s-single.yml` | Одиночный Kind кластер | `make lab-test LAB_SPEC=molecule/presets/k8s-single.yml` |
| `k8s-multi.yml` | Мульти-кластер (dev/staging/prod) | `make lab-test LAB_SPEC=molecule/presets/k8s-multi.yml` |
| `k8s-istio-full.yml` | Полный стек Istio | `make lab-test LAB_SPEC=molecule/presets/k8s-istio-full.yml` |
### Docker пресеты
| Пресет | Тип | Описание | Команда |
|--------|-----|----------|---------|
| `dind-simple.yml` | DinD | 3 изолированных Docker среды | `make lab-test LAB_SPEC=molecule/presets/dind-simple.yml` |
| `dind-swarm.yml` | DinD | Docker Swarm кластер | `make lab-test LAB_SPEC=molecule/presets/dind-swarm.yml` |
| `dind-compose.yml` | DinD | Docker Compose стеки | `make lab-test LAB_SPEC=molecule/presets/dind-compose.yml` |
| `dood-simple.yml` | DOoD | 3 DOoD контейнера | `make lab-test LAB_SPEC=molecule/presets/dood-simple.yml` |
| `dood-mixed.yml` | DOoD | Смешанная конфигурация | `make lab-test LAB_SPEC=molecule/presets/dood-mixed.yml` |
### Смешанные пресеты
| Пресет | Описание | Команда |
|--------|----------|---------|
| `mixed-k8s-dind.yml` | Kubernetes + DinD | `make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dind.yml` |
| `mixed-k8s-dood.yml` | Kubernetes + DOoD | `make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dood.yml` |
| `mixed-full.yml` | Полная гибридная конфигурация | `make lab-test LAB_SPEC=molecule/presets/mixed-full.yml` |
## 🛠️ Основные команды
### Управление лабораторией
```bash
# Поднять контроллер
make lab-up
# Погасить контроллер
make lab-down
# Полный цикл тестирования
make lab-test
# Создать инфраструктуру
make lab-create
# Запустить роли
make lab-converge
# Проверить работу
make lab-verify
# Уничтожить инфраструктуру
make lab-destroy
# Полный сброс
make lab-reset
```
### Снапшоты и восстановление
```bash
# Сохранить снапшот
make lab-snapshot
# Восстановить из снапшота
make lab-restore
# Очистить лабораторию
make lab-cleanup
```
### Kubernetes команды
```bash
# Войти в контейнер с kubectl
make kube-sh
# Выполнить kubectl команду
make kube-cmd CLUSTER=lab CMD="get pods -A"
# Войти в кластер
make kube-enter CLUSTER=lab
# Port-forward Kiali
make kiali-port-forward CLUSTER=lab
# Port-forward Istio Gateway
make istio-gw-port-forward CLUSTER=lab
# Port-forward Grafana
make grafana-port-forward CLUSTER=lab
# Port-forward Prometheus
make prom-port-forward CLUSTER=lab
# Остановить все port-forward
make kube-pf-stop
```
### Отчеты и мониторинг
```bash
# Сгенерировать HTML отчет
make lab-report
# Открыть Grafana
make grafana-open
# Получить URL Bookinfo
make bookinfo-url
```
## 🔧 Создание собственных пресетов
### Структура пресета
```yaml
---
# ПРЕСЕТ: Название (количество машин)
#
# Описание: Подробное описание пресета
#
# Использование: make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/your-preset.yml
#
# Автор: Ваше имя
# Сайт: https://your-site.com
docker_network: labnet
# Kind кластеры (опционально)
kind_clusters:
- name: your-cluster
workers: 2
api_port: 6443
addons:
ingress_nginx: true
metrics_server: true
istio: true
kiali: true
prometheus_stack: true
ingress_host_http_port: 8081
ingress_host_https_port: 8443
# Образы для разных семейств ОС
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
# Настройки по умолчанию для 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: host1
family: debian
group: webservers
publish:
- "8080:80"
- name: host2
type: dind
group: dind
publish:
- "2375:2375"
- name: host3
type: dood
family: rhel
group: dood
publish:
- "8081:80"
env:
DOCKER_HOST: "unix:///var/run/docker.sock"
```
### Типы хостов
- **systemd** - обычные контейнеры с systemd (по умолчанию)
- **dind** - Docker-in-Docker контейнеры
- **dood** - Docker-outside-of-Docker контейнеры
### Семейства ОС
- **debian** - Debian/Ubuntu системы
- **rhel** - RHEL/CentOS системы
### Группы хостов
Можно создавать любые группы для организации хостов:
```yaml
hosts:
- name: web1
group: webservers
- name: db1
group: databases
- name: cache1
group: caches
```
### Публикация портов
```yaml
publish:
- "8080:80" # HTTP
- "8443:443" # HTTPS
- "3306:3306" # MySQL
- "5432:5432" # PostgreSQL
```
### Переменные окружения
```yaml
env:
DOCKER_HOST: "unix:///var/run/docker.sock"
DATABASE_URL: "postgresql://user:pass@db:5432/mydb"
DEBUG: "true"
```
### 5. **Дополнительные улучшения**
-**Добавлено**: Универсальная Docker Compose конфигурация с поддержкой preset'ов
-**Создан**: Dockerfile для проекта
-**Добавлено**: Переменные окружения в `env.example`
-**Улучшено**: Расширенная справка и команды Docker
-**Добавлено**: Команды для работы с preset'ами через Docker Compose
## 📁 Структура проекта
```
ansible-template/
├── README.md # Основная документация
├── Makefile # Команды управления
├── docker-compose.yaml # Docker Compose конфигурация
├── vault-password.txt # Пароль для Ansible Vault
├── docs/ # Документация
├── universal-lab.md # Руководство по лаборатории
── presets.md # Описание пресетов
├── roles.md # Структура ролей
├── 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
│ │ ├── vars.yml # Переменные по умолчанию
│ │ ├── create.yml # Создание инфраструктуры
│ │ └── verify.yml # Проверка работы
│ └── presets/ # Готовые пресеты
│ ├── minimal.yml # Минимальная лаборатория
│ ├── webapp.yml # Веб-приложение
│ ├── k8s-single.yml # Kubernetes single
│ ├── dind-simple.yml # DinD simple
│ ├── dood-simple.yml # DOoD simple
│ └── ... # Другие пресеты
├── files/ # Файлы для ролей
│ ├── playbooks/ # Ansible playbooks
│ ├── k8s/ # Kubernetes манифесты
│ ├── grafana/ # Grafana дашборды
│ └── requirements.yml # Ansible коллекции
├── roles/ # Ansible роли
│ └── your_role/ # Ваши роли
├── scripts/ # Скрипты (запускаются через Docker)
│ ├── report_html.py # Генератор HTML отчетов
│ ├── snapshot.sh # Создание снапшотов
│ ├── restore.sh # Восстановление снапшотов
│ └── cleanup.sh # Очистка лаборатории
├── vault/ # Секреты и пароли
│ ├── .vault # Пароль для Ansible Vault
│ └── secrets.yml # Зашифрованные секреты
└── .pre-commit-config.yaml # Pre-commit конфигурация
AnsibleTemplate/
├── molecule/
│ ├── default/ # Molecule конфигурация
│ │ ├── create.yml # Создание тестовых контейнеров
│ │ ├── converge.yml # Запуск тестов
├── destroy.yml # Удаление контейнеров
│ └── site.yml # Основной playbook
── presets/ # Preset'ы конфигурации
├── default.yml # Стандартный preset (2 хоста)
├── minimal.yml # Минимальный preset (1 хост)
├── standard.yml # Расширенный preset (3 хоста)
└── docker.yml # Docker preset (DinD/DOoD)
├── roles/ # Ansible роли
├── vault/ # Зашифрованные секреты
├── inventory/ # Инвентори файлы
├── Makefile # Основные команды
── docker-compose.yml # Docker Compose конфигурация
├── Dockerfile # Docker образ
└── env.example # Переменные окружения
```
## 🤝 Участие в разработке
## 🚀 Использование
### Установка для разработки
### 🧪 Тестирование (Docker контейнеры)
```bash
# Клонировать репозиторий
git clone https://github.com/your-username/ansible-template.git
cd ansible-template
# Просмотр доступных preset'ов
make role presets
# Установить pre-commit хуки
make pre-commit-install
# Запустить тесты
make lab-test
# Тестирование с разными preset'ами
make role test # default preset
make role test minimal # minimal preset
make role test standard # standard preset
make role test docker # docker preset
make role test performance # performance preset
make role test security # security preset
make role test my-custom-preset # любой custom preset
```
### Создание нового пресета
**Особенности тестирования:**
- Использует Docker контейнеры для изоляции
- Динамический inventory создается из preset файлов
- Временные контейнеры (u1, u2, u3, ...)
- Автоматическая очистка после тестов
1. Создать файл в `molecule/presets/your-preset.yml`
2. Добавить описание в `docs/presets.md`
3. Протестировать: `make lab-test LAB_SPEC=molecule/presets/your-preset.yml`
4. Создать Pull Request
### 🚀 Развертывание (Реальные серверы)
### Создание новой роли
```bash
# Развертывание на реальные серверы
make role deploy # развертывание ролей
```
1. Создать структуру роли в `roles/your-role/`
2. Добавить описание в `docs/roles.md`
3. Протестировать с подходящим пресетом
4. Создать Pull Request
**Особенности развертывания:**
- Использует статический `inventory/hosts.ini`
- Подключение по SSH к реальным серверам
- Dry-run проверка перед развертыванием
- Подтверждение пользователя
## 📄 Лицензия
### 🔧 Вспомогательные команды
Этот проект распространяется под лицензией MIT. См. файл [LICENSE](LICENSE) для подробностей.
```bash
# Docker команды
make docker clean # очистить Docker ресурсы
## 👥 Авторы
# Другие команды
make role lint # проверка синтаксиса
make vault create # создание секретов
make help # полная справка
```
- **Сергей Антропов** - *Основной разработчик* - [devops.org.ru](https://devops.org.ru)
### Preset'ы конфигурации
## 🙏 Благодарности
| Preset | Описание | Хосты | Использование |
|--------|----------|-------|---------------|
| `default` | Стандартный preset | 2 хоста (Debian + RHEL) | Базовое тестирование |
| `minimal` | Минимальный preset | 1 хост (Debian) | Быстрое тестирование |
| `standard` | Расширенный preset | 3 хоста (Debian + RHEL + Debian) | Полное тестирование |
| `docker` | Docker preset | DinD + DOoD узлы | Тестирование Docker функциональности |
| `performance` | Performance preset | 5 хостов (Debian + RHEL) | Нагрузочное тестирование |
| `security` | Security preset | 3 хоста (Debian + RHEL) | Тестирование безопасности |
| `[custom]` | Любой custom preset | Любое количество | Пользовательские сценарии |
- [Ansible](https://www.ansible.com/) - за отличный инструмент автоматизации
- [Molecule](https://molecule.readthedocs.io/) - за фреймворк тестирования
- [Docker](https://www.docker.com/) - за контейнеризацию
- [Kubernetes](https://kubernetes.io/) - за оркестрацию
- [Istio](https://istio.io/) - за service mesh
## 🔧 Технические детали
### Исправления в Makefile
1. **Универсальное определение preset'а**:
```bash
ARGS="$(filter-out test,$(MAKECMDGOALS))"
PRESET="$$(echo $$ARGS | cut -d' ' -f1)"
```
2. **Проверка существования preset'ов с подробной справкой**:
```bash
if [ ! -f "molecule/presets/$$PRESET.yml" ]; then
echo "❌ Ошибка: Пресет '$PRESET' не найден!"
# Показать доступные preset'ы и примеры использования
fi
```
3. **Динамическая загрузка в Ansible**:
```yaml
- name: Load preset configuration
include_vars: "{{ preset_file }}"
when: preset_file is file
ignore_errors: true
```
4. **Поддержка любых preset'ов без изменения Makefile**:
```makefile
# Динамические цели для всех возможных preset'ов
%:
@true
```
### Fallback значения
Добавлены fallback значения в `create.yml` и `destroy.yml` для случаев отсутствия preset файлов:
```yaml
vars:
# Fallback значения если preset.yml не найден
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
# ... остальные значения
```
## 🐳 Docker поддержка
### Упрощенная архитектура
Docker-compose удален из проекта, так как он избыточен при наличии универсальной системы preset'ов. Все тестирование происходит через preset систему:
```bash
# Основное тестирование через preset систему
make role test [любой_preset] # универсальное тестирование
make role presets # показать доступные preset'ы
# Очистка Docker ресурсов
make docker clean # очистить Docker ресурсы
```
**Преимущества упрощенной архитектуры:**
- ✅ **Простота**: Один способ тестирования через preset систему
- ✅ **Универсальность**: Любой preset без дополнительной конфигурации
- ✅ **Автономность**: Preset система сама управляет контейнерами
- ✅ **Меньше сложности**: Нет дублирования функциональности
## 📝 Переменные окружения
Скопируйте `env.example` в `.env` и настройте под свои нужды:
```bash
cp env.example .env
```
## 🎯 Результат
Теперь система тестирования работает корректно:
1. ✅ **Полностью универсальная система preset'ов - любой preset без изменения Makefile**
2. ✅ **Динамическое определение preset'ов через `filter-out` и `cut`**
3. ✅ **Проверка существования preset'ов с подробной справкой**
4. ✅ **Унифицированные имена контейнеров**
5. ✅ **Надежные fallback значения**
6. ✅ **Упрощенная архитектура без docker-compose**
7. ✅ **Поддержка неограниченного количества custom preset'ов**
8. ✅ **Автономная preset система сама управляет контейнерами**
9. ✅ **Подробная документация и справка**
## 📞 Поддержка
- **Документация**: [docs/](docs/)
- **Issues**: [GitHub Issues](https://github.com/your-username/ansible-template/issues)
- **Discussions**: [GitHub Discussions](https://github.com/your-username/ansible-template/discussions)
- **Сайт**: [devops.org.ru](https://devops.org.ru)
При возникновении проблем:
1. Проверьте наличие Docker и Docker Compose
2. Убедитесь, что все preset файлы существуют
3. Используйте `make help` для справки
4. Проверьте логи: `make docker shell` и `docker logs ansible-controller`
---
**Сделано с ❤️ для сообщества DevOps**
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru

View File

@@ -1,6 +1,6 @@
[defaults]
inventory = inventory/hosts
vault_password_file = vault-password.txt
inventory = inventory/hosts.ini
# vault_password_file = vault/.vault
remote_user = devops
host_key_checking = False
enable_plugins = yaml, ini

View File

@@ -1,89 +0,0 @@
stages:
- lint
- test
- deploy
- notify
services:
- name: docker:dind
command: ["--tls=false"]
variables:
DOCKER_IMAGE: "hub.cism-ms.ru/ansible/ansible:latest"
DOCKER_TLS_CERTDIR: ""
ANSIBLE_FORCE_COLOR: "true"
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login hub.cism-ms.ru -u "$CI_REGISTRY_USER" --password-stdin
- docker pull $DOCKER_IMAGE
- echo "Fixing directory permissions..."
- chmod o-w $CI_PROJECT_DIR
lint:
stage: lint
script:
- echo "Начинаем стейдж Lint"
- echo "Распаковываем секреты..."
- ansible-vault decrypt vars/secrets.yml --vault-password-file ./vault-password.txt
- echo "Запускаем ansible-lint..."
- ansible-lint roles/*
- echo "Упаковываем секреты..."
- ansible-vault encrypt vars/secrets.yml --encrypt-vault-id default --vault-password-file ./vault-password.txt
allow_failure: false
rules:
- if: $CI_COMMIT_REF_NAME != "main" && $CI_COMMIT_REF_NAME != "master"
test:
stage: test
script:
- echo "Распаковываем секреты..."
- ansible-vault decrypt --vault-password-file ./vault-password.txt vars/secrets.yml
- echo "Запускаем тесты через Молекулу..."
- molecule test --parallel --destroy=always
- echo "Упаковываем секреты..."
- ansible-vault encrypt vars/secrets.yml --encrypt-vault-id default --vault-password-file ./vault-password.txt
allow_failure: false
rules:
- if: $CI_COMMIT_REF_NAME != "main" && $CI_COMMIT_REF_NAME != "master"
deploy:
stage: deploy
script:
- echo "Настраиваем SSH-ключ для доступа к серверам..."
# Создаем директорию .ssh и настраиваем права доступа
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
# Записываем SSH-ключ в файл ~/.ssh/id_rsa
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
# Запускаем основной пайплайн
- echo "Распаковываем секреты..."
- ansible-vault decrypt --vault-password-file ./vault-password.txt vars/secrets.yml
- echo "Все ок. Деплоим в прод..."
- ansible-playbook roles/deploy.yaml
- echo "Упаковываем секреты..."
- ansible-vault encrypt vars/secrets.yml --encrypt-vault-id default --vault-password-file ./vault-password.txt
# Удаляем ключ
- rm -rf ~/.ssh
rules:
- if: $CI_COMMIT_REF_NAME != "main" && $CI_COMMIT_REF_NAME != "master"
when: manual
notify:
stage: notify
script:
- |
if [ "$CI_JOB_STATUS" == "success" ]; then
MESSAGE="✅ Пайплайн успешно завершен!%0AПроект: $CI_PROJECT_NAME%0AВетка: $CI_COMMIT_REF_NAME%0AСтатус: $CI_JOB_STATUS"
else
MESSAGE="❌ Пайплайн завершен с ошибкой!%0AПроект: $CI_PROJECT_NAME%0AВетка: $CI_COMMIT_REF_NAME%0AСтатус: $CI_JOB_STATUS"
fi
# curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
# -d "chat_id=$TELEGRAM_CHAT_ID" \
# -d "text=$MESSAGE"
rules:
- if: $CI_JOB_STATUS # Отправлять уведомление только после завершения пайплайна
after_script:
- echo "Работа пайплайна завершена"

View File

@@ -1,123 +0,0 @@
# 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

View File

@@ -1,40 +0,0 @@
# Используем готовый образ с Ansible
FROM geerlingguy/docker-ubuntu2204-ansible:latest
# Добавляем метаданные
LABEL maintainer="Сергей Антропов <sergey@antropoff.ru>"
LABEL description="Этот Dockerfile создан для внедрения подхода IaC в Ansible."
LABEL version="0.1"
LABEL contact.website="https://devops.org.ru"
# Устанавливаем переменные окружения
ENV PYTHONUNBUFFERED=1
ENV EDITOR=nano
# Устанавливаем дополнительные зависимости Python для Molecule
RUN pip install --upgrade pip && \
pip install \
molecule \
molecule-docker \
ansible-lint \
yamllint \
docker \
&& rm -rf /root/.cache/pip
# Создаем рабочую директорию
WORKDIR /ansible
# Копируем файлы проекта
COPY . /ansible/
# Устанавливаем права на выполнение (если папка scripts существует)
RUN if [ -d /ansible/scripts ]; then chmod +x /ansible/scripts/*.sh; fi
# Устанавливаем пользователя
USER root
# Открываем порт для SSH
EXPOSE 22
# Команда по умолчанию
CMD ["/bin/bash"]

View File

@@ -1,54 +0,0 @@
# Сборка контейнера с systemd для удобного тестирования ролей Ansible через Molecule
# Используем официальный образ Fedora
FROM quay.io/fedora/python-312
USER root
# Обновляем пакеты и устанавливаем systemd и необходимые пакеты
RUN dnf update -y && \
dnf install -y --nodocs --setopt=install_weak_deps=False \
systemd rsync \
git \
openssh \
gcc \
libffi-devel \
openssl-devel \
make \
sudo \
openssh-clients \
less \
ca-certificates \
curl \
gnupg2 \
nano \
sshpass \
redhat-lsb-core \
&& dnf clean all && \
rm -rf /var/cache/dnf /tmp/* /var/tmp/*
# Устанавливаем 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
# Устанавливаем Python пакеты для Ansible
RUN pip install --upgrade pip && \
pip install \
ansible \
ansible-vault \
molecule \
molecule-docker \
ansible-lint \
yamllint \
docker \
&& rm -rf /root/.cache/pip
# Настраиваем окружение для systemd
ENV container=docker
STOPSIGNAL SIGRTMIN+3
# Создаем необходимые директории для systemd
VOLUME [ "/sys/fs/cgroup" ]
# Запускаем systemd при старте контейнера
CMD ["/sbin/init"]

View File

@@ -1,62 +0,0 @@
# Сборка контейнера с systemd для удобного тестирования ролей Ansible через Molecule
# Используем готовый образ с Ansible (более старый, но стабильный)
FROM geerlingguy/docker-ubuntu2004-ansible:latest
# Устанавливаем переменные окружения
ENV DEBIAN_FRONTEND=noninteractive
ENV container=docker
# Устанавливаем дополнительные пакеты для тестирования
RUN apt-get update && \
apt-get install -y --no-install-recommends \
systemd \
systemd-sysv \
rsync \
git \
ssh \
gcc \
libffi-dev \
libssl-dev \
make \
sudo \
sshpass \
openssh-client \
nano \
less \
ca-certificates \
curl \
gnupg \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# Устанавливаем Python пакеты для Ansible с обновлением зависимостей
RUN pip install --upgrade pip && \
pip install --upgrade \
requests \
PyYAML \
ansible-core \
&& pip install \
ansible \
"ansible-vault<4.0.0" \
molecule \
molecule-docker \
ansible-lint \
yamllint \
docker \
&& rm -rf /root/.cache/pip
# Устанавливаем 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 в качестве init-системы
ENV container=docker
STOPSIGNAL SIGRTMIN+3
# Создаем необходимые директории для systemd
VOLUME [ "/sys/fs/cgroup" ]
# Запускаем systemd при старте контейнера
CMD ["/sbin/init"]

51
cicd/.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,51 @@
# GitLab CI для AnsibleTemplate
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
stages:
- test
- deploy
variables:
DOCKER_IMAGE: "quay.io/ansible/creator-ee:latest"
DOCKER_TLS_CERTDIR: ""
ANSIBLE_FORCE_COLOR: "true"
before_script:
- echo "Установка зависимостей..."
- pip install molecule[docker] ansible-lint
- ansible-galaxy collection install -r requirements.yml
# Тестирование с Molecule
test:
stage: test
image: $DOCKER_IMAGE
services:
- docker:dind
variables:
DOCKER_TLS_CERTDIR: ""
script:
- echo "Запуск тестов Molecule..."
- cd molecule/universal
- molecule test -s universal
artifacts:
reports:
junit: molecule/universal/.molecule/reports/junit.xml
paths:
- molecule/universal/.molecule/
expire_in: 1 week
only:
- merge_requests
- main
- develop
# Деплой (если нужен)
deploy:
stage: deploy
image: $DOCKER_IMAGE
script:
- echo "Деплой не настроен"
- echo "Добавьте логику деплоя в этот job"
when: manual
only:
- main

View File

@@ -0,0 +1,53 @@
# Azure DevOps Pipeline для AnsibleTemplate
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
trigger:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
variables:
ANSIBLE_FORCE_COLOR: 'true'
DOCKER_TLS_CERTDIR: ''
stages:
- stage: Test
displayName: 'Test Stage'
jobs:
- job: TestJob
displayName: 'Run Tests'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.11'
displayName: 'Use Python 3.11'
- script: |
pip install --upgrade pip
pip install molecule[docker] ansible-lint
ansible-galaxy collection install -r requirements.yml
displayName: 'Install Dependencies'
- script: |
ansible-lint molecule/universal/
displayName: 'Run Ansible Lint'
- script: |
cd molecule/universal
molecule test -s universal
displayName: 'Run Molecule Tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'molecule/universal/.molecule/reports/junit.xml'
testRunTitle: 'Molecule Test Results'
condition: always()
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: 'molecule/universal/.molecule'
artifactName: 'molecule-reports'
condition: always()

70
cicd/github/workflows.yml Normal file
View File

@@ -0,0 +1,70 @@
# GitHub Actions Workflow для AnsibleTemplate
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
name: Ansible Testing
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl start docker
sudo usermod -aG docker $USER
- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install molecule[docker] ansible-lint
ansible-galaxy collection install -r requirements.yml
- name: Run Molecule tests
run: |
cd molecule/universal
molecule test -s universal
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: molecule-reports
path: molecule/universal/.molecule/
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install ansible-lint
ansible-galaxy collection install -r requirements.yml
- name: Run Ansible Lint
run: |
ansible-lint molecule/universal/

59
cicd/jenkins/Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,59 @@
// Jenkins Pipeline для AnsibleTemplate
// Автор: Сергей Антропов
// Сайт: https://devops.org.ru
pipeline {
agent any
environment {
ANSIBLE_FORCE_COLOR = 'true'
DOCKER_TLS_CERTDIR = ''
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Dependencies') {
steps {
sh '''
pip install --upgrade pip
pip install molecule[docker] ansible-lint
ansible-galaxy collection install -r requirements.yml
'''
}
}
stage('Lint') {
steps {
sh 'ansible-lint molecule/universal/'
}
}
stage('Test') {
steps {
dir('molecule/universal') {
sh 'molecule test -s universal'
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'molecule/universal/.molecule/**/*', allowEmptyArchive: true
publishTestResults testResultsPattern: 'molecule/universal/.molecule/reports/junit.xml'
}
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed!'
}
}
}

View File

@@ -1,138 +0,0 @@
#!/bin/bash
# Исправленная команда создания роли
ROLE_NAME="$1"
ROLE_DESC="$2"
ROLE_PACKAGE="$3"
ROLE_SERVICE="$4"
ROLE_TAGS="$5"
if [ -z "$ROLE_NAME" ]; then
echo "Использование: $0 ROLE_NAME ROLE_DESC ROLE_PACKAGE ROLE_SERVICE ROLE_TAGS"
exit 1
fi
echo "Создание роли: $ROLE_NAME"
mkdir -p ./roles/${ROLE_NAME}/{tasks,handlers,templates,files,vars,defaults,meta,tests,playbooks}
# Создаем main.yml
cat > ./roles/${ROLE_NAME}/tasks/main.yml << 'MAIN_EOF'
---
# Основные задачи роли ROLE_NAME_PLACEHOLDER
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Включить задачи для Debian/Ubuntu
import_tasks: debian.yml
when: ansible_os_family == 'Debian'
- name: Включить задачи для RHEL/CentOS
import_tasks: redhat.yml
when: ansible_os_family == 'RedHat'
MAIN_EOF
# Создаем debian.yml
cat > ./roles/${ROLE_NAME}/tasks/debian.yml << 'DEBIAN_EOF'
---
# Задачи для Debian/Ubuntu
- name: Обновить кэш пакетов
apt:
update_cache: yes
cache_valid_time: 3600
- name: Установить пакет PACKAGE_PLACEHOLDER
apt:
name: "{{ ROLE_NAME_PLACEHOLDER_package }}"
state: present
- name: Запустить и включить сервис SERVICE_PLACEHOLDER
systemd:
name: "{{ ROLE_NAME_PLACEHOLDER_service }}"
enabled: "{{ ROLE_NAME_PLACEHOLDER_enabled }}"
state: "{{ 'started' if ROLE_NAME_PLACEHOLDER_started else 'stopped' }}"
DEBIAN_EOF
# Создаем redhat.yml
cat > ./roles/${ROLE_NAME}/tasks/redhat.yml << 'REDHAT_EOF'
---
# Задачи для RHEL/CentOS
- name: Установить пакет PACKAGE_PLACEHOLDER
yum:
name: "{{ ROLE_NAME_PLACEHOLDER_package }}"
state: present
- name: Запустить и включить сервис SERVICE_PLACEHOLDER
systemd:
name: "{{ ROLE_NAME_PLACEHOLDER_service }}"
enabled: "{{ ROLE_NAME_PLACEHOLDER_enabled }}"
state: "{{ 'started' if ROLE_NAME_PLACEHOLDER_started else 'stopped' }}"
REDHAT_EOF
# Создаем defaults/main.yml
cat > ./roles/${ROLE_NAME}/defaults/main.yml << 'DEFAULTS_EOF'
---
# Переменные по умолчанию для роли ROLE_NAME_PLACEHOLDER
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
ROLE_NAME_PLACEHOLDER_package: PACKAGE_PLACEHOLDER
ROLE_NAME_PLACEHOLDER_service: SERVICE_PLACEHOLDER
ROLE_NAME_PLACEHOLDER_enabled: true
ROLE_NAME_PLACEHOLDER_started: true
DEFAULTS_EOF
# Создаем meta/main.yml
cat > ./roles/${ROLE_NAME}/meta/main.yml << 'META_EOF'
---
galaxy_info:
author: Сергей Антропов
description: ROLE_DESC_PLACEHOLDER
company: https://devops.org.ru
license: MIT
min_ansible_version: 2.9
platforms:
- name: Ubuntu
versions: [18.04, 20.04, 22.04]
- name: Debian
versions: [10, 11, 12]
- name: EL
versions: [7, 8, 9]
galaxy_tags: [TAGS_PLACEHOLDER]
dependencies: []
META_EOF
# Создаем handlers/main.yml
cat > ./roles/${ROLE_NAME}/handlers/main.yml << 'HANDLERS_EOF'
---
# Обработчики роли ROLE_NAME_PLACEHOLDER
- name: Перезапустить SERVICE_PLACEHOLDER
systemd:
name: "{{ ROLE_NAME_PLACEHOLDER_service }}"
state: restarted
HANDLERS_EOF
# Заменяем плейсхолдеры
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/tasks/main.yml
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/tasks/debian.yml
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/tasks/redhat.yml
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/defaults/main.yml
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/meta/main.yml
sed -i '' "s/ROLE_NAME_PLACEHOLDER/${ROLE_NAME}/g" ./roles/${ROLE_NAME}/handlers/main.yml
sed -i '' "s/PACKAGE_PLACEHOLDER/${ROLE_PACKAGE}/g" ./roles/${ROLE_NAME}/tasks/debian.yml
sed -i '' "s/PACKAGE_PLACEHOLDER/${ROLE_PACKAGE}/g" ./roles/${ROLE_NAME}/tasks/redhat.yml
sed -i '' "s/PACKAGE_PLACEHOLDER/${ROLE_PACKAGE}/g" ./roles/${ROLE_NAME}/defaults/main.yml
sed -i '' "s/SERVICE_PLACEHOLDER/${ROLE_SERVICE}/g" ./roles/${ROLE_NAME}/tasks/debian.yml
sed -i '' "s/SERVICE_PLACEHOLDER/${ROLE_SERVICE}/g" ./roles/${ROLE_NAME}/tasks/redhat.yml
sed -i '' "s/SERVICE_PLACEHOLDER/${ROLE_SERVICE}/g" ./roles/${ROLE_NAME}/handlers/main.yml
sed -i '' "s/ROLE_DESC_PLACEHOLDER/${ROLE_DESC}/g" ./roles/${ROLE_NAME}/meta/main.yml
sed -i '' "s/TAGS_PLACEHOLDER/${ROLE_TAGS}/g" ./roles/${ROLE_NAME}/meta/main.yml
echo "Роль ${ROLE_NAME} создана успешно!"
echo "Структура: ./roles/${ROLE_NAME}/"

13
deploy.yml Normal file
View File

@@ -0,0 +1,13 @@
---
# Плейбук для развертывания ролей
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Test nginx role
hosts: all
become: true
roles:
- nginx
tags:
- nginx
- test

View File

@@ -1,36 +0,0 @@
version: "3.9"
services:
ansible-controller:
image: quay.io/ansible/creator-ee:latest
container_name: ansible-controller
privileged: true
command: sleep infinity
environment:
DOCKER_HOST: unix:///var/run/docker.sock
ANSIBLE_VAULT_PASSWORD_FILE: /ansible/vault/.vault
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./molecule:/ansible/molecule
- ./files:/ansible/files
- ./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
# Обратная совместимость
# ansible:
# image: inecs/ansible:latest
# container_name: ansible
# volumes:
# - .:/ansible
# - /var/run/docker.sock:/var/run/docker.sock
# environment:
# - ANSIBLE_VAULT_PASSWORD_FILE=./vault-password.txt
# tty: true
# privileged: true
# working_dir: /ansible

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,51 @@
# AlmaLinux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# https://hub.docker.com/_/almalinux
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 dnf install -y dnf-plugins-core \
&& dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo \
&& dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Устанавливаем 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,56 @@
# ALT Linux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# https://hub.docker.com/_/alt/tags
FROM alt:p9
# Обновляем систему
RUN apt-get update && apt-get dist-upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN apt-get install -y \
systemd \
dbus \
curl \
wget \
git \
vim-enhanced \
nano \
htop \
tree \
jq \
python3 \
&& apt-get clean
# Устанавливаем pip для Python 3.7
RUN curl -sS https://bootstrap.pypa.io/pip/3.7/get-pip.py | python3
# Устанавливаем 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 вручную для ALT Linux
RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
gnupg \
&& apt-get clean
# Устанавливаем 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,61 @@
# Astra Linux с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# https://registry.astralinux.ru/browse/library/
FROM registry.astralinux.ru/library/astra/ubi17:1.7.6.uu2
# Обновляем систему
RUN apt-get update && apt-get dist-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 вручную для AstraLinux
RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release \
&& mkdir -p /usr/share/keyrings \
&& curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian buster stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin \
&& apt-get clean
# Устанавливаем 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:stream9
# Обновляем систему
RUN dnf update -y && dnf upgrade -y
# Устанавливаем systemd и необходимые пакеты
RUN dnf install -y --allowerasing \
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,53 @@
# RED OS с systemd
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# https://registry.red-soft.ru/ubi7/ubi/tags
# docker search registry.red-soft.ru/ubi7/ubi
FROM registry.red-soft.ru/ubi7/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 вручную для RED OS
RUN dnf install -y dnf-plugins-core \
&& dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo \
&& dnf install -y docker-ce docker-ce-cli containerd.io \
&& dnf clean all
# Устанавливаем 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,50 @@
# 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 dnf install -y dnf-plugins-core \
&& dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo \
&& dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Устанавливаем 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

@@ -1,616 +0,0 @@
# API Reference
## Автор
Сергей Антропов
Сайт: https://devops.org.ru
## Описание
Этот документ содержит справочник по API универсальной лаборатории, включая все доступные команды, параметры и конфигурации.
## Содержание
- [Makefile команды](#makefile-команды)
- [Пресеты API](#пресеты-api)
- [Kubernetes API](#kubernetes-api)
- [Docker API](#docker-api)
- [Molecule API](#molecule-api)
- [Отчеты API](#отчеты-api)
- [Скрипты API](#скрипты-api)
## Makefile команды
### Основные команды
| Команда | Описание | Параметры |
|---------|----------|-----------|
| `make lab-up` | Поднять контроллер | - |
| `make lab-down` | Погасить контроллер | - |
| `make lab-sh` | Войти в контроллер | - |
| `make lab-test` | Полный цикл Molecule | `SCENARIO=universal` |
| `make lab-create` | Создать инфраструктуру | - |
| `make lab-converge` | Запустить роли | - |
| `make lab-verify` | Проверить работу | - |
| `make lab-destroy` | Уничтожить инфраструктуру | - |
| `make lab-reset` | Полный сброс | - |
### Kubernetes команды
| Команда | Описание | Параметры |
|---------|----------|-----------|
| `make kube-sh` | Shell с kubectl | - |
| `make kube-cmd` | Выполнить kubectl команду | `CLUSTER=lab CMD="get pods"` |
| `make kube-enter` | Войти в кластер | `CLUSTER=lab` |
| `make kiali-port-forward` | Port-forward Kiali | `CLUSTER=lab` |
| `make istio-gw-port-forward` | Port-forward Istio Gateway | `CLUSTER=lab` |
| `make grafana-port-forward` | Port-forward Grafana | `CLUSTER=lab` |
| `make prom-port-forward` | Port-forward Prometheus | `CLUSTER=lab` |
| `make kube-pf-stop` | Остановить все port-forward | - |
### Отчеты и мониторинг
| Команда | Описание | Параметры |
|---------|----------|-----------|
| `make lab-report` | Сгенерировать HTML отчет | - |
| `make lab-snapshot` | Сохранить снапшот | - |
| `make lab-restore` | Восстановить из снапшота | - |
| `make lab-cleanup` | Очистить лабораторию | - |
| `make bookinfo-url` | Получить URL Bookinfo | - |
| `make grafana-open` | Открыть Grafana | - |
### Pre-commit команды
| Команда | Описание | Параметры |
|---------|----------|-----------|
| `make pre-commit-install` | Установить pre-commit хуки | - |
| `make pre-commit-run` | Запустить pre-commit | - |
## Пресеты API
### Структура пресета
```yaml
---
# ПРЕСЕТ: Название (количество машин)
#
# Описание: Подробное описание пресета
#
# Использование: make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/your-preset.yml
#
# Автор: Ваше имя
# Сайт: https://your-site.com
# Сеть для лаборатории
docker_network: labnet
# Kind кластеры (опционально)
kind_clusters:
- name: cluster-name
workers: 2
api_port: 6443
addons:
ingress_nginx: true
metrics_server: true
istio: true
kiali: true
prometheus_stack: true
ingress_host_http_port: 8081
ingress_host_https_port: 8443
# Образы для разных семейств ОС
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
# Настройки по умолчанию для 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: host-name
family: debian|rhel
type: systemd|dind|dood
group: group-name
publish:
- "host-port:container-port"
env:
KEY: value
volumes:
- "host-path:container-path"
tmpfs:
- "/tmp"
capabilities:
- "SYS_ADMIN"
```
### Параметры хостов
| Параметр | Тип | Описание | Обязательный |
|----------|-----|----------|--------------|
| `name` | string | Имя хоста | Да |
| `family` | string | Семейство ОС (debian/rhel) | Нет |
| `type` | string | Тип контейнера (systemd/dind/dood) | Нет |
| `group` | string | Группа хоста | Нет |
| `publish` | array | Публикация портов | Нет |
| `env` | object | Переменные окружения | Нет |
| `volumes` | array | Монтирование томов | Нет |
| `tmpfs` | array | Временные файловые системы | Нет |
| `capabilities` | array | Capabilities | Нет |
### Параметры Kind кластеров
| Параметр | Тип | Описание | Обязательный |
|----------|-----|----------|--------------|
| `name` | string | Имя кластера | Да |
| `workers` | integer | Количество worker узлов | Нет |
| `api_port` | integer | Порт API сервера | Нет |
| `addons` | object | Включенные аддоны | Нет |
| `ingress_host_http_port` | integer | HTTP порт для ingress | Нет |
| `ingress_host_https_port` | integer | HTTPS порт для ingress | Нет |
### Аддоны Kind кластеров
| Аддон | Тип | Описание |
|-------|-----|----------|
| `ingress_nginx` | boolean | Ingress NGINX контроллер |
| `metrics_server` | boolean | Metrics Server для метрик |
| `istio` | boolean | Istio service mesh |
| `kiali` | boolean | Kiali для визуализации |
| `prometheus_stack` | boolean | Prometheus + Grafana |
## Kubernetes API
### kubectl команды
```bash
# Получить информацию о кластере
kubectl cluster-info
# Получить ноды
kubectl get nodes
# Получить поды
kubectl get pods -A
# Получить сервисы
kubectl get svc -A
# Получить события
kubectl get events --sort-by=.metadata.creationTimestamp
# Описать ресурс
kubectl describe pod <pod-name>
# Логи пода
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
# Port-forward сервиса
kubectl port-forward svc/<service-name> <local-port>:<remote-port>
# Port-forward пода
kubectl port-forward pod/<pod-name> <local-port>:<remote-port>
# Port-forward в фоне
kubectl port-forward svc/<service-name> <local-port>:<remote-port> &
# Остановить все port-forward
pkill -f "kubectl .* port-forward"
```
### Istio команды
```bash
# Проверить Istio
istioctl version
# Установить Istio
istioctl install --set profile=demo
# Удалить Istio
istioctl uninstall --purge
# Проверить статус
istioctl proxy-status
# Получить конфигурацию
istioctl proxy-config cluster <pod-name>
```
## Docker API
### Docker команды
```bash
# Список контейнеров
docker ps
# Список образов
docker images
# Список сетей
docker network ls
# Список томов
docker volume ls
# Информация о контейнере
docker inspect <container-name>
# Логи контейнера
docker logs <container-name>
# Войти в контейнер
docker exec -it <container-name> /bin/sh
```
### Docker Compose команды
```bash
# Запустить стек
docker-compose up -d
# Остановить стек
docker-compose down
# Логи стека
docker-compose logs
# Масштабирование
docker-compose up --scale service=3
```
### Docker Swarm команды
```bash
# Инициализировать Swarm
docker swarm init
# Присоединиться к Swarm
docker swarm join --token <token> <manager-ip>:2377
# Список нод
docker node ls
# Создать сервис
docker service create --name <service-name> <image>
# Масштабировать сервис
docker service scale <service-name>=3
```
## Molecule API
### Molecule команды
```bash
# Создать сценарий
molecule init scenario <scenario-name>
# Создать роль
molecule init role <role-name>
# Проверить синтаксис
molecule syntax
# Проверить конфигурацию
molecule lint
# Валидация
molecule validate
# Создать инфраструктуру
molecule create
# Запустить роли
molecule converge
# Проверить работу
molecule verify
# Уничтожить инфраструктуру
molecule destroy
# Полный цикл
molecule test
```
### Конфигурация molecule.yml
```yaml
---
driver:
name: docker
platforms:
- name: instance
image: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
privileged: true
pre_build_image: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
capabilities:
- "SYS_ADMIN"
tmpfs:
- "/run"
- "/run/lock"
provisioner:
name: ansible
config_options:
defaults:
stdout_callback: default
callbacks_enabled: profile_tasks
env:
ANSIBLE_STDOUT_CALLBACK: default
dependency:
name: galaxy
enabled: false
verifier:
name: ansible
lint: |-
set -e
ansible-lint
```
## Отчеты API
### HTML отчет
```bash
# Генерация отчета
python3 scripts/report_html.py <input.json> <output.html>
# Параметры
# input.json - JSON файл с данными
# output.html - HTML файл для вывода
```
### JSON структура
```json
{
"timestamp": "2024-01-01T00:00:00Z",
"idempotence_raw": "changed=0",
"haproxy_select1": "1",
"helm_ingress_toolbox_raw": "ingress ready",
"istio_kiali_raw": "istio-system pods running",
"istio_bookinfo_raw": "bookinfo deployed",
"k8s_overview_raw": "nodes ready"
}
```
### HTML структура
```html
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Lab Report</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
/* CSS стили */
</style>
</head>
<body>
<div class="container">
<div class="hdr">
<h1>Ansible Lab Report</h1>
<div class="time">generated: timestamp</div>
</div>
<div class="grid">
<!-- Отчеты -->
</div>
</div>
</body>
</html>
```
## Скрипты API
### snapshot.sh
```bash
#!/usr/bin/env bash
# Создание снапшотов лаборатории (запускается через Docker)
# Параметры
OUT_DIR="/ansible/snapshots"
# Создать директорию
mkdir -p "$OUT_DIR"
# Получить ID контейнеров
ids=$(docker ps -q --filter "label=ansible.lab=true")
# Создать снапшоты
for id in $ids; do
name=$(docker inspect --format '{{.Name}}' "$id" | sed 's#^/##')
img="lab-snap-$name:latest"
echo "[snapshot] $name -> $img"
docker commit "$id" "$img" >/dev/null
echo "$img" > "$OUT_DIR/$name.image"
done
```
### restore.sh
```bash
#!/usr/bin/env bash
# Восстановление из снапшотов (запускается через Docker)
# Параметры
IN_DIR="/ansible/snapshots"
# Проверить директорию
[ -d "$IN_DIR" ] || { echo "No snapshots dir"; exit 1; }
# Восстановить контейнеры
for f in "$IN_DIR"/*.image; do
[ -f "$f" ] || continue
name=$(basename "$f" .image)
img=$(cat "$f")
echo "[restore] $name from $img"
docker rm -f "$name" >/dev/null 2>&1 || true
docker run -d --name "$name" "$img" >/dev/null
done
```
### cleanup.sh
```bash
#!/usr/bin/env bash
# Очистка лаборатории (запускается через Docker)
echo "[cleanup] removing lab containers/volumes/networks"
# Удалить контейнеры
docker ps -aq --filter "label=ansible.lab=true" | xargs -r docker rm -f
# Удалить тома
docker volume ls -q --filter "name=_docker$" | xargs -r docker volume rm
# Удалить сеть
docker network rm labnet >/dev/null 2>&1 || true
echo "done."
```
## Переменные окружения
### Основные переменные
| Переменная | Описание | Значение по умолчанию |
|------------|----------|----------------------|
| `LAB_SPEC` | Путь к пресету | `molecule/presets/minimal.yml` |
| `SCENARIO` | Сценарий Molecule | `universal` |
| `COMPOSE` | Docker Compose команда | `docker compose` |
| `ROLES_DIR` | Директория с ролями | `./roles` |
| `LAB_PAUSE_MINUTES` | Пауза для ручной проверки | `10` |
### Kubernetes переменные
| Переменная | Описание | Значение по умолчанию |
|------------|----------|----------------------|
| `KUBECONFIG` | Путь к kubeconfig | `~/.kube/config` |
| `KUBE_CONTEXT` | Контекст Kubernetes | `kind-lab` |
| `ISTIO_VERSION` | Версия Istio | `1.22.1` |
| `KIND_VERSION` | Версия Kind | `v0.23.0` |
### Docker переменные
| Переменная | Описание | Значение по умолчанию |
|------------|----------|----------------------|
| `DOCKER_HOST` | Docker daemon адрес | `unix:///var/run/docker.sock` |
| `DOCKER_TLS_CERTDIR` | Директория TLS сертификатов | `""` |
| `DOCKER_BUILDKIT` | Использовать BuildKit | `1` |
## Конфигурационные файлы
### docker-compose.yaml
```yaml
version: "3.9"
services:
ansible-controller:
image: quay.io/ansible/creator-ee:latest
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
- ./molecule:/ansible/molecule
- ./files:/ansible/files
- ./vault-password.txt:/ansible/vault-password.txt
- ${ROLES_DIR:-./roles}:/ansible/roles:ro
working_dir: /ansible
```
### .pre-commit-config.yaml
```yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/ansible/ansible-lint
rev: v6.17.2
hooks:
- id: ansible-lint
```
## Заключение
Этот справочник содержит все необходимые API для работы с универсальной лабораторией. Для получения дополнительной информации обратитесь к [основной документации](universal-lab.md) и [примерам использования](examples.md).

View File

@@ -1,354 +1,315 @@
# Примеры использования
# Примеры использования универсальной системы тестирования
## Автор
Сергей Антропов
Сайт: https://devops.org.ru
## Пример 1: Тестирование кластера etcd + PostgreSQL + Patroni
## Описание
### Описание
Этот пример демонстрирует тестирование высокодоступного кластера PostgreSQL с Patroni и etcd.
Этот документ содержит практические примеры использования универсальной лаборатории для различных сценариев тестирования Ansible ролей.
### 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]
- [Базовые примеры](#базовые-примеры)
- [Kubernetes примеры](#kubernetes-примеры)
- [Docker примеры](#docker-примеры)
- [Смешанные примеры](#смешанные-примеры)
- [Мониторинг и отчеты](#мониторинг-и-отчеты)
- [Troubleshooting](#troubleshooting)
# 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 порты
### Пример 1: Тестирование веб-сервера
```bash
# Запустить веб-приложение пресет
make lab-test LAB_SPEC=molecule/presets/webapp.yml
# Проверить статус
make lab-verify
# Посмотреть отчет
make lab-report
# DinD узел для тестирования Docker Compose внутри
- name: app-dind
type: dind
groups: [apps, docker]
publish: ["8080:8080"]
```
### Пример 2: Тестирование базы данных
### Запуск тестирования
```bash
# Запустить пресет с базой данных
make lab-test LAB_SPEC=molecule/presets/ha.yml
# Информация о preset'е
make preset-info PRESET=etcd-patroni
# Проверить подключение к БД
make kube-cmd CLUSTER=lab CMD="exec -it postgres-0 -- psql -U postgres -c 'SELECT 1;'"
# Тестирование с preset'ом
make preset-test PRESET=etcd-patroni
# Или через role test
make role test etcd-patroni
```
### Пример 3: Тестирование микросервисов
### Проверка результатов
```bash
# Запустить микросервисный пресет
make lab-test LAB_SPEC=molecule/presets/microservices.yml
# Проверить статус контейнеров
make container-info
# Проверить API Gateway
curl http://localhost:8000/health
# Проверить vault файлы
make vault-check
```
## Kubernetes примеры
## Пример 2: Нагрузочное тестирование
### Пример 1: Простой Kubernetes кластер
### Описание
Этот пример демонстрирует тестирование под нагрузкой с множественными серверами и кэшем.
```bash
# Запустить одиночный Kind кластер
make lab-test LAB_SPEC=molecule/presets/k8s-single.yml
### Preset: performance
# Войти в кластер
make kube-sh
```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]
# Проверить ноды
kubectl get nodes
# База данных (3 узла)
- name: db1
family: rhel
groups: [database, db]
- name: db2
family: debian
groups: [database, db]
- name: db3
family: rhel
groups: [database, db]
# Проверить поды
kubectl get pods -A
# Кэш (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"]
```
### Пример 2: Мульти-кластерная конфигурация
### Запуск тестирования
```bash
# Запустить мульти-кластер
make lab-test LAB_SPEC=molecule/presets/k8s-multi.yml
# Тестирование с performance preset'ом
make role test performance
# Переключиться между кластерами
kubectl config use-context kind-dev
kubectl get nodes
kubectl config use-context kind-staging
kubectl get nodes
kubectl config use-context kind-prod
kubectl get nodes
# Проверка статуса
make container-info
```
### Пример 3: Istio Service Mesh
## Пример 3: Тестирование безопасности
```bash
# Запустить полный Istio стек
make lab-test LAB_SPEC=molecule/presets/k8s-istio-full.yml
### Описание
Этот пример демонстрирует тестирование в безопасной среде с bastion хостами и изоляцией.
# Port-forward Kiali
make kiali-port-forward CLUSTER=istio-full
### Preset: security
# Port-forward Istio Gateway
make istio-gw-port-forward CLUSTER=istio-full
```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"]
# Открыть Kiali
open http://localhost:20001
# Внутренние серверы (без внешнего доступа)
- name: internal1
family: rhel
groups: [internal, servers, app]
- name: internal2
family: debian
groups: [internal, servers, app]
- name: internal3
family: rhel
groups: [internal, servers, app]
# Открыть Bookinfo
open http://localhost:8082/productpage
# База данных (изолированная сеть)
- 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"
```
### Пример 4: Мониторинг Kubernetes
### Запуск тестирования
```bash
# Port-forward Grafana
make grafana-port-forward CLUSTER=istio-full
# Тестирование с security preset'ом
make role test security
# Port-forward Prometheus
make prom-port-forward CLUSTER=istio-full
# Открыть Grafana
open http://localhost:3000
# Открыть Prometheus
open http://localhost:9090
# Проверка безопасности
make vault-check
make vault-scan
```
## Docker примеры
## Пример 4: Тестирование на разных ОС
### Пример 1: Docker-in-Docker
### Описание
Этот пример демонстрирует тестирование на различных операционных системах.
```bash
# Запустить DinD пресет
make lab-test LAB_SPEC=molecule/presets/dind-simple.yml
### Preset: multi-os
# Войти в DinD контейнер
docker exec -it dind1 sh
```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]
# Внутри контейнера проверить Docker
docker ps
docker images
# 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"]
```
### Пример 2: Docker Swarm
### Запуск тестирования
```bash
# Запустить Docker Swarm пресет
make lab-test LAB_SPEC=molecule/presets/dind-swarm.yml
# Тестирование с multi-os preset'ом
make role test multi-os
# Войти в manager
docker exec -it swarm-manager sh
# Инициализировать Swarm
docker swarm init
# Присоединить workers
docker node ls
# Проверка типов контейнеров
make container-types
```
### Пример 3: Docker Compose
## Пример 5: Создание собственного preset'а
### Описание
Этот пример демонстрирует создание собственного preset'а для специфических нужд.
### Создание preset'а
```bash
# Запустить Compose пресет
make lab-test LAB_SPEC=molecule/presets/dind-compose.yml
# Войти в compose контейнер
docker exec -it compose-web sh
# Создать docker-compose.yml
cat > docker-compose.yml << EOF
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
api:
image: node:alpine
ports:
- "3000:3000"
EOF
# Запустить стек
docker-compose up -d
```
### Пример 4: Docker-outside-of-Docker
```bash
# Запустить DOoD пресет
make lab-test LAB_SPEC=molecule/presets/dood-simple.yml
# Войти в DOoD контейнер
docker exec -it dood1 sh
# Проверить доступ к Docker daemon хоста
docker ps
docker images
```
## Смешанные примеры
### Пример 1: Kubernetes + DinD
```bash
# Запустить смешанный пресет
make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dind.yml
# Проверить Kubernetes
make kube-cmd CLUSTER=hybrid CMD="get nodes"
# Проверить DinD
docker exec -it dind-dev sh
docker ps
```
### Пример 2: Kubernetes + DOoD
```bash
# Запустить смешанный пресет
make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dood.yml
# Проверить Kubernetes
make kube-cmd CLUSTER=hybrid CMD="get pods -A"
# Проверить DOoD
docker exec -it dood-web sh
docker ps
```
### Пример 3: Полная гибридная конфигурация
```bash
# Запустить полный смешанный пресет
make lab-test LAB_SPEC=molecule/presets/mixed-full.yml
# Проверить все компоненты
make kube-cmd CLUSTER=full-stack CMD="get nodes"
docker exec -it dind-dev sh
docker exec -it dood-web sh
```
## Мониторинг и отчеты
### Пример 1: Генерация HTML отчета
```bash
# Запустить тест
make lab-test LAB_SPEC=molecule/presets/enterprise.yml
# Сгенерировать отчет
make lab-report
# Открыть отчет
open reports/lab-report.html
```
### Пример 2: Снапшоты
```bash
# Создать снапшот
make lab-snapshot
# Восстановить из снапшота
make lab-restore
# Очистить лабораторию
make lab-cleanup
```
### Пример 3: Мониторинг в реальном времени
```bash
# Port-forward всех сервисов мониторинга
make grafana-port-forward CLUSTER=lab
make prom-port-forward CLUSTER=lab
make kiali-port-forward CLUSTER=lab
# Открыть все дашборды
open http://localhost:3000 # Grafana
open http://localhost:9090 # Prometheus
open http://localhost:20001 # Kiali
```
## Troubleshooting
### Пример 1: Проблемы с портами
```bash
# Проверить занятые порты
netstat -tulpn | grep :8080
# Остановить все port-forward
make kube-pf-stop
# Перезапустить лабораторию
make lab-reset
```
### Пример 2: Проблемы с Docker
```bash
# Проверить Docker daemon
docker ps
# Перезапустить Docker
sudo systemctl restart docker
# Очистить Docker
docker system prune -a
```
### Пример 3: Проблемы с Kubernetes
```bash
# Проверить Kind кластеры
kind get clusters
# Удалить проблемный кластер
kind delete cluster --name lab
# Пересоздать кластер
make lab-create
```
### Пример 4: Проблемы с ресурсами
```bash
# Проверить использование ресурсов
docker stats
# Ограничить ресурсы
docker run --memory=512m --cpus=1.0 your-image
# Очистить неиспользуемые ресурсы
make lab-cleanup
```
## Продвинутые примеры
### Пример 1: Создание собственного пресета
```bash
# Создать новый пресет
cat > molecule/presets/my-custom.yml << EOF
# Создать новый preset
cat > molecule/presets/my-custom.yml << 'EOF'
---
# ПРЕСЕТ: Мой кастомный пресет
#
# Описание: Кастомная конфигурация для моих нужд
#
# Использование: make lab-test LAB_SPEC=molecule/presets/my-custom.yml
# Пресет для тестирования веб-приложения
# Автор: Ваше имя
# Сайт: 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"
@@ -358,105 +319,106 @@ systemd_defaults:
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs:
- "/run"
- "/run/lock"
capabilities:
- "SYS_ADMIN"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
# Описание кластера
hosts:
- name: my-web
# Веб-серверы
- name: web1
family: debian
group: webservers
publish:
- "8080:80"
- name: my-db
groups: [web, servers]
publish: ["80:80", "443:443"]
- name: web2
family: rhel
group: databases
publish:
- "5432:5432"
EOF
groups: [web, servers]
publish: ["8080:80", "8443:443"]
# Протестировать пресет
make lab-test LAB_SPEC=molecule/presets/my-custom.yml
# База данных
- 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
```
### Пример 2: Создание собственной роли
### Использование preset'а
```bash
# Создать структуру роли
mkdir -p roles/my-role/{tasks,handlers,templates,files,vars,defaults,meta}
# Информация о preset'е
make preset-info PRESET=my-custom
# Создать основной task
cat > roles/my-role/tasks/main.yml << EOF
---
- name: Install nginx
package:
name: nginx
state: present
# Тестирование с preset'ом
make preset-test PRESET=my-custom
- name: Start nginx
service:
name: nginx
state: started
enabled: true
EOF
# Создать playbook
cat > files/playbooks/my-playbook.yml << EOF
---
- name: Deploy my role
hosts: webservers
become: true
roles:
- my-role
EOF
# Протестировать роль
make lab-test LAB_SPEC=molecule/presets/webapp.yml
# Или через role test
make role test my-custom
```
### Пример 3: Интеграция с CI/CD
## Пример 6: Работа с Ansible Vault
### Создание vault файла
```bash
# Создать GitHub Actions workflow
cat > .github/workflows/test.yml << EOF
name: Test Ansible Roles
# Создать файл секретов
make vault create
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Ввести имя файла: secrets
# Ввести содержимое:
# ---
# database_password: "super_secret_password"
# api_key: "your_api_key_here"
# ssl_cert: "your_ssl_certificate"
```
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Docker
run: |
docker-compose up -d
- name: Run tests
run: |
make lab-test LAB_SPEC=molecule/presets/minimal.yml
- name: Generate report
run: |
make lab-report
- name: Upload report
uses: actions/upload-artifact@v3
with:
name: lab-report
path: reports/lab-report.html
EOF
### Использование в ролях
```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
```
## Заключение
Эти примеры демонстрируют основные возможности универсальной лаборатории. Для получения дополнительной информации обратитесь к [основной документации](universal-lab.md) и [описанию пресетов](presets.md).
Эти примеры демонстрируют различные способы использования универсальной системы тестирования Ansible ролей. Вы можете:
1. Использовать готовые preset'ы для быстрого тестирования
2. Создавать собственные preset'ы для специфических нужд
3. Комбинировать различные типы контейнеров
4. Использовать Ansible Vault для безопасности
5. Тестировать на различных операционных системах
Для получения дополнительной информации используйте:
- `make help` - общая справка
- `make preset-list` - список preset'ов
- `make container-types` - типы контейнеров
- `make vault` - команды Vault

View File

@@ -1,196 +0,0 @@
# Пресеты универсальной лаборатории
## Автор
Сергей Антропов
Сайт: https://devops.org.ru
## Описание
Этот каталог содержит готовые пресеты для различных сценариев тестирования Ansible ролей. Каждый пресет оптимизирован для определенного типа инфраструктуры и количества машин.
## Доступные пресеты
### 🏗️ Классические пресеты (systemd контейнеры)
#### 1. Минимальная лаборатория (1-3 машины)
**Файл:** `minimal.yml`
**Описание:** Базовая конфигурация для простых тестов Ansible ролей
**Компоненты:** 1 контроллер, 1 веб-сервер, 1 база данных
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/minimal.yml`
### 2. Веб-приложение (3-5 машин)
**Файл:** `webapp.yml`
**Описание:** Классическая архитектура веб-приложения
**Компоненты:** 2 веб-сервера, 1 БД, 1 кэш, 1 балансировщик
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/webapp.yml`
### 3. Микросервисы (5-8 машин)
**Файл:** `microservices.yml`
**Описание:** Архитектура микросервисов с разделением ответственности
**Компоненты:** API Gateway, микросервисы, БД, кэш, очередь, мониторинг
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/microservices.yml`
### 4. Высокая доступность (6-10 машин)
**Файл:** `ha.yml`
**Описание:** Кластер высокой доступности с репликацией
**Компоненты:** 2 веб-сервера, 2 БД, 2 кэша, балансировщик, мониторинг
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/ha.yml`
### 5. Kubernetes кластер (8-12 машин)
**Файл:** `k8s-cluster.yml`
**Описание:** Полноценный Kubernetes кластер с различными ролями
**Компоненты:** 3 master, 3 worker, 3 etcd, ingress, мониторинг
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/k8s-cluster.yml`
### 6. CI/CD пайплайн (10-15 машин)
**Файл:** `cicd.yml`
**Описание:** Полноценный CI/CD пайплайн с различными инструментами
**Компоненты:** Git, Jenkins, Nexus, Docker Registry, среды, мониторинг, ELK
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/cicd.yml`
### 7. Big Data кластер (12-18 машин)
**Файл:** `bigdata.yml`
**Описание:** Кластер для обработки больших данных
**Компоненты:** Hadoop, Spark, Kafka, Zookeeper, Elasticsearch, Kibana
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/bigdata.yml`
### 8. Service Mesh (15-20 машин)
**Файл:** `servicemesh.yml`
**Описание:** Полноценный service mesh с Istio и множественными сервисами
**Компоненты:** Istio, Frontend, Backend, БД, кэш, мониторинг, трассировка
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/servicemesh.yml`
### 9. Enterprise (18-20 машин)
**Файл:** `enterprise.yml`
**Описание:** Полноценная enterprise инфраструктура с высокой доступностью
**Компоненты:** LB, Web, API Gateway, App, БД, кэш, очереди, поиск, мониторинг, логи, backup
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/enterprise.yml`
### 10. Максимальный (20 машин)
**Файл:** `maximum.yml`
**Описание:** Максимально сложная инфраструктура для экстремальных условий
**Компоненты:** Все компоненты enterprise + трассировка + визуализация
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/maximum.yml`
### ☸️ Kubernetes пресеты
#### 11. Kubernetes Single Node (1 кластер)
**Файл:** `k8s-single.yml`
**Описание:** Одиночный Kind кластер для простого тестирования K8s ролей
**Компоненты:** 1 Kind кластер с 1 worker, базовые аддоны
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/k8s-single.yml`
#### 12. Kubernetes Multi-Cluster (3 кластера)
**Файл:** `k8s-multi.yml`
**Описание:** Несколько Kind кластеров для тестирования мульти-кластерных сценариев
**Компоненты:** 3 кластера (dev, staging, prod) с различными конфигурациями
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/k8s-multi.yml`
#### 13. Kubernetes + Istio Full Stack (1 кластер с полным стеком)
**Файл:** `k8s-istio-full.yml`
**Описание:** Полноценный Kubernetes кластер с полным стеком Istio
**Компоненты:** 1 Kind кластер с 3 workers, Istio, Kiali, Prometheus, Grafana, Jaeger
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/k8s-istio-full.yml`
### 🐳 Docker-in-Docker (DinD) пресеты
#### 14. DinD Simple (3 DinD контейнера)
**Файл:** `dind-simple.yml`
**Описание:** Простая конфигурация DinD для тестирования Docker ролей
**Компоненты:** 3 DinD контейнера с изолированными Docker средами
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/dind-simple.yml`
#### 15. DinD Swarm (5 DinD контейнеров)
**Файл:** `dind-swarm.yml`
**Описание:** Docker Swarm кластер для тестирования оркестрации
**Компоненты:** 1 Manager + 4 Worker узла в Docker Swarm режиме
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/dind-swarm.yml`
#### 16. DinD Compose (4 DinD контейнера)
**Файл:** `dind-compose.yml`
**Описание:** DinD контейнеры для тестирования Docker Compose стека
**Компоненты:** 4 DinD контейнера с различными стеками
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/dind-compose.yml`
### 🔗 Docker-outside-of-Docker (DOoD) пресеты
#### 17. DOoD Simple (3 DOoD контейнера)
**Файл:** `dood-simple.yml`
**Описание:** Простая конфигурация DOoD для тестирования Docker ролей
**Компоненты:** 3 DOoD контейнера с доступом к Docker daemon хоста
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/dood-simple.yml`
#### 18. DOoD Mixed (5 DOoD + 2 systemd)
**Файл:** `dood-mixed.yml`
**Описание:** Смешанная конфигурация DOoD и systemd контейнеров
**Компоненты:** 5 DOoD контейнеров для Docker операций + 2 systemd для системных ролей
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/dood-mixed.yml`
### 🔀 Смешанные пресеты
#### 19. Mixed Kubernetes + DinD (1 K8s + 3 DinD)
**Файл:** `mixed-k8s-dind.yml`
**Описание:** Смешанная конфигурация Kubernetes и Docker-in-Docker
**Компоненты:** 1 Kind кластер + 3 DinD контейнера
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/mixed-k8s-dind.yml`
#### 20. Mixed Kubernetes + DOoD (1 K8s + 3 DOoD)
**Файл:** `mixed-k8s-dood.yml`
**Описание:** Смешанная конфигурация Kubernetes и Docker-outside-of-Docker
**Компоненты:** 1 Kind кластер + 3 DOoD контейнера
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/mixed-k8s-dood.yml`
#### 21. Mixed Full Stack (1 K8s + 2 DinD + 2 DOoD + 2 systemd)
**Файл:** `mixed-full.yml`
**Описание:** Полная смешанная конфигурация для комплексного тестирования
**Компоненты:** 1 Kind кластер + 2 DinD + 2 DOoD + 2 systemd контейнера
**Использование:** `make lab-test SCENARIO=universal LAB_SPEC=molecule/presets/mixed-full.yml`
## Использование
### Быстрый старт
```bash
# Выбрать пресет
export LAB_SPEC=molecule/presets/minimal.yml
# Запустить тестирование
make lab-test
```
### Создание собственного пресета
1. Скопировать существующий пресет: `cp minimal.yml my-preset.yml`
2. Отредактировать под ваши нужды
3. Использовать: `make lab-test LAB_SPEC=molecule/presets/my-preset.yml`
### Переменные окружения
```bash
# Установить пресет по умолчанию
export LAB_SPEC=molecule/presets/webapp.yml
# Или использовать в команде
make lab-test LAB_SPEC=molecule/presets/ha.yml
```
## Рекомендации
- **Для начинающих:** используйте `minimal.yml` или `webapp.yml`
- **Для микросервисов:** `microservices.yml` или `servicemesh.yml`
- **Для Kubernetes:** `k8s-cluster.yml`
- **Для enterprise:** `enterprise.yml` или `maximum.yml`
- **Для Big Data:** `bigdata.yml`
## Кастомизация
Каждый пресет можно настроить под ваши нужды:
- Изменить количество машин
- Добавить/убрать группы
- Изменить семейства ОС (debian/rhel)
- Настроить порты и переменные
## Troubleshooting
Если пресет не работает:
1. Проверьте доступность Docker образов
2. Убедитесь в достаточности ресурсов
3. Проверьте логи: `make lab-verify`
4. Очистите лабораторию: `make lab-cleanup`

View File

@@ -1,372 +0,0 @@
# Управление ролями Ansible
Полное руководство по созданию, управлению и использованию ролей в универсальной лаборатории.
## Создание роли
### Интерактивное создание
```bash
make role create NAME=my-role
```
**Что происходит:**
1. **Запрашивается описание роли** - краткое описание функциональности
2. **Настраивается основной пакет** - имя пакета для установки
3. **Настраивается сервис** - имя сервиса для управления
4. **Выбираются платформы** - поддерживаемые ОС (ubuntu, centos, rhel)
5. **Указываются теги** - теги для Ansible Galaxy
6. **Создается универсальная структура роли** с поддержкой RHEL и Debian семейств
7. **Создается папка `playbooks/`** для playbooks роли
### Структура созданной роли
```
roles/my-role/
├── tasks/
│ ├── main.yml # Основные задачи (универсальные)
│ ├── debian.yml # Задачи для Debian/Ubuntu
│ └── redhat.yml # Задачи для RHEL/CentOS
├── handlers/
│ └── main.yml # Обработчики
├── templates/ # Шаблоны Jinja2
├── files/ # Статические файлы
├── vars/
│ └── main.yml # Переменные роли
├── defaults/
│ └── main.yml # Переменные по умолчанию
├── meta/
│ └── main.yml # Метаданные роли
├── tests/ # Тесты роли
└── playbooks/ # Playbooks роли
└── (создаются через make role playbook)
```
## Универсальные роли
### Принцип работы
Роли создаются **универсальными** для RHEL и Debian семейств:
1. **`tasks/main.yml`** - содержит общую логику и включает OS-специфичные задачи
2. **`tasks/debian.yml`** - задачи для Debian/Ubuntu (apt, systemd)
3. **`tasks/redhat.yml`** - задачи для RHEL/CentOS (yum, systemd)
### Автоматическое определение ОС
```yaml
# tasks/main.yml
- name: Include OS-specific tasks
include_tasks: "{{ ansible_os_family | lower }}.yml"
```
**Поддерживаемые ОС:**
- **Debian семейство**: Ubuntu, Debian, Linux Mint
- **RHEL семейство**: CentOS, RHEL, Rocky Linux, AlmaLinux
### Примеры задач
#### Debian/Ubuntu (tasks/debian.yml)
```yaml
---
# Задачи для Debian/Ubuntu семейства
- name: Update apt cache (Debian)
apt:
update_cache: true
cache_valid_time: 3600
when: ansible_os_family == 'Debian'
- name: Install nginx package (Debian)
apt:
name: "{{ nginx_package | default('nginx') }}"
state: present
when: ansible_os_family == 'Debian'
```
#### RHEL/CentOS (tasks/redhat.yml)
```yaml
---
# Задачи для RHEL/CentOS семейства
- name: Update yum cache (RHEL)
yum:
update_cache: true
when: ansible_os_family == 'RedHat'
- name: Install nginx package (RHEL)
yum:
name: "{{ nginx_package | default('nginx') }}"
state: present
when: ansible_os_family == 'RedHat'
```
## Управление playbooks роли
### Создание playbook
```bash
make role playbook NAME=my-role
# Выберите: create
# Введите имя: deploy
```
**Создается файл:** `roles/my-role/playbooks/deploy.yml`
```yaml
---
# Playbook: deploy для роли my-role
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: deploy
hosts: all
become: true
gather_facts: true
vars:
# Переменные для роли my-role
my_role_enabled: true
pre_tasks:
- name: Display OS information
debug:
msg: "OS Family: {{ ansible_os_family }}, OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
roles:
- role: my-role
post_tasks:
- name: Verify my-role installation
debug:
msg: "my-role successfully deployed on {{ inventory_hostname }}"
```
### Универсальные playbooks
Playbooks создаются **универсальными** с поддержкой:
1. **`gather_facts: true`** - сбор информации об ОС
2. **`pre_tasks`** - отображение информации об ОС
3. **`post_tasks`** - проверка успешного развертывания
4. **Переменные роли** - автоматически добавляются в `vars`
### Список playbooks
```bash
make role playbook NAME=my-role
# Выберите: list
```
### Редактирование playbook
```bash
make role playbook NAME=my-role
# Выберите: edit
# Введите имя: deploy
```
### Запуск playbook
```bash
make role playbook NAME=my-role
# Выберите: run
# Введите имя: deploy
```
## Команды управления ролями
### Основные команды
```bash
# Список ролей
make role list
# Создать роль (интерактивно)
make role create NAME=my-role
# Редактировать роль
make role edit NAME=my-role
# Тестировать роль
make role test NAME=my-role
# Проверить синтаксис
make role lint
# Развернуть роли
make role deploy
# Информация о роли
make role info NAME=my-role
# Управление playbooks
make role playbook NAME=my-role
```
### Интерактивные возможности
#### При создании роли:
- **Описание роли** - автоматически добавляется в README.md
- **Основной пакет** - настраивается в defaults/main.yml
- **Сервис** - настраивается в defaults/main.yml
- **Платформы** - добавляются в meta/main.yml
- **Теги** - добавляются в meta/main.yml
#### При работе с playbooks:
- **Создание** - интерактивный ввод имени
- **Редактирование** - выбор из списка существующих
- **Запуск** - выбор playbook для выполнения
## Примеры использования
### Создание роли nginx
```bash
make role create NAME=nginx
# Описание: Nginx web server role
# Пакет: nginx
# Сервис: nginx
# Платформы: ubuntu,centos
# Теги: web,nginx,server
```
### Создание playbook для nginx
```bash
make role playbook NAME=nginx
# Выберите: create
# Имя: install
```
**Результат:** `roles/nginx/playbooks/install.yml`
### Запуск playbook
```bash
make role playbook NAME=nginx
# Выберите: run
# Имя: install
```
## Структура файлов роли
### tasks/main.yml
```yaml
---
# Основные задачи роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: nginx placeholder
debug:
msg: "Роль nginx готова для настройки"
- name: Install nginx package
package:
name: "{{ nginx_package | default('nginx') }}"
state: present
- name: Start nginx service
systemd:
name: "{{ nginx_service | default('nginx') }}"
state: started
enabled: true
when: nginx_service is defined
```
### defaults/main.yml
```yaml
---
# Переменные по умолчанию для роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
nginx_enabled: true
nginx_package: nginx
nginx_service: nginx
```
### meta/main.yml
```yaml
---
galaxy_info:
author: Сергей Антропов
description: Nginx web server role
company: https://devops.org.ru
license: MIT
min_ansible_version: 2.9
platforms:
- name: Ubuntu
versions: [focal, jammy]
- name: CentOS
versions: [7, 8, 9]
- name: RHEL
versions: [7, 8, 9]
galaxy_tags: [web,nginx,server]
dependencies: []
```
## Лучшие практики
### 1. Универсальные роли
- **Всегда создавайте OS-специфичные задачи** в `debian.yml` и `redhat.yml`
- **Используйте `ansible_os_family`** для определения ОС
- **Тестируйте на разных платформах** (Ubuntu, CentOS, RHEL)
- **Используйте универсальные модули** когда возможно (package, systemd)
### 2. Структура роли
- **`tasks/main.yml`** - общая логика и включение OS-специфичных задач
- **`tasks/debian.yml`** - задачи для Debian/Ubuntu (apt, systemd)
- **`tasks/redhat.yml`** - задачи для RHEL/CentOS (yum, systemd)
- **`handlers`** - для перезапуска сервисов
- **`templates`** - для конфигурационных файлов
- **`files`** - для статических файлов
### 3. Переменные
- **`defaults/main.yml`** - значения по умолчанию
- **`vars/main.yml`** - внутренние переменные роли
- **Используйте префиксы** для переменных роли
- **Создавайте OS-специфичные переменные** при необходимости
### 4. Playbooks
- **`gather_facts: true`** - всегда собирайте информацию об ОС
- **`pre_tasks`** - отображайте информацию об ОС
- **`post_tasks`** - проверяйте успешное развертывание
- **Используйте переменные** для настройки
### 5. Тестирование
- **`make role test`** - проверка роли
- **Тестируйте на разных ОС** - Ubuntu, CentOS, RHEL
- **Создавайте тесты** в папке tests/
- **Проверяйте идемпотентность** - повторный запуск не должен изменять систему
## Интеграция с лабораторией
### Автоматическое добавление в систему
При создании роли через `make role create`:
1. Роль автоматически добавляется в `deploy/tasks/main.yml`
2. Создается переменная `{role_name}_enabled: true`
3. Обновляется `site.yml` с новой ролью
### Использование в playbooks
```yaml
---
- name: Deploy my-role
hosts: all
become: true
roles:
- role: my-role
vars:
my_role_enabled: true
my_role_package: custom-package
```
## Автор
Сергей Антропов
Сайт: https://devops.org.ru

View File

@@ -0,0 +1,99 @@
# Тестирование vs Развертывание
## Автор: Сергей Антропов
## Сайт: https://devops.org.ru
## Различие между тестированием и развертыванием
### 🧪 Тестирование (molecule)
**Команда:** `make role test [preset]`
**Использует:**
- Динамический inventory, создаваемый в `molecule/default/create.yml`
- Preset файлы из `molecule/presets/`
- Docker контейнеры для изоляции тестов
- Временные контейнеры (u1, u2, u3)
**Процесс:**
1. Загружается preset конфигурация
2. Создаются Docker контейнеры согласно preset
3. Генерируется временный inventory файл
4. Запускаются тесты на контейнерах
5. Контейнеры удаляются после тестов
**Пример:**
```bash
make role test standart # Тестирование в 3 контейнерах
make role test minimal # Тестирование в 1 контейнере
```
### 🚀 Развертывание (deploy)
**Команда:** `make role deploy`
**Использует:**
- Статический inventory файл `inventory/hosts.ini`
- Реальные серверы
- SSH подключение
**Процесс:**
1. Проверяется наличие `inventory/hosts.ini`
2. Показывается содержимое inventory
3. Запускается dry-run (--check)
4. Запрашивается подтверждение
5. Выполняется развертывание на реальные серверы
**Пример:**
```bash
make role deploy # Развертывание на реальные серверы
```
## Конфигурация
### Для тестирования
- Preset файлы: `molecule/presets/*.yml`
- Динамический inventory создается в `create.yml`
- Контейнеры: Docker
### Для развертывания
- Inventory файл: `inventory/hosts.ini`
- Серверы: Реальные хосты
- Подключение: SSH
## Примеры конфигурации
### Preset для тестирования (molecule/presets/standart.yml)
```yaml
hosts:
- name: u1
family: debian
groups: [test]
- name: u2
family: rhel
groups: [test]
- name: u3
family: debian
groups: [test]
```
### Inventory для развертывания (inventory/hosts.ini)
```ini
[web_servers]
web1 ansible_host=192.168.1.10 ansible_user=ubuntu
web2 ansible_host=192.168.1.11 ansible_user=ubuntu
[db_servers]
db1 ansible_host=192.168.1.20 ansible_user=ubuntu
[all:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
```
## Рекомендации
1. **Сначала тестируйте** с помощью `make role test [preset]`
2. **Затем развертывайте** с помощью `make role deploy`
3. **Используйте разные preset'ы** для разных сценариев тестирования
4. **Настройте inventory** для ваших реальных серверов

View File

@@ -1,652 +0,0 @@
# Troubleshooting
## Автор
Сергей Антропов
Сайт: https://devops.org.ru
## Описание
Этот документ содержит решения наиболее распространенных проблем при работе с универсальной лабораторией.
## Содержание
- [Общие проблемы](#общие-проблемы)
- [Проблемы с Docker](#проблемы-с-docker)
- [Проблемы с Kubernetes](#проблемы-с-kubernetes)
- [Проблемы с портами](#проблемы-с-портами)
- [Проблемы с ресурсами](#проблемы-с-ресурсами)
- [Проблемы с сетью](#проблемы-с-сетью)
- [Проблемы с Ansible](#проблемы-с-ansible)
- [Проблемы с Molecule](#проблемы-с-molecule)
- [Проблемы с пресетами](#проблемы-с-пресетами)
- [Проблемы с отчетами](#проблемы-с-отчетами)
## Общие проблемы
### Проблема: Лаборатория не запускается
**Симптомы:**
- Команда `make lab-up` завершается с ошибкой
- Контейнеры не создаются
- Ошибки в логах Docker
**Решение:**
```bash
# Проверить статус Docker
docker ps
docker version
# Перезапустить Docker
sudo systemctl restart docker
# Очистить Docker
docker system prune -a
# Перезапустить лабораторию
make lab-reset
```
### Проблема: Команды Make не работают
**Симптомы:**
- `make: command not found`
- Ошибки в Makefile
**Решение:**
```bash
# Установить Make
# Ubuntu/Debian
sudo apt-get install make
# CentOS/RHEL
sudo yum install make
# macOS
brew install make
# Проверить версию
make --version
```
### Проблема: Недостаточно прав
**Симптомы:**
- `Permission denied`
- Ошибки доступа к файлам
**Решение:**
```bash
# Проверить права на файлы
ls -la
# Установить права
chmod +x scripts/*.sh
chmod 644 *.yml
# Добавить пользователя в группу docker
sudo usermod -aG docker $USER
newgrp docker
```
## Проблемы с Docker
### Проблема: Docker daemon не запущен
**Симптомы:**
- `Cannot connect to the Docker daemon`
- `docker: command not found`
**Решение:**
```bash
# Запустить Docker daemon
sudo systemctl start docker
sudo systemctl enable docker
# Проверить статус
sudo systemctl status docker
# Проверить доступ
docker ps
```
### Проблема: Недостаточно места на диске
**Симптомы:**
- `No space left on device`
- Ошибки создания контейнеров
**Решение:**
```bash
# Проверить использование диска
df -h
# Очистить Docker
docker system prune -a
docker volume prune
docker network prune
# Удалить неиспользуемые образы
docker image prune -a
```
### Проблема: Конфликты портов
**Симптомы:**
- `Port is already in use`
- Ошибки привязки портов
**Решение:**
```bash
# Найти процесс, использующий порт
sudo netstat -tulpn | grep :8080
sudo lsof -i :8080
# Убить процесс
sudo kill -9 <PID>
# Или изменить порт в пресете
publish:
- "8081:80" # Вместо 8080:80
```
### Проблема: DinD контейнеры не работают
**Симптомы:**
- DinD контейнеры не запускаются
- Ошибки Docker-in-Docker
**Решение:**
```bash
# Проверить privileged режим
docker run --privileged -d docker:dind
# Проверить доступ к Docker socket
docker run -v /var/run/docker.sock:/var/run/docker.sock docker:latest ps
# Перезапустить с правильными параметрами
make lab-reset
make lab-create
```
## Проблемы с Kubernetes
### Проблема: Kind кластер не создается
**Симптомы:**
- `kind create cluster` завершается с ошибкой
- Кластер не доступен
**Решение:**
```bash
# Проверить Kind
kind version
# Удалить существующие кластеры
kind delete cluster --name lab
# Очистить Docker
docker system prune -a
# Пересоздать кластер
make lab-create
```
### Проблема: kubectl не работает
**Симптомы:**
- `kubectl: command not found`
- Ошибки подключения к кластеру
**Решение:**
```bash
# Установить kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
# Проверить конфигурацию
kubectl config get-contexts
# Переключиться на правильный контекст
kubectl config use-context kind-lab
```
### Проблема: Pods не запускаются
**Симптомы:**
- Pods в состоянии Pending
- Ошибки в логах pods
**Решение:**
```bash
# Проверить статус pods
kubectl get pods -A
kubectl describe pod <pod-name>
# Проверить события
kubectl get events --sort-by=.metadata.creationTimestamp
# Проверить ресурсы
kubectl top nodes
kubectl top pods
```
### Проблема: Istio не устанавливается
**Симптомы:**
- Istio компоненты не запускаются
- Ошибки в Istio логах
**Решение:**
```bash
# Проверить Istio
istioctl version
# Переустановить Istio
istioctl uninstall --purge
istioctl install --set profile=demo
# Проверить статус
kubectl get pods -n istio-system
```
## Проблемы с портами
### Проблема: Порт уже используется
**Симптомы:**
- `bind: address already in use`
- Ошибки привязки портов
**Решение:**
```bash
# Найти процесс
sudo lsof -i :8080
# Убить процесс
sudo kill -9 <PID>
# Или изменить порт в пресете
publish:
- "8081:80"
```
### Проблема: Port-forward не работает
**Симптомы:**
- Port-forward не устанавливается
- Ошибки подключения
**Решение:**
```bash
# Остановить все port-forward
make kube-pf-stop
# Проверить доступность сервиса
kubectl get svc -n istio-system
# Перезапустить port-forward
make kiali-port-forward CLUSTER=lab
```
## Проблемы с ресурсами
### Проблема: Недостаточно памяти
**Симптомы:**
- `Out of memory`
- Контейнеры завершаются
**Решение:**
```bash
# Проверить память
free -h
docker stats
# Ограничить ресурсы
docker run --memory=512m your-image
# Или уменьшить количество контейнеров в пресете
```
### Проблема: Недостаточно CPU
**Симптомы:**
- Медленная работа
- Высокая нагрузка на CPU
**Решение:**
```bash
# Проверить CPU
top
htop
# Ограничить CPU
docker run --cpus=1.0 your-image
# Или использовать более легкие образы
```
### Проблема: Недостаточно места на диске
**Симптомы:**
- `No space left on device`
- Ошибки записи
**Решение:**
```bash
# Проверить место
df -h
# Очистить Docker
docker system prune -a
docker volume prune
# Удалить неиспользуемые образы
docker image prune -a
```
## Проблемы с сетью
### Проблема: Контейнеры не могут связаться
**Симптомы:**
- Ping не работает между контейнерами
- Ошибки сети
**Решение:**
```bash
# Проверить сеть
docker network ls
docker network inspect labnet
# Пересоздать сеть
docker network rm labnet
docker network create labnet
# Перезапустить лабораторию
make lab-reset
```
### Проблема: DNS не работает
**Симптомы:**
- Не удается разрешить имена
- Ошибки DNS
**Решение:**
```bash
# Проверить DNS
nslookup google.com
# Перезапустить Docker
sudo systemctl restart docker
# Проверить resolv.conf
cat /etc/resolv.conf
```
## Проблемы с Ansible
### Проблема: Ansible не найден
**Симптомы:**
- `ansible: command not found`
- Ошибки выполнения playbook
**Решение:**
```bash
# Установить Ansible
pip install ansible
# Или через пакетный менеджер
sudo apt-get install ansible
# Проверить версию
ansible --version
```
### Проблема: Ошибки в playbook
**Симптомы:**
- Синтаксические ошибки
- Ошибки выполнения задач
**Решение:**
```bash
# Проверить синтаксис
ansible-playbook --syntax-check playbook.yml
# Запустить в режиме отладки
ansible-playbook -vvv playbook.yml
# Проверить инвентарь
ansible-inventory --list
```
### Проблема: Ошибки подключения
**Симптомы:**
- `Connection refused`
- Ошибки SSH
**Решение:**
```bash
# Проверить подключение
ansible all -m ping
# Проверить SSH ключи
ssh-keygen -t rsa -b 4096
ssh-copy-id user@host
# Или использовать пароль
ansible all -m ping -k
```
## Проблемы с Molecule
### Проблема: Molecule не найден
**Симптомы:**
- `molecule: command not found`
- Ошибки выполнения molecule
**Решение:**
```bash
# Установить Molecule
pip install molecule
# Или через пакетный менеджер
sudo apt-get install molecule
# Проверить версию
molecule --version
```
### Проблема: Ошибки в molecule.yml
**Симптомы:**
- Синтаксические ошибки в конфигурации
- Ошибки валидации
**Решение:**
```bash
# Проверить синтаксис
molecule syntax
# Проверить конфигурацию
molecule lint
# Исправить ошибки
molecule validate
```
### Проблема: Ошибки драйвера
**Симптомы:**
- Ошибки Docker драйвера
- Проблемы с контейнерами
**Решение:**
```bash
# Проверить драйвер
molecule driver list
# Установить Docker драйвер
pip install molecule-docker
# Перезапустить Molecule
molecule destroy
molecule create
```
## Проблемы с пресетами
### Проблема: Пресет не найден
**Симптомы:**
- `File not found`
- Ошибки загрузки пресета
**Решение:**
```bash
# Проверить путь
ls -la molecule/presets/
# Проверить синтаксис YAML
yamllint molecule/presets/your-preset.yml
# Исправить ошибки
molecule validate
```
### Проблема: Ошибки в пресете
**Симптомы:**
- Синтаксические ошибки
- Ошибки валидации
**Решение:**
```bash
# Проверить синтаксис
yamllint molecule/presets/your-preset.yml
# Проверить структуру
molecule validate
# Исправить ошибки
molecule syntax
```
## Проблемы с отчетами
### Проблема: HTML отчет не генерируется
**Симптомы:**
- `File not found`
- Ошибки генерации отчета
**Решение:**
```bash
# Проверить JSON файл
ls -la reports/
cat reports/lab-health.json
# Перезапустить верификацию
make lab-verify
# Сгенерировать отчет
make lab-report
```
### Проблема: Отчет пустой
**Симптомы:**
- Отчет не содержит данных
- Ошибки в JSON
**Решение:**
```bash
# Проверить JSON
jq . reports/lab-health.json
# Перезапустить тест
make lab-test
# Проверить логи
make lab-verify
```
## Полезные команды для диагностики
### Общие команды
```bash
# Проверить статус системы
docker ps
docker images
docker network ls
docker volume ls
# Проверить ресурсы
free -h
df -h
top
# Проверить сеть
netstat -tulpn
ss -tulpn
```
### Команды для Kubernetes
```bash
# Проверить кластеры
kind get clusters
kubectl config get-contexts
# Проверить ресурсы
kubectl get nodes
kubectl get pods -A
kubectl get svc -A
# Проверить события
kubectl get events --sort-by=.metadata.creationTimestamp
```
### Команды для Ansible
```bash
# Проверить инвентарь
ansible-inventory --list
ansible all -m ping
# Проверить playbook
ansible-playbook --syntax-check playbook.yml
ansible-playbook --check playbook.yml
```
## Получение помощи
Если проблема не решается:
1. **Проверьте логи:**
```bash
docker logs <container-name>
kubectl logs <pod-name>
```
2. **Создайте issue:**
- Опишите проблему
- Приложите логи
- Укажите версии компонентов
3. **Обратитесь к сообществу:**
- GitHub Discussions
- Discord/Slack каналы
- Форумы Ansible
4. **Проверьте документацию:**
- [Основная документация](universal-lab.md)
- [Примеры использования](examples.md)
- [API Reference](api.md)

View File

@@ -1,295 +0,0 @@
# Универсальная лаборатория для тестирования Ansible ролей
## Автор
Сергей Антропов
Сайт: https://devops.org.ru
## Описание
Это универсальная лаборатория для тестирования Ansible ролей, созданная на основе предложений ChatGPT. Лаборатория поддерживает:
- **Docker-in-Docker (DinD)** - полная изоляция контейнеров
- **Docker-outside-of-Docker (DOoD)** - использование хостового Docker
- **Kind кластеры** - локальные Kubernetes кластеры
- **Helm charts** - nginx, prometheus-stack
- **Istio service mesh** - с Kiali для мониторинга
- **Prometheus + Grafana** - с автопровижинингом дашбордов
- **HTML отчеты** - красивые отчеты о результатах тестирования
## Структура проекта
```
molecule/
├── universal/ # Универсальная лаборатория
│ ├── molecule.yml # Конфигурация Molecule
│ ├── vars.yml # Переменные лаборатории
│ ├── create.yml # Создание инфраструктуры
│ ├── converge.yml # Запуск ролей
│ ├── verify.yml # Проверка работы
│ └── destroy.yml # Очистка
├── presets/ # Пресеты для разных сценариев
│ └── k8s-kind.yml # Пресет для Kubernetes
└── default/ # Старый сценарий (для совместимости)
files/
├── requirements.yml # Коллекции Ansible
├── playbooks/
│ └── site.yml # Основной playbook
└── k8s/ # Kubernetes манифесты
└── istio/ # Istio конфигурации
roles/ # Ваши Ansible роли
```
## Использование
### 1. Подготовка
```bash
# Создать файл с паролем для vault
echo "test" > vault-password.txt
# Создать каталог для ролей
mkdir -p roles
# Скопировать переменные окружения
cp env.example .env
# Отредактировать .env под ваши нужды
```
### 2. Запуск лаборатории
```bash
# Поднять контроллер
make lab-up
# Создать инфраструктуру
make lab-create
# Запустить роли
make lab-converge
# Проверить работу
make lab-verify
# Сгенерировать HTML отчет
make lab-report
# Уничтожить лабораторию
make lab-destroy
```
### 3. Управление лабораторией
```bash
# Полный цикл тестирования
make lab-test
# Снапшоты и восстановление
make lab-snapshot # Сохранить состояние
make lab-restore # Восстановить из снапшота
make lab-cleanup # Очистить все
# Сброс лаборатории
make lab-reset
```
### 4. Пресеты для разных сценариев
#### 🏗️ Классические пресеты (systemd контейнеры)
```bash
# Минимальная лаборатория (1-3 машины)
make lab-test LAB_SPEC=molecule/presets/minimal.yml
# Веб-приложение (3-5 машин)
make lab-test LAB_SPEC=molecule/presets/webapp.yml
# Микросервисы (5-8 машин)
make lab-test LAB_SPEC=molecule/presets/microservices.yml
# Высокая доступность (6-10 машин)
make lab-test LAB_SPEC=molecule/presets/ha.yml
# Kubernetes кластер (8-12 машин)
make lab-test LAB_SPEC=molecule/presets/k8s-cluster.yml
# CI/CD пайплайн (10-15 машин)
make lab-test LAB_SPEC=molecule/presets/cicd.yml
# Big Data кластер (12-18 машин)
make lab-test LAB_SPEC=molecule/presets/bigdata.yml
# Service Mesh (15-20 машин)
make lab-test LAB_SPEC=molecule/presets/servicemesh.yml
# Enterprise (18-20 машин)
make lab-test LAB_SPEC=molecule/presets/enterprise.yml
# Максимальный (20 машин)
make lab-test LAB_SPEC=molecule/presets/maximum.yml
```
#### ☸️ Kubernetes пресеты
```bash
# Kubernetes Single Node (1 кластер)
make lab-test LAB_SPEC=molecule/presets/k8s-single.yml
# Kubernetes Multi-Cluster (3 кластера)
make lab-test LAB_SPEC=molecule/presets/k8s-multi.yml
# Kubernetes + Istio Full Stack (1 кластер с полным стеком)
make lab-test LAB_SPEC=molecule/presets/k8s-istio-full.yml
```
#### 🐳 Docker-in-Docker (DinD) пресеты
```bash
# DinD Simple (3 DinD контейнера)
make lab-test LAB_SPEC=molecule/presets/dind-simple.yml
# DinD Swarm (5 DinD контейнеров)
make lab-test LAB_SPEC=molecule/presets/dind-swarm.yml
# DinD Compose (4 DinD контейнера)
make lab-test LAB_SPEC=molecule/presets/dind-compose.yml
```
#### 🔗 Docker-outside-of-Docker (DOoD) пресеты
```bash
# DOoD Simple (3 DOoD контейнера)
make lab-test LAB_SPEC=molecule/presets/dood-simple.yml
# DOoD Mixed (5 DOoD + 2 systemd)
make lab-test LAB_SPEC=molecule/presets/dood-mixed.yml
```
#### 🔀 Смешанные пресеты
```bash
# Mixed Kubernetes + DinD (1 K8s + 3 DinD)
make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dind.yml
# Mixed Kubernetes + DOoD (1 K8s + 3 DOoD)
make lab-test LAB_SPEC=molecule/presets/mixed-k8s-dood.yml
# Mixed Full Stack (1 K8s + 2 DinD + 2 DOoD + 2 systemd)
make lab-test LAB_SPEC=molecule/presets/mixed-full.yml
```
### 3. Работа с Kubernetes
```bash
# Войти в контейнер с kubectl
make kube-sh
# Выполнить команду kubectl
make kube-cmd CLUSTER=lab CMD="get pods -A"
# Войти в toolbox pod
make kube-enter CLUSTER=lab
# Port-forward для Kiali
make kiali-port-forward CLUSTER=lab
# Port-forward для Istio Gateway
make istio-gw-port-forward CLUSTER=lab
```
## Конфигурация
### Переменные лаборатории (molecule/universal/vars.yml)
```yaml
# Сеть для лаборатории
docker_network: labnet
# Образы для разных семейств ОС
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
# Определение хостов
hosts:
- name: etcd1
group: etcd
family: debian
- name: app-dind
group: apps
type: dind
publish:
- "8080:8080"
# Kind кластеры
kind_clusters:
- name: lab
workers: 2
addons:
ingress_nginx: true
istio: true
kiali: true
```
## Особенности
### 1. Автогенерация инвентаря
Инвентарь генерируется автоматически на основе определения хостов в `vars.yml`.
### 2. Поддержка DinD и DOoD
- **DinD**: Полная изоляция, каждый хост имеет свой Docker daemon
- **DOoD**: Использование хостового Docker, меньше ресурсов
### 3. Kubernetes интеграция
- Автоматическое создание Kind кластеров
- Установка Ingress NGINX, Metrics Server
- Поддержка Istio и Kiali
- Prometheus Stack с Grafana
### 4. Мониторинг и отчеты
- Автоматическая генерация HTML отчетов
- Интеграция с Prometheus и Grafana
- Дашборды для Istio
## Troubleshooting
### Проблемы с образами
Если возникают проблемы с загрузкой образов, обновите `vars.yml`:
```yaml
images:
debian: "ubuntu:22.04" # Используйте стандартные образы
rhel: "centos:8"
```
### Проблемы с Docker
Убедитесь, что Docker socket доступен:
```bash
ls -la /var/run/docker.sock
```
### Проблемы с Molecule
Если возникают проблемы с Molecule, попробуйте:
```bash
# Очистить кэш
make lab-reset
# Проверить конфигурацию
docker exec ansible-controller bash -lc 'molecule lint -s universal'
```
## Дальнейшее развитие
1. **Добавить поддержку Terraform** для создания инфраструктуры
2. **Интегрировать с GitLab CI/CD** для автоматического тестирования
3. **Добавить поддержку ARM64** для тестирования на Apple Silicon
4. **Создать веб-интерфейс** для управления лабораторией
5. **Добавить поддержку OpenShift** для enterprise сценариев
## Лицензия
MIT License
## Контакты
- Автор: Сергей Антропов
- Сайт: https://devops.org.ru
- Email: [ваш email]

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

@@ -1,69 +0,0 @@
# =============================================================================
# Ansible Template Environment Configuration
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# =============================================================================
# Основные настройки проекта
PROJECT_NAME=ansible-template
VERSION=0.1.0
AUTHOR="Сергей Антропов"
SITE="https://devops.org.ru"
# Docker настройки
DOCKER_IMAGE=quay.io/ansible/creator-ee:latest
DOCKER_NETWORK=labnet
DOCKER_COMPOSE=docker compose
# 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

View File

@@ -1,69 +0,0 @@
{
"id": null,
"uid": "istio-overview",
"title": "Istio • Overview",
"schemaVersion": 36,
"version": 1,
"timezone": "browser",
"tags": ["istio", "sre", "mesh"],
"panels": [
{
"type": "stat",
"title": "Global RPS",
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 0},
"targets": [
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\"}[5m]))",
"legendFormat": "rps"
}
]
},
{
"type": "stat",
"title": "Success Rate",
"gridPos": {"h": 4, "w": 6, "x": 6, "y": 0},
"targets": [
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\",response_code!~\"5..\"}[5m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[5m]))",
"legendFormat": "success"
}
],
"options": {"reduceOptions":{"calcs":["lastNotNull"]},"colorMode":"value","graphMode":"none"},
"fieldConfig":{"defaults":{"unit":"percentunit","min":0,"max":1}}
},
{
"type": "timeseries",
"title": "Latency (ms) p50/p95/p99",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 4},
"targets": [
{
"expr": "histogram_quantile(0.5, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[5m])) by (le))",
"legendFormat": "p50"
},
{
"expr": "histogram_quantile(0.95, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[5m])) by (le))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[5m])) by (le))",
"legendFormat": "p99"
}
],
"fieldConfig":{"defaults":{"unit":"ms"}}
},
{
"type": "timeseries",
"title": "RPS by Workload",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 12},
"targets": [
{
"expr": "sum by (destination_workload) (rate(istio_requests_total{reporter=\"destination\"}[5m]))",
"legendFormat": "{{destination_workload}}"
}
]
}
],
"templating": {
"list": []
}
}

View File

@@ -1,80 +0,0 @@
{
"id": null,
"uid": "service-sli",
"title": "Service • SLI",
"schemaVersion": 36,
"version": 1,
"timezone": "browser",
"tags": ["istio", "sre", "sli"],
"templating": {
"list": [
{
"name": "namespace",
"type": "query",
"datasource": "${DS_PROMETHEUS}",
"query": "label_values(istio_requests_total, destination_namespace)",
"refresh": 1
},
{
"name": "workload",
"type": "query",
"datasource": "${DS_PROMETHEUS}",
"query": "label_values(istio_requests_total{destination_namespace=\"$namespace\"}, destination_workload)",
"refresh": 1
}
]
},
"panels": [
{
"type": "stat",
"title": "Success Rate",
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 0},
"targets": [
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\",response_code!~\"5..\"}[5m])) / sum(rate(istio_requests_total{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\"}[5m]))",
"legendFormat": "success"
}
],
"fieldConfig":{"defaults":{"unit":"percentunit","min":0,"max":1}}
},
{
"type": "timeseries",
"title": "Latency (ms) p50/p95/p99",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 4},
"targets": [
{
"expr": "histogram_quantile(0.5, sum by (le) (rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\"}[5m])))",
"legendFormat": "p50"
},
{
"expr": "histogram_quantile(0.95, sum by (le) (rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\"}[5m])))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, sum by (le) (rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\"}[5m])))",
"legendFormat": "p99"
}
],
"fieldConfig":{"defaults":{"unit":"ms"}}
},
{
"type": "timeseries",
"title": "RPS (2xx/4xx/5xx)",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 12},
"targets": [
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\",response_code=~\"2..\"}[5m]))",
"legendFormat": "2xx"
},
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\",response_code=~\"4..\"}[5m]))",
"legendFormat": "4xx"
},
{
"expr": "sum(rate(istio_requests_total{reporter=\"destination\",destination_namespace=\"$namespace\",destination_workload=\"$workload\",response_code=~\"5..\"}[5m]))",
"legendFormat": "5xx"
}
]
}
]
}

View File

@@ -1,39 +0,0 @@
---
# Istio Telemetry для сбора метрик
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
selector: {}
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_DURATION
tagOverrides:
"destination_workload": { operation: UPSERT, value: "%DESTINATION_WORKLOAD%" }
"destination_namespace": { operation: UPSERT, value: "%DESTINATION_NAMESPACE%" }
"request_host": { operation: UPSERT, value: "%REQUEST_HOST%" }
histogram:
buckets:
- 1
- 5
- 10
- 25
- 50
- 100
- 250
- 500
- 1000
- 2000
- 5000
- match:
metric: REQUEST_COUNT
tagOverrides:
"response_code": { operation: UPSERT, value: "%RESPONSE_CODE%" }

View File

@@ -1,66 +0,0 @@
---
# Istio Traffic Policy для управления трафиком
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# mesh-wide mTLS STRICT
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
---
# Пример строгой политики для bookinfo (pool + outlier)
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: productpage-policy
namespace: bookinfo
spec:
host: productpage.bookinfo.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 1000
maxRequestsPerConnection: 100
outlierDetection:
consecutive5xx: 5
interval: 5s
baseEjectionTime: 30s
maxEjectionPercent: 50
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-policy
namespace: bookinfo
spec:
host: reviews.bookinfo.svc.cluster.local
subsets:
- name: v1
labels: { version: v1 }
- name: v2
labels: { version: v2 }
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 1000
maxRequestsPerConnection: 100
outlierDetection:
consecutive5xx: 3
interval: 5s
baseEjectionTime: 30s
maxEjectionPercent: 50

View File

@@ -1,93 +0,0 @@
---
# 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

View File

@@ -1,45 +0,0 @@
---
# Основной playbook для универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Base deps
hosts: all
become: true
tasks:
- name: Update apt cache (Debian)
apt:
update_cache: true
when: ansible_os_family == 'Debian'
changed_when: false
- name: Update yum cache (RHEL)
yum:
update_cache: true
when: ansible_os_family == 'RedHat'
changed_when: false
- name: Common tools
package:
name:
- curl
- jq
- ca-certificates
- iproute2
- iputils-ping
- procps
- net-tools
- sudo
- vim
- wget
- unzip
state: present
# Развертывание инфраструктуры
- name: Deploy infrastructure
hosts: all
become: true
tasks:
- name: Infrastructure placeholder
debug:
msg: "Инфраструктура готова для настройки"

View File

@@ -1,8 +0,0 @@
---
# Коллекции Ansible для универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
collections:
- name: community.docker
- name: community.general

16
inventory/hosts.ini Normal file
View File

@@ -0,0 +1,16 @@
# Инвентори для развертывания на реальные серверы
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Примеры серверов (замените на ваши реальные серверы)
[web_servers]
# web1 ansible_host=192.168.1.10 ansible_user=ubuntu
# web2 ansible_host=192.168.1.11 ansible_user=ubuntu
[db_servers]
# db1 ansible_host=192.168.1.20 ansible_user=ubuntu
[all:vars]
# Общие переменные для всех серверов
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

View File

@@ -1,79 +1,75 @@
---
# Запуск ролей в универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- hosts: localhost
gather_facts: false
vars:
# Перечисли файлы/глобы с секретами (можно добавлять свои пути)
# Получаем preset из переменной окружения или используем default
preset_name: "{{ lookup('env', 'MOLECULE_PRESET') | default('default') }}"
preset_file: "/workspace/molecule/presets/{{ preset_name }}.yml"
# перечисли файлы/глобы, которые нужно временно расшифровать
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
- name: Load preset configuration
include_vars: "{{ preset_file }}"
when: preset_file is file
ignore_errors: true
- name: Install collections
community.docker.docker_container_exec:
container: ansible-controller
command: bash -lc "ansible-galaxy collection install -r /ansible/files/requirements.yml || true"
command: bash -lc "ansible-galaxy collection install -r /ansible/requirements.yml --force --no-deps --upgrade >/dev/null 2>&1 || 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;
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
[ -f "$f" ] || continue;
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
echo "[vault] decrypt for run: $f";
ansible-vault decrypt --vault-password-file /ansible/vault/.vault "$f";
ansible-vault decrypt --vault-password-file /ansible/vault-password.txt "$f";
done
done
'
- name: Run external playbook (your roles live in /ansible/roles)
- name: Run lab playbook
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.yml /ansible/files/playbooks/site.yml
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml
"
# --- Пост-этап: всегда шифруем обратно ---
- name: Post-run vault — re-encrypt everything
- name: Post-run — re-encrypt secrets
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -euo pipefail;
shopt -s nullglob globstar;
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
[ -f "$f" ] || continue;
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/.vault "$f" || true;
ansible-vault encrypt --encrypt-vault-id default --vault-password-file /ansible/vault-password.txt "$f" || true;
fi
done
done
'
ignore_errors: true
ignore_errors: true

165
molecule/default/create.yml Normal file
View File

@@ -0,0 +1,165 @@
---
- 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
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
images:
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:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
hosts:
- name: u1
family: debian
groups: [test]
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
include_vars: "{{ preset_file }}"
when: preset_file is file
ignore_errors: true
- name: Ensure network exists
community.docker.docker_network:
name: "{{ docker_network }}"
state: present
# SYSTEMD nodes
- name: Pull systemd images
community.docker.docker_image:
name: "{{ images[item.family] }}"
source: pull
loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
- name: Start systemd nodes
community.docker.docker_container:
name: "{{ item.name }}"
image: "{{ images[item.family] }}"
networks:
- name: "{{ docker_network }}"
privileged: "{{ systemd_defaults.privileged }}"
command: "{{ systemd_defaults.command }}"
volumes: "{{ systemd_defaults.volumes | default([]) + (item.volumes | default([])) }}"
tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
published_ports: "{{ item.publish | default([]) }}"
environment: "{{ item.env | default({}) }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
# DinD nodes
- name: Start DinD nodes (docker:27-dind)
community.docker.docker_container:
name: "{{ item.name }}"
image: "docker:27-dind"
networks:
- name: "{{ docker_network }}"
privileged: true
environment:
DOCKER_TLS_CERTDIR: ""
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_control: { label: "{{ item.name }}" }
# DOoD nodes (mount docker.sock)
- name: Start DOoD nodes (systemd + docker.sock mount)
community.docker.docker_container:
name: "{{ item.name }}"
image: "{{ images[item.family] }}"
networks:
- name: "{{ docker_network }}"
privileged: "{{ systemd_defaults.privileged }}"
command: "{{ systemd_defaults.command }}"
volumes: "{{ (systemd_defaults.volumes | default([])) + ['/var/run/docker.sock:/var/run/docker.sock'] + (item.volumes | default([])) }}"
tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
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_control: { label: "{{ item.name }}" }
when: item.family is defined and images[item.family] is defined
# Build groups map
- name: Initialize groups map
set_fact:
groups_map: {}
- name: Append hosts to groups
set_fact:
groups_map: "{{ groups_map | combine({ item_group: (groups_map[item_group] | default([])) + [item_name] }) }}"
loop: "{{ hosts | subelements('groups', skip_missing=True) }}"
loop_control:
label: "{{ item.0.name }}"
vars:
item_name: "{{ item.0.name }}"
item_group: "{{ item.1 }}"
# Render inventory
- name: Render inventory ini
set_fact:
inv_content: |
[all:vars]
ansible_connection=community.docker.docker
ansible_python_interpreter=/usr/bin/python3
{% for group, members in (groups_map | dictsort) %}
[{{ group }}]
{% for h in members %}{{ h }}
{% endfor %}
{% endfor %}
[all]
{% for h in hosts %}{{ h.name }}
{% endfor %}
- name: Write inventory file
copy:
dest: "{{ generated_inventory }}"
content: "{{ inv_content }}"
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

@@ -0,0 +1,60 @@
---
- 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
- name: Stop and remove containers
community.docker.docker_container:
name: "{{ item.name }}"
state: absent
force_kill: true
loop: "{{ hosts }}"
loop_control: { label: "{{ item.name }}" }
ignore_errors: true
- name: Remove DinD volumes
community.docker.docker_volume:
name: "{{ item.name }}-docker"
state: absent
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
loop_control: { label: "{{ item.name }}" }
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
community.docker.docker_network:
name: "{{ docker_network }}"
state: absent
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 }}

View File

@@ -0,0 +1,38 @@
---
# Универсальная конфигурация Molecule
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
driver:
name: docker
platforms:
# Платформы будут созданы динамически через preset файлы
- name: placeholder
image: ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy
pre_build_image: true
provisioner:
name: ansible
config_options:
defaults:
stdout_callback: yaml
env:
ANSIBLE_STDOUT_CALLBACK: yaml
inventory:
links:
hosts: "${MOLECULE_EPHEMERAL_DIRECTORY}/inventory/hosts.ini"
playbooks:
create: create.yml
converge: converge.yml
destroy: destroy.yml
dependency:
name: galaxy
verifier:
name: ansible
lint: |-
set -e
ansible-lint /workspace/roles/

29
molecule/default/site.yml Normal file
View File

@@ -0,0 +1,29 @@
---
# Универсальный плейбук для тестирования
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Base deps
hosts: all
become: true
tasks:
- name: Update apt cache (Debian)
apt:
update_cache: true
when: ansible_os_family == 'Debian'
changed_when: false
- name: Common tools
raw: dnf install -y curl jq ca-certificates iproute2 iputils procps-ng net-tools sudo vim || yum install -y curl jq ca-certificates iproute2 iputils procps-ng net-tools sudo vim || apt-get update && apt-get install -y curl jq ca-certificates iproute2 iputils-ping procps net-tools sudo vim || true
ignore_errors: true
- name: Update ansible-lint
raw: pip install --upgrade ansible-lint --quiet --no-warn-script-location || true
ignore_errors: true
- name: Install ansible collections
raw: ansible-galaxy collection install -r requirements.yml --force --no-deps --upgrade || true
ignore_errors: true
- import_playbook: ../../deploy.yml

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

@@ -0,0 +1,29 @@
---
#description: Стандартный пресет по умолчанию для тестирования с 2 хостами (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:
# Стандартный набор - 2 хоста для базового тестирования
- name: u1
family: debian
groups: [test, web]
- name: u2
family: rhel
groups: [test, web]

View File

@@ -0,0 +1,44 @@
---
#description: Пресет с Docker контейнерами (DinD + DOoD) для тестирования Docker-задач
# Автор: Сергей Антропов
# Сайт: 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:
# Тестовые хосты
- name: test1
family: debian
groups: [test]
- name: test2
family: rhel
groups: [test]
# DinD узел (Docker-in-Docker)
- name: docker1
type: dind
groups: [docker]
publish: ["8080:8080"]
# DOoD узел (Docker-out-of-Docker)
- name: dood1
type: dood
family: debian
groups: [dood]
publish: ["8081:8081"]
env:
DOCKER_HOST: unix:///var/run/docker.sock

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,17 +1,25 @@
---
# Минимальный пресет лаборатории
#description: Минимальный пресет для быстрого тестирования с 1 хостом (Debian)
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
hosts:
- name: host1
family: debian
groups: [all]
docker_network: labnet
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
features:
docker: true
dind: false
k8s: false
istio: false
monitoring: false
chaos: false
# systemd-ready образы
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
hosts:
# Минимальный набор - один хост
- name: u1
family: debian
groups: [test]

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

@@ -0,0 +1,73 @@
---
#description: Пресет для нагрузочного тестирования с 12 хостами (серверы + БД + кэш)
# Автор: Сергей Антропов
# Сайт: 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:
# Основные серверы (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"]

View File

@@ -0,0 +1,76 @@
---
#description: Пресет для тестирования безопасности с 10 хостами (bastion + internal + monitoring)
# Автор: Сергей Антропов
# Сайт: 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:
# 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"

View File

@@ -0,0 +1,32 @@
---
#description: Стандартный пресет для тестирования с 3 хостами (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:
# Стандартный набор - 3 хоста
- name: u1
family: debian
groups: [test]
- name: u2
family: rhel
groups: [test]
- name: u3
family: debian
groups: [test]

25
molecule/presets/test.yml Normal file
View File

@@ -0,0 +1,25 @@
---
#description: Минимальный пресет для быстрого тестирования с 1 хостом (Debian)
# Автор: Сергей Антропов
# Сайт: 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"
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs: ["/run", "/run/lock"]
capabilities: ["SYS_ADMIN"]
hosts:
# Минимальный набор - один хост
- name: u1
family: debian
groups: [test]

View File

@@ -1,296 +0,0 @@
---
# Создание инфраструктуры универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- hosts: localhost
gather_facts: false
vars_files:
- vars.yml
tasks:
- name: Ensure network exists
community.docker.docker_network:
name: "{{ docker_network }}"
state: present
- name: Pull systemd images
community.docker.docker_image:
name: "{{ images[item.family] }}"
source: pull
loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control:
label: "{{ item.name }}"
- name: Start systemd nodes
community.docker.docker_container:
name: "{{ item.name }}"
image: "{{ images[item.family] }}"
networks:
- name: "{{ docker_network }}"
privileged: "{{ systemd_defaults.privileged }}"
command: "{{ systemd_defaults.command }}"
volumes: "{{ systemd_defaults.volumes }}"
tmpfs: "{{ systemd_defaults.tmpfs }}"
capabilities: "{{ systemd_defaults.capabilities }}"
published_ports: "{{ item.publish | default([]) }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','undefined') | list }}"
loop_control:
label: "{{ item.name }}"
- name: Start DinD nodes
community.docker.docker_container:
name: "{{ item.name }}"
image: "docker:27-dind"
privileged: true
environment:
DOCKER_TLS_CERTDIR: ""
networks:
- name: "{{ docker_network }}"
published_ports: "{{ item.publish | default([]) }}"
volumes:
- "{{ item.name }}-docker:/var/lib/docker"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
loop_control:
label: "{{ item.name }}"
- name: Start DOoD nodes
community.docker.docker_container:
name: "{{ item.name }}"
image: "{{ images[item.family] }}"
networks:
- name: "{{ docker_network }}"
privileged: "{{ systemd_defaults.privileged }}"
command: "{{ systemd_defaults.command }}"
volumes:
- "{{ systemd_defaults.volumes | default([]) }}"
- "/var/run/docker.sock:/var/run/docker.sock"
tmpfs: "{{ systemd_defaults.tmpfs }}"
capabilities: "{{ systemd_defaults.capabilities }}"
published_ports: "{{ item.publish | default([]) }}"
state: started
restart_policy: unless-stopped
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
loop_control:
label: "{{ item.name }}"
# ---------- Build multi-group map ----------
- name: Init groups map
set_fact:
groups_map: {}
- name: Append hosts to groups
set_fact:
groups_map: >-
{{
groups_map | combine(
{ item_group: (groups_map[item_group] | default([])) + [item_name] }
)
}}
loop: "{{ (hosts | default([])) | subelements('groups', skip_missing=True) }}"
loop_control:
label: "{{ item.0.name }}"
vars:
item_name: "{{ item.0.name }}"
item_group: "{{ item.1 }}"
when: item.0.groups is defined
- name: Append hosts to single group
set_fact:
groups_map: >-
{{
groups_map | combine(
{ item.group: (groups_map[item.group] | default([])) + [item.name] }
)
}}
loop: "{{ hosts | default([]) }}"
loop_control:
label: "{{ item.name }}"
when: item.group is defined and item.groups is not defined
# ---------- INI inventory ----------
- name: Render inventory.ini
set_fact:
inv_ini: |
[all:vars]
ansible_connection=community.docker.docker
ansible_python_interpreter=/usr/bin/python3
{% for group, members in (groups_map | dictsort) %}
[{{ group }}]
{% for h in members %}{{ h }}
{% endfor %}
{% endfor %}
[all]
{% for h in (hosts | default([])) %}{{ h.name }}
{% endfor %}
- name: Write hosts.ini
copy:
dest: "{{ generated_inventory }}"
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:
container: ansible-controller
command: >
bash -lc '
mkdir -p /ansible/.kind;
cat > /ansible/.kind/{{ item.name }}.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
{% if (item.addons|default({})).ingress_nginx|default(false) %}
extraPortMappings:
- containerPort: 80
hostPort: {{ item.ingress_host_http_port | default(8081) }}
protocol: TCP
- containerPort: 443
hostPort: {{ item.ingress_host_https_port | default(8443) }}
protocol: TCP
{% endif %}
{% for i in range(item.workers | default(0)) %}
- role: worker
{% endfor %}
networking:
apiServerAddress: "0.0.0.0"
apiServerPort: {{ item.api_port | default(0) }}
EOF
'
loop: "{{ kind_clusters | default([]) }}"
when: (kind_clusters | default([])) | length > 0
- name: Create kind clusters
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
if kind get clusters | grep -qx "$$n"; then
echo "[kind] cluster $$n already exists";
else
echo "[kind] creating $$n";
kind create cluster --name "$$n" --config "/ansible/.kind/$$n.yaml";
fi
done
'
when: (kind_clusters | default([])) | length > 0
- name: Install Ingress NGINX, Metrics Server, Istio, Kiali, Prometheus Stack (per cluster, if enabled)
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
helm repo add kiali https://kiali.org/helm-charts >/dev/null 2>&1 || true;
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts >/dev/null 2>&1 || true;
helm repo update >/dev/null 2>&1 || true;
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
# ingress-nginx
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("ingress_nginx", False) | to_json }}; then
echo "[addons] ingress-nginx on $$n";
kubectl --context kind-$$n apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml || true;
kubectl --context kind-$$n -n ingress-nginx rollout status deploy/ingress-nginx-controller --timeout=180s || true;
fi
# metrics-server
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("metrics_server", False) | to_json }}; then
echo "[addons] metrics-server on $$n";
kubectl --context kind-$$n apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml || true;
kubectl --context kind-$$n -n kube-system patch deploy metrics-server -p \
"{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"metrics-server\",\"args\":[\"--kubelet-insecure-tls\",\"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname\"]}]}}}}}" || true;
fi
# istio (demo profile)
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("istio", False) | to_json }}; then
echo "[addons] istio (demo profile) on $$n";
istioctl install -y --set profile=demo --context kind-$$n;
kubectl --context kind-$$n -n istio-system rollout status deploy/istiod --timeout=180s || true;
kubectl --context kind-$$n -n istio-system rollout status deploy/istio-ingressgateway --timeout=180s || true;
fi
# kiali (server chart, anonymous auth) — требует istio/metrics
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("kiali", False) | to_json }}; then
echo "[addons] kiali on $$n";
kubectl --context kind-$$n create ns istio-system >/dev/null 2>&1 || true;
helm upgrade --install kiali-server kiali/kiali-server \
--namespace istio-system --kube-context kind-$$n \
--set auth.strategy=anonymous --wait --timeout 180s;
fi
# kube-prometheus-stack (Prometheus + Grafana)
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("prometheus_stack", False) | to_json }}; then
echo "[addons] kube-prometheus-stack on $$n";
kubectl --context kind-$$n create ns monitoring >/dev/null 2>&1 || true;
helm upgrade --install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring --kube-context kind-$$n \
--set grafana.adminPassword=admin \
--set grafana.defaultDashboardsTimezone=browser \
--wait --timeout 600s;
# дождаться графаны
kubectl --context kind-$$n -n monitoring rollout status deploy/monitoring-grafana --timeout=300s || true;
fi
done
'
when: (kind_clusters | default([])) | length > 0
- name: Apply Istio Telemetry + mesh mTLS + Grafana dashboards (per cluster)
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map("quote") | join(" ") }}; do
# Telemetry/mTLS — только если istio есть
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("istio", False) | to_json }}; then
echo "[istio] applying Telemetry + PeerAuthentication on $$n";
kubectl --context kind-$$n -n istio-system apply -f /ansible/files/k8s/istio/telemetry.yaml || true;
kubectl --context kind-$$n -n istio-system apply -f /ansible/files/k8s/istio/trafficpolicy.yaml --dry-run=client -o yaml >/dev/null 2>&1 || true;
# DestinationRule из trafficpolicy — namespace bookinfo, создадим позже в verify после деплоя
fi
# Grafana dashboards (ConfigMap with label grafana_dashboard=1)
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("prometheus_stack", False) | to_json }}; then
echo "[grafana] provisioning dashboards on $$n";
kubectl --context kind-$$n -n monitoring create configmap dashboard-istio-overview \
--from-file=dashboard.json=/ansible/files/grafana/dashboards/istio-overview.json \
--dry-run=client -o yaml | kubectl --context kind-$$n apply -f -;
kubectl --context kind-$$n -n monitoring label configmap dashboard-istio-overview grafana_dashboard=1 --overwrite;
kubectl --context kind-$$n -n monitoring create configmap dashboard-service-sli \
--from-file=dashboard.json=/ansible/files/grafana/dashboards/service-sli.json \
--dry-run=client -o yaml | kubectl --context kind-$$n apply -f -;
kubectl --context kind-$$n -n monitoring label configmap dashboard-service-sli grafana_dashboard=1 --overwrite;
fi
done
'
when: (kind_clusters | default([])) | length > 0

View File

@@ -1,50 +0,0 @@
---
# Уничтожение инфраструктуры универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- hosts: localhost
gather_facts: false
vars_files:
- vars.yml
tasks:
- name: Remove DinD volumes
community.docker.docker_volume:
name: "{{ item.name }}-docker"
state: absent
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
loop_control:
label: "{{ item.name }}"
ignore_errors: true
- name: Remove containers
community.docker.docker_container:
name: "{{ item.name }}"
state: absent
force_kill: true
loop: "{{ hosts }}"
loop_control:
label: "{{ item.name }}"
ignore_errors: true
- name: Remove network
community.docker.docker_network:
name: "{{ docker_network }}"
state: absent
ignore_errors: true
- name: Remove kind clusters
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
if kind get clusters | grep -qx "$$n"; then
echo "[kind] deleting $$n";
kind delete cluster --name "$$n" || true;
fi
done
'
when: (kind_clusters | default([])) | length > 0
ignore_errors: true

View File

@@ -1,61 +0,0 @@
---
# Универсальная лаборатория для тестирования Ansible ролей
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
driver:
name: docker
platforms:
- name: instance-ubuntu
image: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
privileged: true
pre_build_image: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
capabilities:
- "SYS_ADMIN"
tmpfs:
- "/run"
- "/run/lock"
provisioner:
name: ansible
config_options:
defaults:
stdout_callback: yaml
callbacks_enabled: profile_tasks
env:
ANSIBLE_STDOUT_CALLBACK: yaml
ANSIBLE_CALLBACKS_ENABLED: profile_tasks
inventory:
links:
hosts: "${MOLECULE_EPHEMERAL_DIRECTORY}/inventory/hosts.yml"
dependency:
name: galaxy
enabled: false
verifier:
name: ansible
lint: |-
set -e
ansible-lint
scenario:
name: universal
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy

View File

@@ -1,90 +0,0 @@
---
# Конфигурация универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Сеть для лаборатории
docker_network: labnet
# Образы для разных семейств ОС
images:
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
rhel: "quay.io/centos/centos:stream9-systemd"
# Можно использовать собственные образы
# debian: "inecs/ansible:ubuntu"
# rhel: "inecs/ansible:centos"
# Настройки по умолчанию для systemd контейнеров
systemd_defaults:
privileged: true
command: "/sbin/init"
volumes:
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
tmpfs:
- "/run"
- "/run/lock"
capabilities:
- "SYS_ADMIN"
# Определение хостов лаборатории
hosts:
# Пример: etcd кластер
- name: etcd1
group: etcd
family: debian
- name: etcd2
group: etcd
family: debian
- name: etcd3
group: etcd
family: debian
# Пример: PostgreSQL с Patroni
- name: patroni1
group: patroni
family: rhel
- name: patroni2
group: patroni
family: rhel
- name: patroni3
group: patroni
family: rhel
# Пример: HAProxy
- name: haproxy
group: haproxy
family: rhel
publish:
- "5000:5000" # RW порт
- "5001:5001" # RO порт
# Пример: DinD узел для изоляции
- name: app-dind
group: apps
type: dind
publish:
- "8080:8080"
# Пример: DOoD узел (Docker Outside of Docker)
- name: app-dood
group: apps
type: dood
publish:
- "8081:8081"
# Kind кластеры (опционально)
kind_clusters:
- name: lab
workers: 2
api_port: 6443
addons:
ingress_nginx: true
metrics_server: true
istio: true
kiali: true
prometheus_stack: true
ingress_host_http_port: 8081
ingress_host_https_port: 8443
# Пути для файлов
generated_inventory: "${MOLECULE_EPHEMERAL_DIRECTORY}/inventory/hosts.ini"

View File

@@ -1,305 +0,0 @@
---
# Проверка работы универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- hosts: localhost
gather_facts: false
vars:
inv_yaml: "{{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.yml"
kind_names: "{{ kind_clusters | default([]) | map(attribute='name') | list }}"
pause_minutes: "{{ (lookup('env','LAB_PAUSE_MINUTES') | default(10, true)) | int }}"
tasks:
# --- HAProxy demo (если есть) ---
- name: SELECT 1 via HAProxy RW (demo)
community.docker.docker_container_exec:
container: ansible-controller
command: bash -lc "psql -h haproxy -p 5000 -U postgres -d postgres -tAc 'select 1;'"
environment: { PGPASSWORD: postgres }
register: sel_rw
failed_when: false
ignore_errors: true
# --- Idempotence ---
- name: Idempotence run
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.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:
container: ansible-controller
command: >
bash -lc '
set -e;
helm repo add bitnami https://charts.bitnami.com/bitnami >/dev/null 2>&1 || true;
helm repo update >/dev/null 2>&1 || true;
for n in {{ kind_names | map('quote') | join(' ') }}; do
ns="lab-demo"; rel="nginx-$$n";
kubectl --context kind-$$n create ns $$ns >/dev/null 2>&1 || true;
# метка для автосайдкаров Istio — не мешает, если Istio отключен
kubectl --context kind-$$n label ns $$ns istio-injection=enabled --overwrite >/dev/null 2>&1 || true;
echo "[helm] installing $$rel";
helm upgrade --install $$rel bitnami/nginx --namespace $$ns --kube-context kind-$$n --wait --timeout 180s;
# Ingress (ingressClassName: nginx), бэкенд на сервис релиза
cat <<EOF | kubectl --context kind-$$n -n $$ns apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: $$rel
port:
number: 80
EOF
# Toolbox — чтобы можно было "зайти в кластер"
cat <<EOF | kubectl --context kind-$$n -n $$ns apply -f -
apiVersion: apps/v1
kind: Deployment
metadata: { name: toolbox }
spec:
replicas: 1
selector: { matchLabels: { app: toolbox } }
template:
metadata: { labels: { app: toolbox } }
spec:
containers:
- name: sh
image: alpine:3
command: ["/bin/sh","-c","sleep 1000000"]
EOF
kubectl --context kind-$$n -n $$ns rollout status deploy/toolbox --timeout=90s || true
# curl по Ingress с хоста: http://localhost:<mapped>
http_port="{{ (kind_clusters | items2dict(key_name='name', value_name='ingress_host_http_port')).get(n, 8081) }}"
echo "[ingress] test curl http://localhost:${http_port}/";
curl -sS -o /dev/null -w "%{http_code}" "http://localhost:${http_port}/" || true
done
'
register: helm_ingress_toolbox
when: kind_names | length > 0
failed_when: false
# --- Istio/Kiali overview (если включены) ---
- name: Istio & Kiali status
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ kind_names | map('quote') | join(' ') }}; do
echo "=== $$n istio pods ===";
kubectl --context kind-$$n -n istio-system get pods -o wide || true;
echo "=== $$n services (istio-system) ===";
kubectl --context kind-$$n -n istio-system get svc || true;
done
'
register: istio_kiali
when: kind_names | length > 0
failed_when: false
# === Istio Bookinfo demo (если включён Istio) ===
- name: Deploy Istio Bookinfo + Gateway/Routes (per cluster)
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ kind_names | map('quote') | join(' ') }}; do
# проверим что istio есть (namespace и istiod)
if ! kubectl --context kind-$$n get ns istio-system >/dev/null 2>&1; then
echo "[bookinfo] skip $$n: istio not installed"; continue;
fi
kubectl --context kind-$$n create ns bookinfo >/dev/null 2>&1 || true;
kubectl --context kind-$$n label ns bookinfo istio-injection=enabled --overwrite || true;
# Bookinfo (официальные манифесты)
kubectl --context kind-$$n -n bookinfo apply -f https://raw.githubusercontent.com/istio/istio/release-1.22/samples/bookinfo/platform/kube/bookinfo.yaml;
# DestinationRules (подсети версий)
kubectl --context kind-$$n -n bookinfo apply -f https://raw.githubusercontent.com/istio/istio/release-1.22/samples/bookinfo/networking/destination-rule-all.yaml;
# Gateway + VirtualService (route 90% v1, 10% v2 для reviews)
cat <<EOF | kubectl --context kind-$$n -n bookinfo apply -f -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata: { name: bookinfo-gateway }
spec:
selector:
istio: ingressgateway
servers:
- port: { number: 80, name: http, protocol: HTTP }
hosts: ["*"]
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata: { name: bookinfo }
spec:
hosts: ["*"]
gateways: ["bookinfo-gateway"]
http:
- match:
- uri:
prefix: /productpage
- uri:
prefix: /static
- uri:
prefix: /login
- uri:
prefix: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port: { number: 9080 }
- match:
- uri:
prefix: /reviews
route:
- destination:
host: reviews
subset: v1
port: { number: 9080 }
weight: 90
- destination:
host: reviews
subset: v2
port: { number: 9080 }
weight: 10
EOF
# Ждём доступности productpage/reviews
kubectl --context kind-$$n -n bookinfo rollout status deploy/productpage-v1 --timeout=180s || true
kubectl --context kind-$$n -n bookinfo rollout status deploy/reviews-v1 --timeout=180s || true
kubectl --context kind-$$n -n bookinfo rollout status deploy/reviews-v2 --timeout=180s || true
echo "[bookinfo] try curl through Istio IngressGateway (port-forward 8082 if needed)";
done
'
register: istio_bookinfo
when: kind_names | length > 0
failed_when: false
- name: Apply DestinationRule TrafficPolicy for bookinfo (after deploy)
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ kind_names | map("quote") | join(" ") }}; do
if kubectl --context kind-$$n get ns bookinfo >/dev/null 2>&1; then
echo "[istio] traffic policies for bookinfo on $$n";
# из общего файла — применятся только DR в namespace bookinfo
kubectl --context kind-$$n -n bookinfo apply -f /ansible/files/k8s/istio/trafficpolicy.yaml || true;
fi
done
'
when: kind_names | length > 0
failed_when: false
# --- K8s overview (nodes & kube-system pods) ---
- name: Collect k8s overview
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -e;
for n in {{ kind_names | map('quote') | join(' ') }}; do
echo "=== $$n nodes ===";
kubectl --context kind-$$n get nodes -o wide || true;
echo "=== $$n pods kube-system ===";
kubectl --context kind-$$n -n kube-system get pods -o wide || true;
done
'
register: k8s_overview
when: kind_names | length > 0
failed_when: false
# --- Health JSON (для HTML отчёта) ---
- name: Build health report JSON
community.docker.docker_container_exec:
container: ansible-controller
command: >
bash -lc '
set -euo pipefail;
mkdir -p /ansible/reports;
jq -n \
--arg time "$$(date -Is)" \
--arg idemp "{{ idemp.stdout | to_json | replace("\"","\\\"") }}" \
--arg haproxy_sel "{{ sel_rw.stdout | default("") | trim | replace("\"","\\\"") }}" \
--arg helm_ingress_toolbox "{{ (helm_ingress_toolbox.stdout | default("")) | replace("\"","\\\"") }}" \
--arg istio_kiali "{{ (istio_kiali.stdout | default("")) | replace("\"","\\\"") }}" \
--arg istio_bookinfo "{{ (istio_bookinfo.stdout | default("")) | replace("\"","\\\"") }}" \
--arg k8s_overview "{{ (k8s_overview.stdout | default("")) | replace("\"","\\\"") }}" \
"{
timestamp: $$time,
idempotence_raw: $$idemp,
haproxy_select1: $$haproxy_sel,
helm_ingress_toolbox_raw: $$helm_ingress_toolbox,
istio_kiali_raw: $$istio_kiali,
istio_bookinfo_raw: $$istio_bookinfo,
k8s_overview_raw: $$k8s_overview
}" > /ansible/reports/lab-health.json
'
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:
msg: |
========================================
РЕЗУЛЬТАТЫ ПРОВЕРКИ УНИВЕРСАЛЬНОЙ ЛАБОРАТОРИИ:
========================================
Idempotence: {{ '✓ Успешно' if idemp is succeeded else '✗ Ошибка' }}
HAProxy: {{ '✓ Работает' if sel_rw is succeeded else '✗ Недоступен' }}
Kubernetes: {{ '✓ Готов' if k8s_overview is succeeded else '✗ Недоступен' }}
========================================

View File

9
requirements.yml Normal file
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

@@ -1,21 +0,0 @@
# Эта папка содержит Ansible роли
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
#
# Для создания новой роли используйте:
# make role create NAME=my-role
#
# Структура роли:
# roles/my-role/
# ├── tasks/
# │ ├── main.yml
# │ ├── debian.yml
# │ └── redhat.yml
# ├── handlers/main.yml
# ├── templates/
# ├── files/
# ├── vars/main.yml
# ├── defaults/main.yml
# ├── meta/main.yml
# ├── tests/
# └── playbooks/

View File

@@ -1,89 +0,0 @@
# Ansible Roles
Эта папка содержит Ansible роли для универсальной лаборатории.
## Создание новой роли
```bash
# Интерактивное создание роли
make role create NAME=my-role
# Список ролей
make role list
# Управление playbooks роли
make role playbook NAME=my-role
```
## Структура роли
```
roles/my-role/
├── tasks/
│ ├── main.yml # Основные задачи (универсальные)
│ ├── debian.yml # Задачи для Debian/Ubuntu
│ └── redhat.yml # Задачи для RHEL/CentOS
├── handlers/
│ └── main.yml # Обработчики
├── templates/ # Шаблоны Jinja2
├── files/ # Статические файлы
├── vars/
│ └── main.yml # Переменные роли
├── defaults/
│ └── main.yml # Переменные по умолчанию
├── meta/
│ └── main.yml # Метаданные роли
├── tests/ # Тесты роли
└── playbooks/ # Playbooks роли
└── deploy.yml
└── install.yml
```
## Универсальные роли
Все роли создаются **универсальными** для RHEL и Debian семейств:
- **`tasks/main.yml`** - содержит общую логику и включает OS-специфичные задачи
- **`tasks/debian.yml`** - задачи для Debian/Ubuntu (apt, systemd)
- **`tasks/redhat.yml`** - задачи для RHEL/CentOS (yum, systemd)
## Поддерживаемые ОС
- **Debian семейство**: Ubuntu, Debian, Linux Mint
- **RHEL семейство**: CentOS, RHEL, Rocky Linux, AlmaLinux
## Команды управления
```bash
# Создать роль
make role create NAME=nginx
# Редактировать роль
make role edit NAME=nginx
# Тестировать роль
make role test NAME=nginx
# Проверить синтаксис
make role lint
# Развернуть роли
make role deploy
# Информация о роли
make role info NAME=nginx
# Управление playbooks
make role playbook NAME=nginx
```
## Документация
- **[Полное руководство](../docs/roles.md)** - подробная документация по работе с ролями
- **[Примеры использования](../docs/examples.md)** - практические примеры
- **[API Reference](../docs/api.md)** - справочник по API
## Автор
Сергей Антропов
Сайт: https://devops.org.ru

View File

@@ -0,0 +1,60 @@
---
# Переменные по умолчанию для роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Основные настройки nginx
nginx_user: "nginx"
nginx_worker_processes: "auto"
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
# Настройки сервера
nginx_server_name: "{{ ansible_fqdn | default(ansible_hostname) }}"
nginx_listen_port: 80
nginx_root_dir: "/var/www/html"
nginx_index_file: "index.html"
# Настройки логов
nginx_access_log: "/var/log/nginx/access.log"
nginx_error_log: "/var/log/nginx/error.log"
# Настройки безопасности
nginx_server_tokens: "off"
nginx_hide_version: true
# Настройки производительности
nginx_sendfile: "on"
nginx_tcp_nopush: "on"
nginx_tcp_nodelay: "on"
# Настройки gzip
nginx_gzip: true
nginx_gzip_vary: "on"
nginx_gzip_min_length: 1024
nginx_gzip_types:
- "text/plain"
- "text/css"
- "text/xml"
- "text/javascript"
- "application/javascript"
- "application/xml+rss"
- "application/json"
# Настройки для разных ОС
nginx_packages:
- nginx
# Дополнительные пакеты для Ubuntu/Debian
nginx_ubuntu_packages:
- nginx
- nginx-common
# Дополнительные пакеты для RHEL/CentOS
nginx_rhel_packages:
- nginx
- nginx-mod-http-geoip
- nginx-mod-http-image-filter
- nginx-mod-http-xslt-filter
- nginx-mod-mail
- nginx-mod-stream

View File

@@ -0,0 +1,44 @@
---
# Обработчики для роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Restart nginx
systemd:
name: nginx
state: restarted
listen: restart nginx
tags:
- nginx
- service
- restart
- name: Reload nginx
systemd:
name: nginx
state: reloaded
listen: reload nginx
tags:
- nginx
- service
- reload
- name: Start nginx
systemd:
name: nginx
state: started
listen: start nginx
tags:
- nginx
- service
- start
- name: Stop nginx
systemd:
name: nginx
state: stopped
listen: stop nginx
tags:
- nginx
- service
- stop

26
roles/nginx/meta/main.yml Normal file
View File

@@ -0,0 +1,26 @@
---
# Метаданные роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
galaxy_info:
author: Сергей Антропов
description: Простая роль для установки и настройки nginx
company: DevOps.org.ru
license: MIT
min_ansible_version: "2.9"
platforms:
- name: Ubuntu
versions:
- jammy
- focal
- name: EL
versions:
- all
galaxy_tags:
- web
- nginx
- http
- server
dependencies: []

196
roles/nginx/tasks/main.yml Normal file
View File

@@ -0,0 +1,196 @@
---
# Основные задачи для роли nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Установка nginx на Ubuntu/Debian
apt:
name: "{{ nginx_ubuntu_packages }}"
state: present
update_cache: true
when: ansible_os_family == "Debian"
tags:
- nginx
- install
- debian
- name: Установка nginx на RHEL/CentOS
yum:
name: "{{ nginx_rhel_packages }}"
state: present
when: ansible_os_family == "RedHat"
tags:
- nginx
- install
- rhel
- name: Включение и запуск nginx на Ubuntu/Debian
systemd:
name: nginx
enabled: true
state: started
when: ansible_os_family == "Debian"
tags:
- nginx
- service
- debian
- name: Включение и запуск nginx на RHEL/CentOS
systemd:
name: nginx
enabled: true
state: started
when: ansible_os_family == "RedHat"
tags:
- nginx
- service
- rhel
- name: Создание директории для веб-контента
file:
path: "{{ nginx_root_dir }}"
state: directory
owner: "{{ nginx_user }}"
group: "{{ nginx_user }}"
mode: '0755'
tags:
- nginx
- config
- directories
- name: Создание тестовой страницы
copy:
content: |
<!DOCTYPE html>
<html>
<head>
<title>Nginx Test Page</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.container { max-width: 600px; margin: 0 auto; }
h1 { color: #333; }
.info { background: #f4f4f4; padding: 20px; border-radius: 5px; }
</style>
</head>
<body>
<div class="container">
<h1>Nginx работает!</h1>
<div class="info">
<p><strong>Сервер:</strong> {{ ansible_hostname }}</p>
<p><strong>ОС:</strong> {{ ansible_distribution }} \
{{ ansible_distribution_version }}</p>
<p><strong>Время:</strong> {{ ansible_date_time.iso8601 }}</p>
<p><strong>Роль:</strong> nginx (Сергей Антропов)</p>
</div>
</div>
</body>
</html>
dest: "{{ nginx_root_dir }}/{{ nginx_index_file }}"
owner: "{{ nginx_user }}"
group: "{{ nginx_user }}"
mode: '0644'
notify: restart nginx
tags:
- nginx
- config
- content
- name: Создание резервной копии конфигурации nginx
copy:
src: "{{ item }}"
dest: "{{ item }}.backup"
remote_src: true
mode: '0644'
owner: root
group: root
loop:
- /etc/nginx/nginx.conf
- /etc/nginx/sites-available/default
ignore_errors: true
when: ansible_os_family == "Debian"
tags:
- nginx
- config
- backup
- name: Создание резервной копии конфигурации nginx (RHEL)
copy:
src: "{{ item }}"
dest: "{{ item }}.backup"
remote_src: true
mode: '0644'
owner: root
group: root
loop:
- /etc/nginx/nginx.conf
- /etc/nginx/conf.d/default.conf
ignore_errors: true
when: ansible_os_family == "RedHat"
tags:
- nginx
- config
- backup
- name: Настройка основной конфигурации nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: true
notify: restart nginx
tags:
- nginx
- config
- main
- name: Настройка виртуального хоста (Ubuntu/Debian)
template:
src: default.conf.j2
dest: /etc/nginx/sites-available/default
owner: root
group: root
mode: '0644'
backup: true
when: ansible_os_family == "Debian"
notify: restart nginx
tags:
- nginx
- config
- vhost
- debian
- name: Настройка виртуального хоста (RHEL/CentOS)
template:
src: default.conf.j2
dest: /etc/nginx/conf.d/default.conf
owner: root
group: root
mode: '0644'
backup: true
when: ansible_os_family == "RedHat"
notify: restart nginx
tags:
- nginx
- config
- vhost
- rhel
- name: Проверка конфигурации nginx
command: nginx -t
register: nginx_config_test
changed_when: false
tags:
- nginx
- config
- test
- name: Показать результат проверки конфигурации
debug:
msg: "{{ nginx_config_test.stdout_lines }}"
when: nginx_config_test.stdout_lines is defined
tags:
- nginx
- config
- test

View File

@@ -0,0 +1,67 @@
# Конфигурация виртуального хоста nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Сгенерировано: {{ ansible_date_time.iso8601 }}
server {
listen {{ nginx_listen_port }};
server_name {{ nginx_server_name }};
# Настройки безопасности
{% if nginx_hide_version %}
server_tokens off;
{% endif %}
# Корневая директория
root {{ nginx_root_dir }};
index {{ nginx_index_file }};
# Настройки логов для этого виртуального хоста
access_log {{ nginx_access_log }};
error_log {{ nginx_error_log }};
# Основная локация
location / {
try_files $uri $uri/ =404;
}
# Настройки для статических файлов
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Настройки безопасности
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Настройки для favicon
location = /favicon.ico {
log_not_found off;
access_log off;
}
# Настройки для robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# Настройки для health check
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Настройки для статуса nginx
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}

View File

@@ -0,0 +1,58 @@
# Основная конфигурация nginx
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Сгенерировано: {{ ansible_date_time.iso8601 }}
user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
error_log {{ nginx_error_log }};
pid /run/nginx.pid;
events {
worker_connections {{ nginx_worker_connections }};
}
http {
# Основные настройки
sendfile {{ nginx_sendfile }};
tcp_nopush {{ nginx_tcp_nopush }};
tcp_nodelay {{ nginx_tcp_nodelay }};
keepalive_timeout {{ nginx_keepalive_timeout }};
types_hash_max_size 2048;
server_tokens {{ nginx_server_tokens }};
# Настройки MIME типов
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Настройки логирования
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log {{ nginx_access_log }} main;
# Настройки gzip
{% if nginx_gzip %}
gzip {{ nginx_gzip_vary }};
gzip_min_length {{ nginx_gzip_min_length }};
gzip_types
{% for gzip_type in nginx_gzip_types %}
{{ gzip_type }}{% if not loop.last %} {% endif %}
{% endfor %};
{% endif %}
# Настройки безопасности
{% if nginx_hide_version %}
server_tokens off;
{% endif %}
# Включение конфигураций виртуальных хостов
{% if ansible_os_family == "Debian" %}
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
{% elif ansible_os_family == "RedHat" %}
include /etc/nginx/conf.d/*.conf;
{% endif %}
}

View File

View File

@@ -1,12 +0,0 @@
#!/usr/bin/env bash
# Очистка лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
set -euo pipefail
echo "[cleanup] removing lab containers/volumes/networks"
docker ps -aq --filter "label=ansible.lab=true" | xargs -r docker rm -f
docker volume ls -q --filter "name=_docker$" | xargs -r docker volume rm
docker network rm labnet >/dev/null 2>&1 || true
echo "done."

View File

@@ -1,143 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Генератор HTML отчетов для универсальной лаборатории
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
import sys
import json
import html
import datetime
def main():
if len(sys.argv) < 3:
print("Usage: report_html.py <input.json> <output.html>")
sys.exit(1)
inp, outp = sys.argv[1], sys.argv[2]
try:
with open(inp, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception as e:
data = {"error": f"failed to read json: {e}"}
ts = data.get("timestamp", datetime.datetime.utcnow().isoformat())
idemp_raw = data.get("idempotence_raw", "")
haproxy_sel = data.get("haproxy_select1", "")
helm_ingress_toolbox = data.get("helm_ingress_toolbox_raw", "")
istio_kiali = data.get("istio_kiali_raw", "")
istio_bookinfo = data.get("istio_bookinfo_raw", "")
k8s_overview = data.get("k8s_overview_raw", "")
def badge(label, ok):
color = "#10b981" if ok else "#ef4444"
return f'<span class="badge" style="background:{color}">{html.escape(label)}</span>'
# Анализ статусов
idempotent_ok = ("changed=0" in idemp_raw)
haproxy_ok = (haproxy_sel.strip() == "1") if haproxy_sel else None
ingress_ok = ("ingress" in helm_ingress_toolbox.lower()) or ("curl http://localhost" in helm_ingress_toolbox.lower())
toolbox_ok = ("deploy/toolbox" in helm_ingress_toolbox.lower()) or ("rollout status" in helm_ingress_toolbox.lower())
istio_ok = ("istio-system" in istio_kiali.lower()) and ("istiod" in istio_kiali.lower())
kiali_ok = ("kiali" in istio_kiali.lower())
bookinfo_ok = ("bookinfo" in istio_bookinfo.lower()) or ("productpage" in istio_bookinfo.lower())
k8s_ok = ("nodes" in k8s_overview.lower()) and ("pods" in k8s_overview.lower())
def maybe_badge(label, status):
if status is None:
return f'<span class="badge" style="background:#6b7280">{html.escape(label)}: n/a</span>'
return badge(f"{label}", bool(status))
html_doc = f"""<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Lab Report</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
:root {{ --bg:#0f172a; --card:#111827; --muted:#94a3b8; --fg:#e5e7eb; --accent:#38bdf8; }}
* {{ box-sizing:border-box; }}
body {{ margin:0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Arial;
background:linear-gradient(180deg,#0b1220,#0f172a); color:var(--fg); }}
.container {{ max-width:1100px; margin:40px auto; padding:0 16px; }}
.hdr {{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }}
.hdr h1 {{ margin:0; font-size:28px; }}
.time {{ color:var(--muted); font-size:14px; }}
.grid {{ display:grid; grid-template-columns:1fr; gap:16px; margin-top:20px; }}
.card {{ background:rgba(17,24,39,.7); border:1px solid rgba(148,163,184,.15);
border-radius:14px; padding:16px; box-shadow:0 10px 30px rgba(0,0,0,.25); backdrop-filter: blur(6px); }}
.card h2 {{ margin:0 0 10px 0; font-size:18px; color:#c7d2fe; }}
pre {{ margin:0; padding:12px; background:#0b1220; border-radius:10px; overflow:auto; font-size:12px; line-height:1.4; }}
.badge {{ display:inline-block; padding:4px 10px; border-radius:999px; font-size:12px; color:white; }}
.kv {{ display:flex; flex-wrap:wrap; gap:8px; margin:8px 0 0 0; }}
footer {{ margin:24px 0 40px; color:var(--muted); font-size:12px; text-align:center; }}
a {{ color: var(--accent); text-decoration:none; }} a:hover {{ text-decoration:underline; }}
</style>
</head>
<body>
<div class="container">
<div class="hdr">
<h1>Ansible Lab Report</h1>
<div class="time">generated: {html.escape(ts)}</div>
</div>
<div class="grid">
<div class="card">
<h2>Summary</h2>
<div class="kv">
{badge("Idempotent", idempotent_ok)}
{maybe_badge("HAProxy SELECT=1", haproxy_ok)}
{maybe_badge("Ingress ready", ingress_ok)}
{maybe_badge("Toolbox ready", toolbox_ok)}
{maybe_badge("Istio ready", istio_ok)}
{maybe_badge("Kiali ready", kiali_ok)}
{maybe_badge("Bookinfo ready", bookinfo_ok)}
{maybe_badge("K8s ready", k8s_ok)}
</div>
</div>
<div class="card">
<h2>Idempotence (raw)</h2>
<pre>{html.escape(idemp_raw) if idemp_raw else "n/a"}</pre>
</div>
<div class="card">
<h2>Helm + Ingress + Toolbox (raw)</h2>
<pre>{html.escape(helm_ingress_toolbox) if helm_ingress_toolbox else "n/a"}</pre>
</div>
<div class="card">
<h2>Istio / Kiali (raw)</h2>
<pre>{html.escape(istio_kiali) if istio_kiali else "n/a"}</pre>
</div>
<div class="card">
<h2>Istio Bookinfo (raw)</h2>
<pre>{html.escape(istio_bookinfo) if istio_bookinfo else "n/a"}</pre>
</div>
<div class="card">
<h2>K8s Overview (raw)</h2>
<pre>{html.escape(k8s_overview) if k8s_overview else "n/a"}</pre>
</div>
<div class="card">
<h2>HAProxy SELECT 1</h2>
<pre>{html.escape(haproxy_sel) if haproxy_sel else "n/a"}</pre>
</div>
</div>
<footer>HTML from /ansible/reports/lab-health.json · kubeconfigs in reports/kubeconfigs/</footer>
</div>
</body>
</html>"""
with open(outp, "w", encoding="utf-8") as f:
f.write(html_doc)
print(outp)
if __name__ == "__main__":
main()

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
# Восстановление лаборатории из снапшотов
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
set -euo pipefail
IN_DIR="/ansible/snapshots"
if [ ! -d "$IN_DIR" ]; then
echo "No snapshots dir"
exit 1
fi
for f in "$IN_DIR"/*.image; do
if [ ! -f "$f" ]; then
continue
fi
name=$(basename "$f" .image)
img=$(cat "$f")
echo "[restore] $name from $img"
docker rm -f "$name" >/dev/null 2>&1 || true
docker run -d --name "$name" "$img" >/dev/null
done
echo "Restored from $IN_DIR/"

View File

@@ -1,72 +0,0 @@
#!/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 "✅ Все проверки безопасности пройдены!"

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
# Снапшот лаборатории
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
set -euo pipefail
OUT_DIR="/ansible/snapshots"
mkdir -p "$OUT_DIR"
# Найти все контейнеры лаборатории
ids=$(docker ps -q --filter "label=ansible.lab=true")
if [ -z "$ids" ]; then
echo "No lab containers to snapshot"
exit 0
fi
for id in $ids; do
name=$(docker inspect --format '{{.Name}}' "$id" | sed 's#^/##')
img="lab-snap-$name:latest"
echo "[snapshot] $name -> $img"
docker commit "$id" "$img" >/dev/null
echo "$img" > "$OUT_DIR/$name.image"
done
echo "Snapshots saved to $OUT_DIR/"

52
scripts/test-playbook.yml Normal file
View File

@@ -0,0 +1,52 @@
---
# Простой тестовый playbook для проверки 3 контейнеров
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
- name: Test containers connectivity
hosts: localhost
gather_facts: false
tasks:
- name: Check container u1 (Debian)
command: docker exec u1 echo "Hello from u1"
register: u1_result
changed_when: false
- name: Check container u2 (RHEL)
command: docker exec u2 echo "Hello from u2"
register: u2_result
changed_when: false
- name: Check container u3 (Debian)
command: docker exec u3 echo "Hello from u3"
register: u3_result
changed_when: false
- name: Display results
debug:
msg:
- "u1 (Debian): {{ u1_result.stdout }}"
- "u2 (RHEL): {{ u2_result.stdout }}"
- "u3 (Debian): {{ u3_result.stdout }}"
- name: Install nginx on u1
command: docker exec u1 bash -c "apt-get update && apt-get install -y nginx"
register: nginx_u1
changed_when: false
- name: Install nginx on u2
command: docker exec u2 bash -c "yum install -y nginx"
register: nginx_u2
changed_when: false
- name: Install nginx on u3
command: docker exec u3 bash -c "apt-get update && apt-get install -y nginx"
register: nginx_u3
changed_when: false
- name: Display nginx installation results
debug:
msg:
- "Nginx installation on u1: {{ 'SUCCESS' if nginx_u1.rc == 0 else 'FAILED' }}"
- "Nginx installation on u2: {{ 'SUCCESS' if nginx_u2.rc == 0 else 'FAILED' }}"
- "Nginx installation on u3: {{ 'SUCCESS' if nginx_u3.rc == 0 else 'FAILED' }}"

83
scripts/test-standart.sh Executable file
View File

@@ -0,0 +1,83 @@
#!/bin/bash
# Скрипт для тестирования с preset standart
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
set -e
echo "🚀 Запуск тестирования с preset standart..."
# Очищаем старые контейнеры
echo "🧹 Очистка старых контейнеров..."
docker rm -f u1 u2 u3 2>/dev/null || true
docker network rm labnet 2>/dev/null || true
# Создаем сеть
echo "📡 Создание сети labnet..."
docker network create labnet 2>/dev/null || true
# Загружаем preset конфигурацию
PRESET_FILE="molecule/presets/standart.yml"
if [ ! -f "$PRESET_FILE" ]; then
echo "❌ Ошибка: Пресет файл $PRESET_FILE не найден!"
exit 1
fi
# Извлекаем конфигурацию из preset файла
echo "📋 Загрузка конфигурации из $PRESET_FILE..."
# Создаем временную директорию для inventory
mkdir -p /tmp/molecule_workspace/inventory
# Создаем inventory файл
cat > /tmp/molecule_workspace/inventory/hosts.ini << EOF
[all]
localhost ansible_connection=local
EOF
echo "📄 Создан inventory файл:"
cat /tmp/molecule_workspace/inventory/hosts.ini
# Запускаем контейнеры
echo "🐳 Создание контейнеров..."
# u1 - Debian
echo "Создание u1 (Debian)..."
docker run -d --name u1 \
--network labnet \
-p 2201:22 \
ubuntu:20.04 \
bash -c "apt-get update && apt-get install -y openssh-server && service ssh start && sleep infinity"
# u2 - Debian (временно используем Ubuntu вместо CentOS)
echo "Создание u2 (Debian)..."
docker run -d --name u2 \
--network labnet \
-p 2202:22 \
ubuntu:20.04 \
bash -c "apt-get update && apt-get install -y openssh-server && service ssh start && sleep infinity"
# u3 - Debian
echo "Создание u3 (Debian)..."
docker run -d --name u3 \
--network labnet \
-p 2203:22 \
ubuntu:20.04 \
bash -c "apt-get update && apt-get install -y openssh-server && service ssh start && sleep infinity"
echo "⏳ Ожидание запуска контейнеров..."
sleep 10
# Проверяем статус контейнеров
echo "📊 Статус контейнеров:"
docker ps --filter "name=u[123]" --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
# Запускаем тесты
echo "🧪 Запуск тестов..."
ansible-playbook -i /tmp/molecule_workspace/inventory/hosts.ini scripts/test-playbook.yml
echo "🧹 Очистка контейнеров..."
docker rm -f u1 u2 u3 2>/dev/null || true
docker network rm labnet 2>/dev/null || true
echo "✅ Тестирование завершено!"

View File

View File

@@ -1,45 +1,33 @@
$ANSIBLE_VAULT;1.1;AES256
36616532373361616262643163656363656533663465653636646264376666313838386336643263
6433626166306136653962646263643632353138396332380a393161333663333331303266373034
36366665626365323036353931353965343239613164393931636234396134343963333065373134
3661666162386339640a373639383233376263613164326234323064613030636336366239393339
37343565613837626236386339303565386531626238646139303266656264623031633663373236
66663362393663633363646664303737343134396465323663376332363864313834643533663539
65643636613437326535396335373333303938353837663632363238393061633431666334313733
37373730383732623632616261626335656534316230356638643266663965323139373239623238
38303831633436313439386639323535363036313539396361353462616338383633636432373338
64363035343337336233313534306166326438303031653034663639353663396435393531666238
66326331663933353463373338393765653434313565306162613135333864633131633035623966
62643239643138323532346165393961363637363864623738323633633862313966346238333464
66363761306637666230373533356432333238633432383966316134353630643432643133303537
31663863303163363433346166363232623737383230613637313435393737353361396565636233
62313835336438663438656536643339353738326539626530383834633061633939633436373262
35656234616538363936353162313436653764303337623032316561373866376266663165653765
31646533666536376366616638336232313830323330316564343864396130623633333530376665
36313365316664656331613863663162323161643732323963303561373765393165623834373766
61383065376534396630333930633666633034303232366637316237373863643065306439643230
37626533373666626263313538613864326539646631306166306637373134366331396138393931
63326139306538313461383434343362313232353265373337326336666639393665396166626262
66353832396665333362643837666438613035323164326361396130643766396434366231616632
31383834616530376634643632376634366637336665393963326239643237363564636134336333
35643536653532343466643932336163643138636662316530663464353639363436663634326432
34376332323936336134396338623835633562343830666431616163643239653132343236303537
65663736333562396430643038313961323365616533323166633663326663633464323934353739
38656138323533346239356432663563336432396463626331623230303864326434616161326233
33303363376164333839333435386339386139633739333435346530633663313261633631383835
63623436356462316362663965366631383663646333356536643632363566636163343264343063
61316664656635363564303135343466393533383164643432656334313338663033306261396136
62333962393039383831626537346566663566356266633364666362623462313166333661656362
34323062393334343063343038646432336239383334303332313166383461663336656465393137
33333364633033633765373432393038396231616139343665306335663231646264663537343637
37393537613338343736613062343963313963656164383734303439376265323135333239363361
30616539363364353333653039613036623966653266333130306634623236636337666437363534
61336130626261376334303636343231333666386132666365623365613735633433343133663031
36366338386630343766363464343536613761653464633138353238313462613265383135383766
35356265316535366231333664346337383266383064363731363437613732306231323339636631
64306535663264316561356531323864303866623331343635663836306333396634306333383764
62343439323433613963343033303535653762663633633130356235393437626164343432626332
33636136636562643166643461343135643265626434656136336236366131326462303036613139
61306263386532343365313539306339636238613062373162333036306166363933616664373962
32383036613961323633366431356434633839333864623565396265366365326162396434653233
35346237363764653866
---
# Основные секреты для тестирования
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# Пароли для баз данных
database_passwords:
root_password: "database-root-password"
app_user_password: "database-app-password"
monitoring_user_password: "monitoring-user-password"
# SSL сертификаты
ssl_certificates:
server_cert: |
-----BEGIN CERTIFICATE-----
# Server certificate content
-----END CERTIFICATE-----
server_key: |
-----BEGIN PRIVATE KEY-----
# Server private key content
-----END PRIVATE KEY-----
# API ключи
api_keys:
github_token: "ghp_example_token"
dockerhub_token: "dckr_example_token"
monitoring_api_key: "monitoring_api_key_example"
# Строки подключения
database_connections:
primary: "mysql://user:password@db1:3306/app"
replica: "mysql://user:password@db2:3306/app"
cache: "redis://cache1:6379/0"