Some checks failed
		
		
	
	Ansible Testing / lint (push) Has been cancelled
				
			Ansible Testing / test (default) (push) Has been cancelled
				
			Ansible Testing / test (minimal) (push) Has been cancelled
				
			Ansible Testing / test (performance) (push) Has been cancelled
				
			Ansible Testing / deploy-check (push) Has been cancelled
				
			
		
			
				
	
	
		
			860 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			860 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Подробное руководство по файлам Molecule
 | ||
| 
 | ||
| **Автор:** Сергей Антропов  
 | ||
| **Сайт:** https://devops.org.ru
 | ||
| 
 | ||
| ## 📋 Обзор
 | ||
| 
 | ||
| Molecule - это инструмент для тестирования Ansible ролей в изолированных окружениях. В проекте DevOpsLab используется универсальная конфигурация Molecule с поддержкой множества операционных систем и различных preset'ов для тестирования.
 | ||
| 
 | ||
| ### 🔧 Fallback значения
 | ||
| 
 | ||
| **Важная особенность:** Все файлы Molecule содержат fallback значения, что обеспечивает работоспособность системы даже без preset файлов. Это означает, что:
 | ||
| 
 | ||
| - **Система всегда работает** - даже если preset файл не найден
 | ||
| - **Быстрый старт** - можно запустить тестирование без настройки
 | ||
| - **Надежность** - меньше точек отказа в системе
 | ||
| - **Отладка** - легче диагностировать проблемы с preset'ами
 | ||
| 
 | ||
| ## 🏗️ Структура файлов Molecule
 | ||
| 
 | ||
| ```
 | ||
| molecule/
 | ||
| ├── default/                    # Основная конфигурация Molecule
 | ||
| │   ├── molecule.yml           # Главный конфигурационный файл
 | ||
| │   ├── create.yml             # Создание тестовых контейнеров
 | ||
| │   ├── converge.yml           # Выполнение ролей в контейнерах
 | ||
| │   ├── verify.yml             # Проверка результатов тестирования
 | ||
| │   ├── destroy.yml            # Удаление тестовых контейнеров
 | ||
| │   └── site.yml               # Основной playbook для тестирования
 | ||
| └── presets/                   # Preset конфигурации для разных сценариев
 | ||
|     ├── minimal.yml            # Минимальный preset (1 хост)
 | ||
|     ├── performance.yml        # Performance preset (12 хостов)
 | ||
|     ├── security.yml           # Security preset (10 хостов)
 | ||
|     ├── etcd-patroni.yml       # etcd-patroni preset
 | ||
|     └── ...                    # Другие preset'ы
 | ||
| ```
 | ||
| 
 | ||
| ## 📄 Детальное описание файлов
 | ||
| 
 | ||
| ### 1. `molecule/default/molecule.yml` - Главный конфигурационный файл
 | ||
| 
 | ||
| **Назначение:** Основная конфигурация Molecule с настройками драйвера, платформ, provisioner'а и verifier'а.
 | ||
| 
 | ||
| #### Основные секции:
 | ||
| 
 | ||
| **Driver (Драйвер):**
 | ||
| ```yaml
 | ||
| driver:
 | ||
|   name: docker
 | ||
| ```
 | ||
| - **Назначение:** Определяет использование Docker в качестве драйвера
 | ||
| - **Функция:** Создание и управление тестовыми контейнерами
 | ||
| 
 | ||
| **Platforms (Платформы):**
 | ||
| ```yaml
 | ||
| platforms:
 | ||
|   - name: placeholder
 | ||
|     image: ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy
 | ||
|     pre_build_image: true
 | ||
|   - name: ansible-controller
 | ||
|     image: inecs/ansible-lab:ansible-controller-latest
 | ||
|     pre_build_image: true
 | ||
|   # ... другие образы
 | ||
| ```
 | ||
| - **Назначение:** Определяет доступные Docker образы для тестирования
 | ||
| - **Поддерживаемые ОС:** Ubuntu, Debian, RHEL, CentOS, AlmaLinux, Rocky Linux, Alt Linux, Astra Linux, RedOS
 | ||
| - **Собственные образы:** DevOpsLab создает собственные образы для тестирования
 | ||
| 
 | ||
| **Provisioner (Провижнер):**
 | ||
| ```yaml
 | ||
| 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
 | ||
| ```
 | ||
| - **Назначение:** Настройка Ansible как provisioner'а
 | ||
| - **Функции:** 
 | ||
|   - Настройка вывода в YAML формате
 | ||
|   - Связывание инвентори файла
 | ||
|   - Определение playbook'ов для разных этапов
 | ||
| 
 | ||
| **Dependency (Зависимости):**
 | ||
| ```yaml
 | ||
| dependency:
 | ||
|   name: galaxy
 | ||
| ```
 | ||
| - **Назначение:** Установка зависимостей через Ansible Galaxy
 | ||
| - **Функция:** Автоматическая установка коллекций из `requirements.yml`
 | ||
| 
 | ||
| **Verifier (Верификатор):**
 | ||
| ```yaml
 | ||
| verifier:
 | ||
|   name: ansible
 | ||
| ```
 | ||
| - **Назначение:** Использование Ansible для проверки результатов
 | ||
| - **Функция:** Выполнение `verify.yml` для проверки состояния системы
 | ||
| 
 | ||
| **Lint (Линтер):**
 | ||
| ```yaml
 | ||
| lint: |-
 | ||
|   set -e
 | ||
|   ansible-lint /workspace/roles/
 | ||
| ```
 | ||
| - **Назначение:** Проверка синтаксиса ролей
 | ||
| - **Функция:** Запуск `ansible-lint` для всех ролей в директории `roles/`
 | ||
| 
 | ||
| ### 2. `molecule/default/create.yml` - Создание тестовых контейнеров
 | ||
| 
 | ||
| **Назначение:** Создание и настройка тестовых контейнеров согласно выбранному preset'у с fallback значениями.
 | ||
| 
 | ||
| #### Переменные и конфигурация:
 | ||
| 
 | ||
| **Fallback значения (по умолчанию):**
 | ||
| ```yaml
 | ||
| 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:
 | ||
|     alt: "inecs/ansible-lab:alt9-latest"
 | ||
|     astra: "inecs/ansible-lab:astra-linux-latest"
 | ||
|     rhel: "inecs/ansible-lab:rhel-latest"
 | ||
|     centos: "inecs/ansible-lab:centos-latest"
 | ||
|     alma: "inecs/ansible-lab:alma-latest"
 | ||
|     rocky: "inecs/ansible-lab:rocky-latest"
 | ||
|     redos: "inecs/ansible-lab:redos-latest"
 | ||
|     ubuntu: "inecs/ansible-lab:ubuntu-latest"
 | ||
|     debian: "inecs/ansible-lab:debian-latest"
 | ||
|   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]
 | ||
| ```
 | ||
| - **Назначение:** Определение fallback значений для случаев когда preset файл не найден
 | ||
| - **Функция:** Обеспечение работоспособности даже без preset файлов
 | ||
| - **Образы:** Собственные образы DevOpsLab для всех поддерживаемых ОС
 | ||
| - **Systemd настройки:** Стандартные настройки для systemd контейнеров
 | ||
| 
 | ||
| #### Основные задачи:
 | ||
| 
 | ||
| **Load preset configuration:**
 | ||
| ```yaml
 | ||
| - name: Load preset configuration
 | ||
|   include_vars: "{{ preset_file }}"
 | ||
|   when: preset_file is file
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Загрузка конфигурации preset'а (перезаписывает fallback значения)
 | ||
| - **Функция:** Динамическое определение тестового окружения
 | ||
| - **Переменные:** `MOLECULE_PRESET` определяет какой preset использовать
 | ||
| - **Fallback:** Если preset файл не найден, используются значения по умолчанию
 | ||
| 
 | ||
| #### Преимущества fallback значений:
 | ||
| 
 | ||
| 1. **Надежность:** Система работает даже без preset файлов
 | ||
| 2. **Быстрый старт:** Можно запустить тестирование без настройки preset'ов
 | ||
| 3. **Стандартизация:** Единые настройки для всех ОС
 | ||
| 4. **Отладка:** Легче диагностировать проблемы с preset файлами
 | ||
| 5. **Разработка:** Удобно для разработки новых preset'ов
 | ||
| 
 | ||
| **Ensure network exists:**
 | ||
| ```yaml
 | ||
| - name: Ensure network exists
 | ||
|   community.docker.docker_network:
 | ||
|     name: "{{ docker_network }}"
 | ||
|     state: present
 | ||
| ```
 | ||
| - **Назначение:** Создание Docker сети для тестирования
 | ||
| - **Функция:** Обеспечение сетевого взаимодействия между контейнерами
 | ||
| - **По умолчанию:** Сеть `labnet`
 | ||
| 
 | ||
| **Pull systemd images:**
 | ||
| ```yaml
 | ||
| - name: Pull systemd images
 | ||
|   community.docker.docker_image:
 | ||
|     name: "{{ images[item.family] }}"
 | ||
|     source: pull
 | ||
|   loop: "{{ hosts | selectattr('type','undefined') | list }}"
 | ||
| ```
 | ||
| - **Назначение:** Загрузка Docker образов для systemd контейнеров
 | ||
| - **Функция:** Подготовка образов для создания контейнеров
 | ||
| - **Поддержка:** Различные семейства ОС (debian, rhel, alt, astra)
 | ||
| 
 | ||
| **Start systemd nodes:**
 | ||
| ```yaml
 | ||
| - 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([]) }}"
 | ||
|     env: "{{ item.env | default({}) }}"
 | ||
|     state: started
 | ||
|     restart_policy: unless-stopped
 | ||
| ```
 | ||
| - **Назначение:** Создание и запуск systemd контейнеров
 | ||
| - **Функции:**
 | ||
|   - Создание контейнеров с systemd поддержкой
 | ||
|   - Настройка привилегированного режима
 | ||
|   - Монтирование cgroup для systemd
 | ||
|   - Настройка tmpfs для /run
 | ||
|   - Публикация портов
 | ||
|   - Настройка переменных окружения
 | ||
| 
 | ||
| **Start DinD nodes (Docker-in-Docker):**
 | ||
| ```yaml
 | ||
| - name: Start DinD nodes (docker:27-dind)
 | ||
|   community.docker.docker_container:
 | ||
|     name: "{{ item.name }}"
 | ||
|     image: "docker:27-dind"
 | ||
|     networks:
 | ||
|       - name: "{{ docker_network }}"
 | ||
|     privileged: true
 | ||
|     env:
 | ||
|       DOCKER_TLS_CERTDIR: ""
 | ||
|     published_ports: "{{ item.publish | default([]) }}"
 | ||
|     volumes: "{{ (item.volumes | default([])) + [item.name + '-docker:/var/lib/docker'] }}"
 | ||
|     state: started
 | ||
|     restart_policy: unless-stopped
 | ||
| ```
 | ||
| - **Назначение:** Создание Docker-in-Docker контейнеров
 | ||
| - **Функции:**
 | ||
|   - Тестирование Docker Compose
 | ||
|   - Тестирование Dockerfile'ов
 | ||
|   - Изолированная Docker среда
 | ||
|   - Отдельные volumes для Docker данных
 | ||
| 
 | ||
| **Start DOoD nodes (Docker-out-of-Docker):**
 | ||
| ```yaml
 | ||
| - 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([]) }}"
 | ||
|     env: "{{ item.env | default({}) }}"
 | ||
|     state: started
 | ||
|     restart_policy: unless-stopped
 | ||
| ```
 | ||
| - **Назначение:** Создание Docker-out-of-Docker контейнеров
 | ||
| - **Функции:**
 | ||
|   - Доступ к Docker daemon хоста
 | ||
|   - Тестирование Docker операций
 | ||
|   - Комбинация systemd + Docker
 | ||
| 
 | ||
| **Build groups map:**
 | ||
| ```yaml
 | ||
| - 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) }}"
 | ||
| ```
 | ||
| - **Назначение:** Создание карты групп для инвентори
 | ||
| - **Функция:** Группировка хостов по назначению (servers, database, cache, etc.)
 | ||
| 
 | ||
| **Render inventory ini:**
 | ||
| ```yaml
 | ||
| - 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 %}
 | ||
| ```
 | ||
| - **Назначение:** Генерация инвентори файла
 | ||
| - **Функция:** Создание динамического инвентори для Ansible
 | ||
| - **Формат:** INI формат с группами и переменными
 | ||
| 
 | ||
| **Write inventory file:**
 | ||
| ```yaml
 | ||
| - name: Write inventory file
 | ||
|   copy:
 | ||
|     dest: "{{ generated_inventory }}"
 | ||
|     content: "{{ inv_content }}"
 | ||
|     mode: "0644"
 | ||
| ```
 | ||
| - **Назначение:** Сохранение инвентори файла
 | ||
| - **Функция:** Запись сгенерированного инвентори в файл
 | ||
| 
 | ||
| **Display inventory summary:**
 | ||
| ```yaml
 | ||
| - 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 }}
 | ||
| ```
 | ||
| - **Назначение:** Отображение сводки по созданным контейнерам
 | ||
| - **Функция:** Информация о количестве и типах контейнеров
 | ||
| 
 | ||
| ### 3. `molecule/default/converge.yml` - Выполнение ролей
 | ||
| 
 | ||
| **Назначение:** Выполнение Ansible ролей в созданных контейнерах.
 | ||
| 
 | ||
| #### Основные задачи:
 | ||
| 
 | ||
| **Load preset configuration:**
 | ||
| ```yaml
 | ||
| - name: Load preset configuration
 | ||
|   include_vars: "{{ preset_file }}"
 | ||
|   when: preset_file is file
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Загрузка конфигурации preset'а
 | ||
| - **Функция:** Применение настроек preset'а для выполнения
 | ||
| 
 | ||
| **Preflight vault — normalize state:**
 | ||
| ```yaml
 | ||
| - name: Preflight vault — normalize state (encrypt if plaintext, then decrypt)
 | ||
|   community.docker.docker_container_exec:
 | ||
|     container: ansible-controller
 | ||
|     command: >
 | ||
|       bash -lc '
 | ||
|       set -euo pipefail; shopt -s nullglob globstar;
 | ||
|       for p in {{ vault_targets | map('quote') | join(' ') }}; do
 | ||
|         for f in $p; do
 | ||
|           [ -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 /workspace/vault/.vault "$f";
 | ||
|           fi
 | ||
|           echo "[vault] decrypt for run: $f";
 | ||
|           ansible-vault decrypt --vault-password-file /workspace/vault/.vault "$f";
 | ||
|         done
 | ||
|       done
 | ||
|       '
 | ||
| ```
 | ||
| - **Назначение:** Подготовка vault файлов для выполнения
 | ||
| - **Функции:**
 | ||
|   - Шифрование незашифрованных файлов
 | ||
|   - Расшифровка файлов для выполнения
 | ||
|   - Нормализация состояния vault файлов
 | ||
| 
 | ||
| **Run lab playbook:**
 | ||
| ```yaml
 | ||
| - name: Run lab playbook
 | ||
|   community.docker.docker_container_exec:
 | ||
|     container: ansible-controller
 | ||
|     command: >
 | ||
|       bash -lc "
 | ||
|         ANSIBLE_ROLES_PATH=/workspace/roles
 | ||
|         ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /workspace/molecule/default/site.yml
 | ||
|       "
 | ||
| ```
 | ||
| - **Назначение:** Выполнение основного playbook'а
 | ||
| - **Функции:**
 | ||
|   - Запуск `site.yml` в ansible-controller контейнере
 | ||
|   - Использование сгенерированного инвентори
 | ||
|   - Установка пути к ролям
 | ||
| 
 | ||
| **Post-run — re-encrypt secrets:**
 | ||
| ```yaml
 | ||
| - name: Post-run — re-encrypt secrets
 | ||
|   community.docker.docker_container_exec:
 | ||
|     container: ansible-controller
 | ||
|     command: >
 | ||
|       bash -lc '
 | ||
|       set -euo pipefail; shopt -s nullglob globstar;
 | ||
|       for p in {{ vault_targets | map('quote') | join(' ') }}; do
 | ||
|         for f in $p; do
 | ||
|           [ -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 /workspace/vault/.vault "$f" || true;
 | ||
|           fi
 | ||
|         done
 | ||
|       done
 | ||
|       '
 | ||
|     ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Повторное шифрование секретов после выполнения
 | ||
| - **Функция:** Обеспечение безопасности vault файлов
 | ||
| 
 | ||
| ### 4. `molecule/default/verify.yml` - Проверка результатов
 | ||
| 
 | ||
| **Назначение:** Проверка состояния системы после выполнения ролей.
 | ||
| 
 | ||
| #### Основные задачи:
 | ||
| 
 | ||
| **Load preset configuration:**
 | ||
| ```yaml
 | ||
| - name: Load preset configuration
 | ||
|   include_vars: "{{ preset_file }}"
 | ||
|   when: preset_file is file
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Загрузка конфигурации preset'а
 | ||
| - **Функция:** Применение настроек для проверки
 | ||
| 
 | ||
| **Check systemd nodes status:**
 | ||
| ```yaml
 | ||
| - name: Check systemd nodes status
 | ||
|   community.docker.docker_container_exec:
 | ||
|     container: "{{ item.name }}"
 | ||
|     command: systemctl is-system-running
 | ||
|   loop: "{{ hosts | selectattr('type','undefined') | list }}"
 | ||
|   register: systemd_status
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Проверка состояния systemd в контейнерах
 | ||
| - **Функция:** Убедиться что systemd работает корректно
 | ||
| 
 | ||
| **Check DinD nodes docker daemon:**
 | ||
| ```yaml
 | ||
| - 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 }}"
 | ||
|   register: dind_status
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Проверка Docker daemon в DinD контейнерах
 | ||
| - **Функция:** Убедиться что Docker работает в контейнерах
 | ||
| 
 | ||
| **Check DOoD nodes docker access:**
 | ||
| ```yaml
 | ||
| - 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 }}"
 | ||
|   register: dood_status
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Проверка доступа к Docker в DOoD контейнерах
 | ||
| - **Функция:** Убедиться что контейнеры могут обращаться к Docker daemon
 | ||
| 
 | ||
| **Test network connectivity between nodes:**
 | ||
| ```yaml
 | ||
| - 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') }}"
 | ||
|   when: item.0.name != item.1.name
 | ||
|   register: ping_results
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Проверка сетевого взаимодействия между контейнерами
 | ||
| - **Функция:** Убедиться что контейнеры могут общаться друг с другом
 | ||
| 
 | ||
| **Check published ports:**
 | ||
| ```yaml
 | ||
| - name: Check published ports
 | ||
|   community.docker.docker_container_exec:
 | ||
|     container: "{{ item.name }}"
 | ||
|     command: netstat -tlnp
 | ||
|   loop: "{{ hosts | selectattr('publish','defined') | list }}"
 | ||
|   register: port_status
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Проверка опубликованных портов
 | ||
| - **Функция:** Убедиться что порты доступны
 | ||
| 
 | ||
| **Display verification summary:**
 | ||
| ```yaml
 | ||
| - 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 }}
 | ||
| ```
 | ||
| - **Назначение:** Отображение итоговой сводки проверки
 | ||
| - **Функция:** Информация о состоянии всех компонентов
 | ||
| 
 | ||
| ### 5. `molecule/default/destroy.yml` - Удаление контейнеров
 | ||
| 
 | ||
| **Назначение:** Очистка тестовых контейнеров и ресурсов.
 | ||
| 
 | ||
| #### Основные задачи:
 | ||
| 
 | ||
| **Load preset configuration:**
 | ||
| ```yaml
 | ||
| - name: Load preset configuration
 | ||
|   include_vars: "{{ preset_file }}"
 | ||
|   when: preset_file is file
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Загрузка конфигурации preset'а
 | ||
| - **Функция:** Определение какие ресурсы нужно удалить
 | ||
| 
 | ||
| **Stop and remove containers:**
 | ||
| ```yaml
 | ||
| - name: Stop and remove containers
 | ||
|   community.docker.docker_container:
 | ||
|     name: "{{ item.name }}"
 | ||
|     state: absent
 | ||
|     force_kill: true
 | ||
|   loop: "{{ hosts }}"
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Остановка и удаление всех контейнеров
 | ||
| - **Функция:** Полная очистка тестовых контейнеров
 | ||
| 
 | ||
| **Remove DinD volumes:**
 | ||
| ```yaml
 | ||
| - name: Remove DinD volumes
 | ||
|   community.docker.docker_volume:
 | ||
|     name: "{{ item.name }}-docker"
 | ||
|     state: absent
 | ||
|   loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Удаление volumes для DinD контейнеров
 | ||
| - **Функция:** Очистка Docker данных
 | ||
| 
 | ||
| **Remove custom volumes:**
 | ||
| ```yaml
 | ||
| - name: Remove custom volumes
 | ||
|   community.docker.docker_volume:
 | ||
|     name: "{{ item.volumes | default([]) | select('match', '^[^:]+$') | list }}"
 | ||
|     state: absent
 | ||
|   loop: "{{ hosts }}"
 | ||
|   ignore_errors: true
 | ||
|   when: item.volumes is defined
 | ||
| ```
 | ||
| - **Назначение:** Удаление пользовательских volumes
 | ||
| - **Функция:** Очистка дополнительных volumes
 | ||
| 
 | ||
| **Remove network:**
 | ||
| ```yaml
 | ||
| - name: Remove network
 | ||
|   community.docker.docker_network:
 | ||
|     name: "{{ docker_network }}"
 | ||
|     state: absent
 | ||
|   ignore_errors: true
 | ||
| ```
 | ||
| - **Назначение:** Удаление Docker сети
 | ||
| - **Функция:** Очистка сетевых ресурсов
 | ||
| 
 | ||
| **Display cleanup summary:**
 | ||
| ```yaml
 | ||
| - 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 }}
 | ||
| ```
 | ||
| - **Назначение:** Отображение сводки по очистке
 | ||
| - **Функция:** Информация о удаленных ресурсах
 | ||
| 
 | ||
| ### 6. `molecule/default/site.yml` - Основной playbook
 | ||
| 
 | ||
| **Назначение:** Основной playbook для тестирования ролей.
 | ||
| 
 | ||
| #### Структура:
 | ||
| 
 | ||
| **Подготовка окружения:**
 | ||
| - Обновление пакетов для всех ОС
 | ||
| - Установка common tools
 | ||
| - Настройка пользователей
 | ||
| - Создание рабочих директорий
 | ||
| 
 | ||
| **Импорт deploy.yml:**
 | ||
| ```yaml
 | ||
| - import_playbook: ../../roles/deploy.yml
 | ||
| ```
 | ||
| - **Назначение:** Импорт playbook'а с ролями
 | ||
| - **Функция:** Разделение логики подготовки и выполнения ролей
 | ||
| 
 | ||
| ## 🎯 Preset файлы
 | ||
| 
 | ||
| ### `molecule/presets/minimal.yml` - Минимальный preset
 | ||
| 
 | ||
| **Назначение:** Быстрое тестирование с одним хостом.
 | ||
| 
 | ||
| **Характеристики:**
 | ||
| - **Количество хостов:** 1
 | ||
| - **ОС:** Debian
 | ||
| - **Группы:** test
 | ||
| - **Использование:** Быстрая проверка ролей
 | ||
| 
 | ||
| ### `molecule/presets/performance.yml` - Performance preset
 | ||
| 
 | ||
| **Назначение:** Нагрузочное тестирование с множеством хостов.
 | ||
| 
 | ||
| **Характеристики:**
 | ||
| - **Количество хостов:** 12
 | ||
| - **Серверы:** 5 узлов (web, app)
 | ||
| - **База данных:** 3 узла
 | ||
| - **Кэш:** 3 узла Redis
 | ||
| - **Load balancer:** 1 узел HAProxy
 | ||
| - **DinD:** 1 узел для Docker Compose
 | ||
| 
 | ||
| **Группы:**
 | ||
| - `servers` - веб-серверы
 | ||
| - `database` - базы данных
 | ||
| - `cache` - кэш серверы
 | ||
| - `loadbalancer` - балансировщик нагрузки
 | ||
| - `apps` - приложения
 | ||
| 
 | ||
| ### `molecule/presets/security.yml` - Security preset
 | ||
| 
 | ||
| **Назначение:** Тестирование безопасности с изолированными сетями.
 | ||
| 
 | ||
| **Характеристики:**
 | ||
| - **Количество хостов:** 10
 | ||
| - **Bastion хосты:** 2 (точки входа)
 | ||
| - **Внутренние серверы:** 3
 | ||
| - **База данных:** 2 (изолированная сеть)
 | ||
| - **Мониторинг:** 2
 | ||
| - **Firewall:** 2
 | ||
| - **DOoD:** 1 для Docker безопасности
 | ||
| 
 | ||
| **Группы:**
 | ||
| - `bastion` - точки входа
 | ||
| - `internal` - внутренние серверы
 | ||
| - `database` - базы данных
 | ||
| - `monitoring` - мониторинг
 | ||
| - `firewall` - сетевые компоненты
 | ||
| - `security` - компоненты безопасности
 | ||
| 
 | ||
| ## 🚀 Использование
 | ||
| 
 | ||
| ### Базовые команды:
 | ||
| 
 | ||
| ```bash
 | ||
| # Тестирование с минимальным preset'ом
 | ||
| make role test minimal
 | ||
| 
 | ||
| # Тестирование с performance preset'ом
 | ||
| make role test performance
 | ||
| 
 | ||
| # Тестирование с security preset'ом
 | ||
| make role test security
 | ||
| 
 | ||
| # Тестирование конкретной роли
 | ||
| make role test minimal ping
 | ||
| 
 | ||
| # Тестирование без preset'а (используются fallback значения)
 | ||
| make role test
 | ||
| 
 | ||
| # Тестирование с несуществующим preset'ом (используются fallback значения)
 | ||
| MOLECULE_PRESET=nonexistent make role test
 | ||
| ```
 | ||
| 
 | ||
| ### Продвинутое использование:
 | ||
| 
 | ||
| ```bash
 | ||
| # Тестирование с кастомным preset'ом
 | ||
| MOLECULE_PRESET=custom make role test
 | ||
| 
 | ||
| # Отладка с подробным выводом
 | ||
| make role test minimal --verbose
 | ||
| 
 | ||
| # Проверка только создания контейнеров
 | ||
| molecule create -s default
 | ||
| 
 | ||
| # Проверка только выполнения ролей
 | ||
| molecule converge -s default
 | ||
| 
 | ||
| # Проверка только верификации
 | ||
| molecule verify -s default
 | ||
| 
 | ||
| # Очистка контейнеров
 | ||
| molecule destroy -s default
 | ||
| ```
 | ||
| 
 | ||
| ## 🔧 Настройка
 | ||
| 
 | ||
| ### Создание собственного preset'а:
 | ||
| 
 | ||
| ```yaml
 | ||
| # molecule/presets/custom.yml
 | ||
| ---
 | ||
| docker_network: labnet
 | ||
| generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
 | ||
| 
 | ||
| images:
 | ||
|   ubuntu: "inecs/ansible-lab:ubuntu-latest"
 | ||
|   rhel: "inecs/ansible-lab:rhel-latest"
 | ||
| 
 | ||
| systemd_defaults:
 | ||
|   privileged: true
 | ||
|   command: "/sbin/init"
 | ||
|   volumes:
 | ||
|     - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
 | ||
|   tmpfs: ["/run", "/run/lock"]
 | ||
|   capabilities: ["SYS_ADMIN"]
 | ||
| 
 | ||
| hosts:
 | ||
|   - name: web1
 | ||
|     family: ubuntu
 | ||
|     groups: [web, servers]
 | ||
|     publish: ["80:80"]
 | ||
|   - name: db1
 | ||
|     family: rhel
 | ||
|     groups: [database, internal]
 | ||
| ```
 | ||
| 
 | ||
| ### Использование fallback значений:
 | ||
| 
 | ||
| ```bash
 | ||
| # Тестирование без preset'а (используются fallback значения из create.yml)
 | ||
| make role test
 | ||
| 
 | ||
| # Тестирование с несуществующим preset'ом (используются fallback значения)
 | ||
| MOLECULE_PRESET=nonexistent make role test
 | ||
| 
 | ||
| # Проверка fallback значений
 | ||
| molecule create -s default --debug
 | ||
| ```
 | ||
| 
 | ||
| ### Использование кастомного preset'а:
 | ||
| 
 | ||
| ```bash
 | ||
| MOLECULE_PRESET=custom make role test
 | ||
| ```
 | ||
| 
 | ||
| ## 🐛 Troubleshooting
 | ||
| 
 | ||
| ### Проблемы с контейнерами:
 | ||
| 
 | ||
| **Ошибка:** Контейнер не запускается
 | ||
| **Решение:** Проверить доступность Docker образа и ресурсы системы
 | ||
| 
 | ||
| **Ошибка:** Systemd не работает
 | ||
| **Решение:** Убедиться что контейнер запущен с `privileged: true` и правильными volumes
 | ||
| 
 | ||
| **Ошибка:** Сетевое взаимодействие не работает
 | ||
| **Решение:** Проверить создание Docker сети и настройки firewall
 | ||
| 
 | ||
| ### Проблемы с preset файлами:
 | ||
| 
 | ||
| **Ошибка:** Preset файл не найден
 | ||
| **Решение:** Система автоматически использует fallback значения из `create.yml`
 | ||
| 
 | ||
| **Ошибка:** Неправильная конфигурация preset'а
 | ||
| **Решение:** Проверить синтаксис YAML и доступность образов в preset файле
 | ||
| 
 | ||
| **Ошибка:** Preset файл не загружается
 | ||
| **Решение:** Убедиться что файл находится в `molecule/presets/` и имеет правильное имя
 | ||
| 
 | ||
| ### Проблемы с ролями:
 | ||
| 
 | ||
| **Ошибка:** Роль не найдена
 | ||
| **Решение:** Проверить путь к роли в `roles/deploy.yml`
 | ||
| 
 | ||
| **Ошибка:** Ошибка выполнения роли
 | ||
| **Решение:** Проверить совместимость роли с ОС и зависимости
 | ||
| 
 | ||
| ### Проблемы с vault:
 | ||
| 
 | ||
| **Ошибка:** Не удается расшифровать vault файлы
 | ||
| **Решение:** Проверить наличие файла `.vault` и правильность пароля
 | ||
| 
 | ||
| **Ошибка:** Vault файлы остались расшифрованными
 | ||
| **Решение:** Проверить права доступа и настройки vault
 | ||
| 
 | ||
| ## 📊 Мониторинг
 | ||
| 
 | ||
| ### Логи выполнения:
 | ||
| 
 | ||
| ```bash
 | ||
| # Просмотр логов Molecule
 | ||
| molecule test -s default --debug
 | ||
| 
 | ||
| # Логи конкретного этапа
 | ||
| molecule create -s default --debug
 | ||
| molecule converge -s default --debug
 | ||
| molecule verify -s default --debug
 | ||
| ```
 | ||
| 
 | ||
| ### Проверка состояния:
 | ||
| 
 | ||
| ```bash
 | ||
| # Статус контейнеров
 | ||
| docker ps
 | ||
| 
 | ||
| # Статус сети
 | ||
| docker network ls
 | ||
| 
 | ||
| # Статус volumes
 | ||
| docker volume ls
 | ||
| ```
 | ||
| 
 | ||
| ## 🎯 Лучшие практики
 | ||
| 
 | ||
| 1. **Используйте подходящие preset'ы** для разных типов тестирования
 | ||
| 2. **Проверяйте совместимость ролей** с различными ОС
 | ||
| 3. **Используйте теги** для разделения задач в ролях
 | ||
| 4. **Документируйте зависимости** ролей
 | ||
| 5. **Тестируйте на разных preset'ах** перед коммитом
 | ||
| 6. **Используйте vault** для секретных данных
 | ||
| 7. **Очищайте ресурсы** после тестирования
 | ||
| 8. **Используйте fallback значения** для быстрого старта без preset'ов
 | ||
| 9. **Проверяйте доступность образов** перед созданием preset'ов
 | ||
| 10. **Документируйте кастомные preset'ы** для команды
 | ||
| 
 | ||
| ## 🔗 Связанные файлы
 | ||
| 
 | ||
| - `roles/deploy.yml` - playbook с ролями
 | ||
| - `inventory/hosts.ini` - статический инвентори
 | ||
| - `vault/.vault` - пароль для vault
 | ||
| - `requirements.yml` - зависимости Ansible
 | ||
| - `Makefile` - команды для запуска тестов
 |