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
This commit is contained in:
2025-10-22 13:08:55 +03:00
parent b4881da7c5
commit 33ada54c12
13 changed files with 712 additions and 2 deletions

View File

@@ -184,12 +184,15 @@
'
when: (kind_clusters | default([])) | length > 0
- name: Install Ingress NGINX and Metrics Server (per cluster, if enabled)
- 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
@@ -204,6 +207,65 @@
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

@@ -43,6 +43,8 @@
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;
@@ -98,6 +100,125 @@
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:
@@ -129,12 +250,16 @@
--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
'