Files
DevOpsLab/molecule/universal/verify.yml
Sergey Antropoff 33ada54c12 feat: Завершена реализация универсальной лаборатории
- Добавлена полная поддержка Istio service mesh с Kiali
- Интегрированы Helm charts (nginx, prometheus-stack)
- Созданы Grafana дашборды для Istio мониторинга
- Добавлен HTML генератор отчетов с красивым дизайном
- Созданы скрипты для снапшотов и восстановления
- Добавлена поддержка Istio Bookinfo demo
- Обновлена документация с полным описанием возможностей

Компоненты:
- Istio с Telemetry и Traffic Policy
- Prometheus + Grafana с автопровижинингом дашбордов
- HTML отчеты с анализом статусов
- Снапшоты и восстановление состояния
- Полная интеграция с Kubernetes

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-10-22 13:08:55 +03:00

279 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
# Проверка работы универсальной лаборатории
# Автор: Сергей Антропов
# Сайт: 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;
# метка для автосайдкаров 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
# --- 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 '✗ Недоступен' }}
========================================