feat: Добавлена универсальная лаборатория для тестирования Ansible ролей
- Создана структура molecule/universal/ с поддержкой DinD и DOoD - Добавлена поддержка Kind кластеров для Kubernetes тестирования - Интегрированы Helm charts (nginx, prometheus-stack) - Добавлена поддержка Istio service mesh с Kiali - Создан Makefile с lab-целями для управления лабораторией - Добавлена поддержка Prometheus + Grafana с автопровижинингом - Создан README с подробной документацией Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
91
Makefile
91
Makefile
@@ -154,4 +154,93 @@ git:
|
|||||||
git checkout -b $$NEW_BRANCH; \
|
git checkout -b $$NEW_BRANCH; \
|
||||||
echo "Создана и переключена на новую ветку: $$NEW_BRANCH";; \
|
echo "Создана и переключена на новую ветку: $$NEW_BRANCH";; \
|
||||||
*) echo "Unknown action. Available actions: push, pull, cluster-branch";; \
|
*) echo "Unknown action. Available actions: push, pull, cluster-branch";; \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# ====== УНИВЕРСАЛЬНАЯ ЛАБОРАТОРИЯ (Molecule universal) ======
|
||||||
|
SCENARIO ?= universal
|
||||||
|
COMPOSE ?= docker compose
|
||||||
|
|
||||||
|
lab-up: ## Поднять контроллер
|
||||||
|
$(COMPOSE) up -d
|
||||||
|
|
||||||
|
lab-down: ## Погасить контроллер
|
||||||
|
$(COMPOSE) down -v
|
||||||
|
|
||||||
|
lab-sh: ## Войти в контроллер
|
||||||
|
docker exec -it ansible-controller bash
|
||||||
|
|
||||||
|
lab-test: lab-up ## Полный цикл Molecule (create+converge+verify+destroy)
|
||||||
|
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||||
|
bash -lc 'cd /ansible && molecule test -s $(SCENARIO)'
|
||||||
|
|
||||||
|
lab-create: lab-up ## Создать инфраструктуру лаборатории
|
||||||
|
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||||
|
bash -lc 'cd /ansible && molecule create -s $(SCENARIO)'
|
||||||
|
|
||||||
|
lab-converge: ## Запустить роли в лаборатории
|
||||||
|
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||||
|
bash -lc 'cd /ansible && molecule converge -s $(SCENARIO)'
|
||||||
|
|
||||||
|
lab-verify: ## Проверить работу лаборатории
|
||||||
|
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||||
|
bash -lc 'cd /ansible && molecule verify -s $(SCENARIO)'
|
||||||
|
|
||||||
|
lab-destroy: ## Уничтожить инфраструктуру лаборатории
|
||||||
|
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule ansible-controller \
|
||||||
|
bash -lc 'cd /ansible && molecule destroy -s $(SCENARIO)'
|
||||||
|
|
||||||
|
lab-reset: lab-destroy lab-down lab-up ## Полный сброс лаборатории
|
||||||
|
|
||||||
|
# ====== K8S ХЕЛПЕРЫ ======
|
||||||
|
kube-sh: ## Shell с kubectl/helm/istioctl внутри контейнера
|
||||||
|
docker exec -it ansible-controller bash
|
||||||
|
|
||||||
|
kube-cmd: ## make kube-cmd CLUSTER=lab CMD="get pods -A"
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make kube-cmd CLUSTER=lab CMD=\"get pods -A\""; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -it ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) $(CMD)'
|
||||||
|
|
||||||
|
kube-enter: ## make kube-enter CLUSTER=lab
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make kube-enter CLUSTER=lab"; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -it ansible-controller bash -lc '\
|
||||||
|
POD=$$(kubectl --context kind-$(CLUSTER) -n lab-demo get pod -l app=toolbox -o jsonpath="{.items[0].metadata.name}"); \
|
||||||
|
[ -n "$$POD" ] || { echo "toolbox pod not found"; exit 1; }; \
|
||||||
|
kubectl --context kind-$(CLUSTER) -n lab-demo exec -it $$POD -- /bin/sh'
|
||||||
|
|
||||||
|
# Port-forward Kiali (http://localhost:20001)
|
||||||
|
kiali-port-forward: ## make kiali-port-forward CLUSTER=lab
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make kiali-port-forward CLUSTER=lab"; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/kiali 20001:20001'
|
||||||
|
|
||||||
|
# Port-forward Istio IngressGateway (HTTP 8082, HTTPS 8444)
|
||||||
|
istio-gw-port-forward: ## make istio-gw-port-forward CLUSTER=lab
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make istio-gw-port-forward CLUSTER=lab"; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/istio-ingressgateway 8082:80 8444:443'
|
||||||
|
@echo "Istio GW forwarded: http://localhost:8082 https://localhost:8444"
|
||||||
|
|
||||||
|
# Port-forward Grafana (http://localhost:3000)
|
||||||
|
grafana-port-forward: ## make grafana-port-forward CLUSTER=lab
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make grafana-port-forward CLUSTER=lab"; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-grafana 3000:80'
|
||||||
|
@echo "Grafana: http://localhost:3000 (admin/admin)"
|
||||||
|
|
||||||
|
# Port-forward Prometheus (http://localhost:9090)
|
||||||
|
prom-port-forward: ## make prom-port-forward CLUSTER=lab
|
||||||
|
ifeq ($(strip $(CLUSTER)),)
|
||||||
|
@echo "Usage: make prom-port-forward CLUSTER=lab"; exit 1
|
||||||
|
endif
|
||||||
|
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-kube-prometheus-prometheus 9090:9090'
|
||||||
|
@echo "Prometheus: http://localhost:9090"
|
||||||
|
|
||||||
|
# Stop all port-forwards
|
||||||
|
kube-pf-stop: ## убить все port-forward в контроллере
|
||||||
|
docker exec -it ansible-controller bash -lc 'pkill -f "kubectl .* port-forward" || true'
|
||||||
193
README-UNIVERSAL-LAB.md
Normal file
193
README-UNIVERSAL-LAB.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Универсальная лаборатория для тестирования 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
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Запуск лаборатории
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Поднять контроллер
|
||||||
|
make lab-up
|
||||||
|
|
||||||
|
# Создать инфраструктуру
|
||||||
|
make lab-create
|
||||||
|
|
||||||
|
# Запустить роли
|
||||||
|
make lab-converge
|
||||||
|
|
||||||
|
# Проверить работу
|
||||||
|
make lab-verify
|
||||||
|
|
||||||
|
# Уничтожить лабораторию
|
||||||
|
make lab-destroy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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]
|
||||||
@@ -1,12 +1,32 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
ansible:
|
ansible-controller:
|
||||||
image: inecs/ansible:latest
|
image: quay.io/ansible/creator-ee:latest
|
||||||
container_name: ansible
|
container_name: ansible-controller
|
||||||
volumes:
|
|
||||||
- .:/ansible
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
environment:
|
|
||||||
- ANSIBLE_VAULT_PASSWORD_FILE=./vault-password.txt
|
|
||||||
tty: true
|
|
||||||
privileged: true
|
privileged: true
|
||||||
working_dir: /ansible
|
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
|
||||||
|
|
||||||
|
# Обратная совместимость
|
||||||
|
# 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
|
||||||
100
files/playbooks/site.yml
Normal file
100
files/playbooks/site.yml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
# Основной 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: ETCD
|
||||||
|
hosts: etcd
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
# - role: your_role_etcd
|
||||||
|
tasks:
|
||||||
|
- name: ETCD placeholder
|
||||||
|
debug:
|
||||||
|
msg: "ETCD группа готова для настройки"
|
||||||
|
|
||||||
|
- name: Patroni
|
||||||
|
hosts: patroni
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
# - role: your_role_patroni
|
||||||
|
tasks:
|
||||||
|
- name: Patroni placeholder
|
||||||
|
debug:
|
||||||
|
msg: "Patroni группа готова для настройки"
|
||||||
|
|
||||||
|
- name: HAProxy
|
||||||
|
hosts: haproxy
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
# - role: your_role_haproxy
|
||||||
|
tasks:
|
||||||
|
- name: HAProxy placeholder
|
||||||
|
debug:
|
||||||
|
msg: "HAProxy группа готова для настройки"
|
||||||
|
|
||||||
|
# Пример: развернуть docker-compose прямо внутри DinD хоста(ов)
|
||||||
|
- name: DinD stack deploy
|
||||||
|
hosts: apps
|
||||||
|
gather_facts: false
|
||||||
|
vars:
|
||||||
|
docker_host: "tcp://{{ inventory_hostname }}:2375"
|
||||||
|
stack_dir: /root/stack
|
||||||
|
tasks:
|
||||||
|
- name: Create stack directory
|
||||||
|
file:
|
||||||
|
path: "{{ stack_dir }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Copy demo docker-compose.yml
|
||||||
|
copy:
|
||||||
|
dest: "{{ stack_dir }}/docker-compose.yml"
|
||||||
|
content: |
|
||||||
|
version: "3.9"
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:alpine
|
||||||
|
ports: ["8080:80"]
|
||||||
|
cache:
|
||||||
|
image: redis:7-alpine
|
||||||
|
|
||||||
|
- name: Deploy stack on DinD
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ stack_dir }}"
|
||||||
|
state: present
|
||||||
|
docker_host: "{{ docker_host }}"
|
||||||
|
when: item.type is defined and item.type == 'dind'
|
||||||
|
loop: "{{ groups['apps'] | map('extract', hostvars) | list }}"
|
||||||
8
files/requirements.yml
Normal file
8
files/requirements.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
# Коллекции Ansible для универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: https://devops.org.ru
|
||||||
|
|
||||||
|
collections:
|
||||||
|
- name: community.docker
|
||||||
|
- name: community.general
|
||||||
46
molecule/presets/k8s-kind.yml
Normal file
46
molecule/presets/k8s-kind.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
# Пресет для Kubernetes лаборатории с Kind кластерами
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: https://devops.org.ru
|
||||||
|
|
||||||
|
# Сеть для лаборатории
|
||||||
|
docker_network: labnet
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Образы для разных семейств ОС
|
||||||
|
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"
|
||||||
|
|
||||||
|
# Определение хостов лаборатории (минимальный набор для k8s)
|
||||||
|
hosts:
|
||||||
|
- name: k8s-controller
|
||||||
|
group: controllers
|
||||||
|
family: debian
|
||||||
|
publish:
|
||||||
|
- "6443:6443"
|
||||||
21
molecule/universal/converge.yml
Normal file
21
molecule/universal/converge.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
# Запуск ролей в универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: https://devops.org.ru
|
||||||
|
|
||||||
|
- hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
tasks:
|
||||||
|
- name: Install collections in controller
|
||||||
|
community.docker.docker_container_exec:
|
||||||
|
container: ansible-controller
|
||||||
|
command: bash -lc "ansible-galaxy collection install -r /ansible/files/requirements.yml || true"
|
||||||
|
|
||||||
|
- name: Run external playbook (your roles live in /ansible/roles)
|
||||||
|
community.docker.docker_container_exec:
|
||||||
|
container: ansible-controller
|
||||||
|
command: >
|
||||||
|
bash -lc "
|
||||||
|
ANSIBLE_ROLES_PATH=/ansible/roles
|
||||||
|
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml
|
||||||
|
"
|
||||||
209
molecule/universal/create.yml
Normal file
209
molecule/universal/create.yml
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
---
|
||||||
|
# Создание инфраструктуры универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: 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"
|
||||||
|
|
||||||
|
# ---------- 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 and Metrics Server (per cluster, if enabled)
|
||||||
|
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
|
||||||
|
# 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
|
||||||
|
done
|
||||||
|
'
|
||||||
|
when: (kind_clusters | default([])) | length > 0
|
||||||
50
molecule/universal/destroy.yml
Normal file
50
molecule/universal/destroy.yml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
# Уничтожение инфраструктуры универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: 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
|
||||||
57
molecule/universal/molecule.yml
Normal file
57
molecule/universal/molecule.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
# Универсальная лаборатория для тестирования 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: default
|
||||||
|
callbacks_enabled: profile_tasks
|
||||||
|
env:
|
||||||
|
ANSIBLE_STDOUT_CALLBACK: default
|
||||||
|
|
||||||
|
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
|
||||||
90
molecule/universal/vars.yml
Normal file
90
molecule/universal/vars.yml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
# Конфигурация универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: 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"
|
||||||
153
molecule/universal/verify.yml
Normal file
153
molecule/universal/verify.yml
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
---
|
||||||
|
# Проверка работы универсальной лаборатории
|
||||||
|
# Автор: Сергей Антропов
|
||||||
|
# Сайт: 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.ini /ansible/files/playbooks/site.yml --check"
|
||||||
|
register: idemp
|
||||||
|
|
||||||
|
# --- 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;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# --- 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 k8s_overview "{{ (k8s_overview.stdout | default("")) | replace("\"","\\\"") }}" \
|
||||||
|
"{
|
||||||
|
timestamp: $$time,
|
||||||
|
idempotence_raw: $$idemp,
|
||||||
|
haproxy_select1: $$haproxy_sel,
|
||||||
|
helm_ingress_toolbox_raw: $$helm_ingress_toolbox,
|
||||||
|
k8s_overview_raw: $$k8s_overview
|
||||||
|
}" > /ansible/reports/lab-health.json
|
||||||
|
'
|
||||||
|
when: kind_names | length > 0
|
||||||
|
|
||||||
|
# --- 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 '✗ Недоступен' }}
|
||||||
|
========================================
|
||||||
3
roles/README.md
Normal file
3
roles/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
# Роли Ansible
|
||||||
|
Разместите ваши роли Ansible в этом каталоге
|
||||||
@@ -1 +1 @@
|
|||||||
password123
|
test
|
||||||
|
|||||||
Reference in New Issue
Block a user