Compare commits
10
Commits
5bca0da31f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23f276417f | ||
|
|
ff808293aa | ||
|
|
9c0189e08e | ||
|
|
d190719c5e | ||
|
|
d41d7f40cc | ||
|
|
3a0853dd4c | ||
|
|
63649a642a | ||
|
|
48f3f1ff22 | ||
|
|
f8ffa9e065 | ||
|
|
58a443a076 |
@@ -0,0 +1,21 @@
|
|||||||
|
# Dockerfile di esempio — containerizza un flow esportato da Langflow
|
||||||
|
# come Python app standalone, da usare nel percorso BYO (Esempio B).
|
||||||
|
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# requirements.txt generato/estratto insieme all'export del flow
|
||||||
|
# (langflow, langgraph-checkpointer-kagent, e le dipendenze del tuo flow)
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Codice esportato dal builder low-code + eventuali customizzazioni
|
||||||
|
# del developer (es. integrazione kagentCheckpointer se usi LangGraph)
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# L'agente deve esporre un endpoint compatibile A2A sulla porta
|
||||||
|
# dichiarata in byo.deployment.port dell'Agent CR
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["python", "agent_server.py"]
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
# crea secret con langflow-secrets-setup.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Poi installa con i valori personalizzati
|
||||||
|
helm install langflow-ide langflow/langflow-ide \
|
||||||
|
-f langflow-values.yaml \
|
||||||
|
-n langflow-team-alpha --create-namespace
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# HTTPRoute (Gateway API) per Langflow IDE
|
||||||
|
# Presuppone un Gateway nginx già esistente nel cluster (nginx Gateway
|
||||||
|
# Fabric), referenziato come parentRef qui sotto.
|
||||||
|
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: langflow-team-alpha
|
||||||
|
namespace: langflow-team-alpha
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: nginx-gateway # nome del Gateway condiviso — verifica con:
|
||||||
|
namespace: nginx-gateway # kubectl get gateway -A
|
||||||
|
sectionName: https # nome del listener HTTPS sul Gateway
|
||||||
|
|
||||||
|
hostnames:
|
||||||
|
- "langflow-team-alpha.pigreco66.it"
|
||||||
|
|
||||||
|
rules:
|
||||||
|
# UI/editor visuale (frontend) — porta 8080 come da doc Langflow
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: langflow-ide-frontend # verifica nome esatto: kubectl get svc -n langflow-team-alpha
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
# API backend, se vuoi esporla separatamente (es. per invocazione
|
||||||
|
# programmatica di un flow senza passare dall'editor) — porta 7860
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /api
|
||||||
|
backendRefs:
|
||||||
|
- name: langflow-ide-backend # verifica nome esatto: kubectl get svc -n langflow-team-alpha
|
||||||
|
port: 7860
|
||||||
|
---
|
||||||
|
# TLS: con Gateway API il certificato si referenzia sul Gateway stesso
|
||||||
|
# (non sull'HTTPRoute). Se il Gateway condiviso non ha già un listener
|
||||||
|
# per questo hostname, serve aggiungerlo lì, es.:
|
||||||
|
#
|
||||||
|
# apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
# kind: Gateway
|
||||||
|
# metadata:
|
||||||
|
# name: nginx-gateway
|
||||||
|
# namespace: nginx-gateway
|
||||||
|
# spec:
|
||||||
|
# gatewayClassName: nginx
|
||||||
|
# listeners:
|
||||||
|
# - name: https
|
||||||
|
# protocol: HTTPS
|
||||||
|
# port: 443
|
||||||
|
# hostname: "*.pigreco66.it"
|
||||||
|
# tls:
|
||||||
|
# mode: Terminate
|
||||||
|
# certificateRefs:
|
||||||
|
# - name: wildcard-pigreco66-it-tls
|
||||||
|
# allowedRoutes:
|
||||||
|
# namespaces:
|
||||||
|
# from: All
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Creazione dei Secret richiesti da langflow-values.yaml
|
||||||
|
# Namespace di esempio: langflow-team-alpha (adatta al tuo tenant)
|
||||||
|
|
||||||
|
# 1. Secret connessione database Postgres
|
||||||
|
kubectl create secret generic langflow-db-secret \
|
||||||
|
-n langflow-team-alpha \
|
||||||
|
--from-literal=connection-string="postgresql://user:pass@host:5432/langflow"
|
||||||
|
|
||||||
|
# 2. Secret credenziali admin (superuser Langflow)
|
||||||
|
kubectl create secret generic langflow-admin-secret \
|
||||||
|
-n langflow-team-alpha \
|
||||||
|
--from-literal=username="admin" \
|
||||||
|
--from-literal=password="<password-sicura>"
|
||||||
|
|
||||||
|
# 3. Secret credenziali LLM — STESSO Secret già usato per kagent nel
|
||||||
|
# golden path di onboarding-team: se lo hai già creato per kagent
|
||||||
|
# in questo namespace, questo passaggio è già fatto, verifica solo
|
||||||
|
# che contenga le chiavi coi nomi attesi (vedi sotto).
|
||||||
|
#
|
||||||
|
# Se non esiste ancora, crealo così (aggiungi/rimuovi provider a
|
||||||
|
# seconda di cosa serve al team):
|
||||||
|
kubectl create secret generic llm-credentials \
|
||||||
|
-n langflow-team-alpha \
|
||||||
|
--from-literal=openai-api-key="sk-..." \
|
||||||
|
--from-literal=anthropic-api-key="sk-ant-..."
|
||||||
|
|
||||||
|
# Se il Secret esiste già (es. creato per kagent) e vuoi solo
|
||||||
|
# aggiungere/aggiornare una chiave senza ricrearlo da zero:
|
||||||
|
kubectl patch secret llm-credentials -n langflow-team-alpha \
|
||||||
|
--type=json \
|
||||||
|
-p='[{"op":"add","path":"/data/openai-api-key","value":"'$(echo -n "sk-..." | base64)'"}]'
|
||||||
|
|
||||||
|
# 4. Verifica che tutti i Secret siano presenti prima di installare/
|
||||||
|
# aggiornare la release Helm
|
||||||
|
kubectl get secrets -n langflow-team-alpha
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# values.yaml — Langflow IDE, personalizzato per un namespace-tenant
|
||||||
|
# Uso: helm install langflow-ide langflow/langflow-ide -f values.yaml -n <namespace>
|
||||||
|
|
||||||
|
langflow:
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: langflowai/langflow
|
||||||
|
tag: "1.10.0" # fissa una versione esplicita, evita 'latest' in produzione
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# Variabili LLM/DB — usa Secret, mai valori in chiaro qui
|
||||||
|
env:
|
||||||
|
- name: LANGFLOW_DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: langflow-db-secret
|
||||||
|
key: connection-string
|
||||||
|
- name: LANGFLOW_SUPERUSER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: langflow-admin-secret
|
||||||
|
key: username
|
||||||
|
- name: LANGFLOW_SUPERUSER_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: langflow-admin-secret
|
||||||
|
key: password
|
||||||
|
# Rimuove automaticamente eventuali API key salvate nei flow prima
|
||||||
|
# di persisterli a DB — best practice di sicurezza, seconda linea
|
||||||
|
# di difesa oltre alle Global Variable qui sotto
|
||||||
|
- name: LANGFLOW_REMOVE_API_KEYS
|
||||||
|
value: "true"
|
||||||
|
|
||||||
|
# --- Pre-caricamento credenziali LLM come Global Variable ---
|
||||||
|
# Riusa lo stesso Secret 'llm-credentials' già previsto per kagent
|
||||||
|
# in fase di onboarding del team (vedi golden path Backstage).
|
||||||
|
# I developer trovano le chiavi già pronte nel dropdown Global
|
||||||
|
# Variable, senza mai vederne il valore reale.
|
||||||
|
- name: LANGFLOW_STORE_ENVIRONMENT_VARIABLES
|
||||||
|
value: "true"
|
||||||
|
- name: LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT
|
||||||
|
value: "OPENAI_API_KEY,ANTHROPIC_API_KEY"
|
||||||
|
- name: OPENAI_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: llm-credentials
|
||||||
|
key: openai-api-key
|
||||||
|
optional: true # non tutti i team useranno tutti i provider
|
||||||
|
- name: ANTHROPIC_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: llm-credentials
|
||||||
|
key: anthropic-api-key
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: langflowai/langflow
|
||||||
|
tag: "1.10.0"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# Ingress classico DISABILITATO — l'esposizione avviene via Gateway API
|
||||||
|
# (nginx Gateway Fabric), vedi manifest separato langflow-httproute.yaml
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Il Service del frontend resta ClusterIP (default del chart), sarà
|
||||||
|
# l'HTTPRoute a instradare il traffico dal Gateway verso questo Service
|
||||||
|
|
||||||
|
# Persistenza dei flow salvati (altrimenti persi al riavvio del pod)
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 5Gi
|
||||||
|
storageClassName: standard # adatta alla tua StorageClass
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# ESEMPIO A — Agent dichiarativo nativo (kagent esegue direttamente)
|
||||||
|
# Caso d'uso: flow Langflow/Flowise semplice — un LLM + un paio di tool,
|
||||||
|
# nessuna logica custom complessa. Tradotto 1:1 in prompt + tool MCP.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: kagent.dev/v1alpha2
|
||||||
|
kind: Agent
|
||||||
|
metadata:
|
||||||
|
name: k8s-troubleshooter
|
||||||
|
namespace: team-alpha
|
||||||
|
spec:
|
||||||
|
description: Agente di troubleshooting Kubernetes
|
||||||
|
type: Declarative
|
||||||
|
declarative:
|
||||||
|
modelConfig: gpt4o-config
|
||||||
|
systemMessage: |
|
||||||
|
Sei un agente di troubleshooting per Kubernetes...
|
||||||
|
a2aConfig:
|
||||||
|
skills:
|
||||||
|
- id: diagnose-pod-issue
|
||||||
|
name: Diagnose Pod Issue
|
||||||
|
description: Investiga problemi su pod/servizi Kubernetes
|
||||||
|
inputModes: ["text"]
|
||||||
|
outputModes: ["text"]
|
||||||
|
tags: ["kubernetes"]
|
||||||
|
tools:
|
||||||
|
- type: McpServer
|
||||||
|
mcpServer:
|
||||||
|
name: kagent-tool-server
|
||||||
|
kind: RemoteMCPServer
|
||||||
|
toolNames:
|
||||||
|
- k8s_get_pods
|
||||||
|
- k8s_describe_pod
|
||||||
|
- k8s_get_logs
|
||||||
|
---
|
||||||
|
apiVersion: kagent.dev/v1alpha1
|
||||||
|
kind: ModelConfig
|
||||||
|
metadata:
|
||||||
|
name: gpt4o-config
|
||||||
|
namespace: team-alpha
|
||||||
|
spec:
|
||||||
|
provider: OpenAI
|
||||||
|
model: gpt-4o
|
||||||
|
apiKeySecretRef:
|
||||||
|
name: llm-credentials
|
||||||
|
key: openai-api-key
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# invocazione
|
||||||
|
Le 4 modalità di invocazione
|
||||||
|
1. Dashboard kagent (per gli utenti umani, uso interattivo)
|
||||||
|
bash
|
||||||
|
kagent dashboard
|
||||||
|
|
||||||
|
Apre una UI web dove cerchi k8s-troubleshooter nella lista e chatti direttamente — il modo più immediato per un developer che vuole testare l'agente senza altri strumenti.
|
||||||
|
|
||||||
|
2. CLI kagent (per script, pipeline, debug da terminale)
|
||||||
|
bash
|
||||||
|
kagent invoke --agent k8s-troubleshooter -n team-alpha \
|
||||||
|
--task "Il pod payment-service-7d9f in default sta crashando, investiga"
|
||||||
|
3. Chiamata diretta via A2A REST (per integrazione da altri sistemi/servizi)
|
||||||
|
|
||||||
|
Ogni Agent espone un endpoint A2A standard, con un "agent card" che ne descrive le capability:
|
||||||
|
|
||||||
|
bash
|
||||||
|
kubectl port-forward -n kagent svc/kagent-service 8083:8083
|
||||||
|
|
||||||
|
# scopri le capability dell'agente
|
||||||
|
curl localhost:8083/api/a2a/team-alpha/k8s-troubleshooter/.well-known/agent.json
|
||||||
|
|
||||||
|
# invocalo
|
||||||
|
curl -X POST localhost:8083/api/a2a/team-alpha/k8s-troubleshooter/ \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"task": "Perché il pod payment-service sta in CrashLoopBackOff?"}'
|
||||||
|
|
||||||
|
Questa è la via che useresti se, ad esempio, un tuo servizio interno (o un'automazione CI/CD) deve invocare l'agente programmaticamente.
|
||||||
|
|
||||||
|
4. Canali chat (Slack/Teams/Discord/Telegram) — via AgentHarness CRD
|
||||||
|
|
||||||
|
Se vuoi che i developer interroghino l'agente direttamente da Slack invece che aprire la dashboard, kagent ha una CRD dedicata (AgentHarness) che fa da ponte:
|
||||||
|
|
||||||
|
yaml
|
||||||
|
apiVersion: kagent.dev/v1alpha2
|
||||||
|
kind: AgentHarness
|
||||||
|
metadata:
|
||||||
|
name: k8s-troubleshooter-slack
|
||||||
|
namespace: kagent
|
||||||
|
spec:
|
||||||
|
backend: hermes
|
||||||
|
modelConfigRef: default-model-config
|
||||||
|
channels:
|
||||||
|
- name: platform
|
||||||
|
type: slack
|
||||||
|
slack:
|
||||||
|
botToken:
|
||||||
|
valueFrom: {type: Secret, name: slack-tokens, key: bot-token}
|
||||||
|
appToken:
|
||||||
|
valueFrom: {type: Secret, name: slack-tokens, key: app-token}
|
||||||
|
|
||||||
|
Poi in Slack: /mykagent perché il pod X sta crashando? — il bot inoltra la richiesta all'agente via A2A e posta la risposta nel canale. Interessante per un'IDP perché è il canale più naturale per i developer, senza dover imparare dashboard o CLI dedicate.
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# ESEMPIO B — Agent BYO (Bring Your Own), container esportato da
|
||||||
|
# Langflow/Flowise dopo containerizzazione custom.
|
||||||
|
# Caso d'uso: flow complesso con logica di stato/loop che il developer
|
||||||
|
# ha personalizzato oltre quello che il builder low-code esporta,
|
||||||
|
# quindi ha bisogno di pieno controllo del codice.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: kagent.dev/v1alpha1
|
||||||
|
kind: Agent
|
||||||
|
metadata:
|
||||||
|
name: currency-exchange-agent
|
||||||
|
namespace: team-alpha
|
||||||
|
spec:
|
||||||
|
type: BYO
|
||||||
|
byo:
|
||||||
|
deployment:
|
||||||
|
image: ghcr.io/team-alpha/langflow-currency-agent:latest
|
||||||
|
workingDir: /app
|
||||||
|
env:
|
||||||
|
- name: GOOGLE_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: llm-credentials
|
||||||
|
key: gemini-api-key
|
||||||
|
port: 8080 # porta su cui l'agente espone l'endpoint A2A
|
||||||
|
|
||||||
|
# Nota: kagent invoca questo agente via protocollo A2A, trattandolo
|
||||||
|
# come black box — nessuna decomposizione in prompt/tool separati,
|
||||||
|
# perché la logica vive interamente dentro l'immagine.
|
||||||
|
|
||||||
|
|
||||||
|
## Esempio Agent di Orchestrazione
|
||||||
|
apiVersion: kagent.dev/v1alpha2
|
||||||
|
kind: Agent
|
||||||
|
metadata:
|
||||||
|
name: incident-commander
|
||||||
|
namespace: team-alpha
|
||||||
|
spec:
|
||||||
|
type: Declarative
|
||||||
|
declarative:
|
||||||
|
systemMessage: |
|
||||||
|
Sei il coordinatore per la gestione incidenti. Quando ricevi una
|
||||||
|
segnalazione, decidi quali specialisti coinvolgere: se riguarda
|
||||||
|
pod/servizi K8s, delega al k8s-troubleshooter; se servono i log,
|
||||||
|
delega al log-analyzer. Puoi chiamare entrambi in sequenza se
|
||||||
|
il problema lo richiede.
|
||||||
|
modelConfig: gpt4o-config
|
||||||
|
tools:
|
||||||
|
- type: McpServer
|
||||||
|
mcpServer:
|
||||||
|
name: kagent-tool-server
|
||||||
|
toolNames: ["k8s_get_events"]
|
||||||
|
|
||||||
|
# Sotto-agenti esposti come "tool" — la scelta di chiamarli
|
||||||
|
# è dell'LLM di incident-commander, non di kagent
|
||||||
|
- type: Agent
|
||||||
|
agent:
|
||||||
|
name: k8s-troubleshooter
|
||||||
|
namespace: team-alpha
|
||||||
|
- type: Agent
|
||||||
|
agent:
|
||||||
|
name: log-analyzer
|
||||||
|
namespace: team-alpha
|
||||||
Binary file not shown.
@@ -0,0 +1,536 @@
|
|||||||
|
BLACKBOX EXPORTER - GUIDA OPERATIVA KUBERNETES
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Stack di partenza
|
||||||
|
-----------------
|
||||||
|
Nel cluster e' gia' installato kube-prometheus-stack nel namespace monitoring:
|
||||||
|
|
||||||
|
```text
|
||||||
|
helm list -A | grep prometheus
|
||||||
|
|
||||||
|
kube-prometheus-stack monitoring 4 2026-08-08 23:55:14.193903052 +0000 UTC deployed kube-prometheus-stack-88.1.5
|
||||||
|
```
|
||||||
|
|
||||||
|
Obiettivo
|
||||||
|
---------
|
||||||
|
Installare prometheus-blackbox-exporter per eseguire test HTTP/HTTPS su servizi Kubernetes interni, Ingress o URL esterni, esportando le metriche verso Prometheus tramite Prometheus Operator.
|
||||||
|
|
||||||
|
Metriche principali:
|
||||||
|
|
||||||
|
```text
|
||||||
|
probe_success
|
||||||
|
probe_duration_seconds
|
||||||
|
probe_http_status_code
|
||||||
|
probe_http_ssl
|
||||||
|
probe_dns_lookup_time_seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
Legenda
|
||||||
|
-------
|
||||||
|
- COMANDO: istruzione da eseguire nel terminale.
|
||||||
|
- FILE: file da creare o aggiornare.
|
||||||
|
- NOTA: informazione da verificare prima di procedere.
|
||||||
|
- OUTPUT ATTESO: risultato indicativo del comando.
|
||||||
|
|
||||||
|
Prerequisiti
|
||||||
|
------------
|
||||||
|
- Accesso kubectl al cluster.
|
||||||
|
- Helm installato.
|
||||||
|
- Namespace monitoring presente o creabile.
|
||||||
|
- kube-prometheus-stack installato con Prometheus Operator.
|
||||||
|
- CRD Probe disponibile: probes.monitoring.coreos.com.
|
||||||
|
|
||||||
|
|
||||||
|
1. VERIFICA PROMETHEUS E PROMETHEUS OPERATOR
|
||||||
|
============================================
|
||||||
|
|
||||||
|
COMANDO - verifica release Helm Prometheus
|
||||||
|
```bash
|
||||||
|
helm list -A | grep prometheus
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica pod Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get pods -A | grep prometheus
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica CRD Probe
|
||||||
|
```bash
|
||||||
|
kubectl get crd probes.monitoring.coreos.com
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica label delle risorse Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get prometheus -A --show-labels
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - controlla selector della risorsa Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get prometheus -n monitoring -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - label dei manifest
|
||||||
|
Dal comando `kubectl get prometheus -A --show-labels` risulta che Prometheus seleziona le risorse con la label `release=kube-prometheus-stack`.
|
||||||
|
Negli esempi sotto viene quindi usata questa label:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
```
|
||||||
|
|
||||||
|
Se in futuro il tuo Prometheus usa un selector diverso, sostituisci questa label nei manifest Probe e PrometheusRule.
|
||||||
|
Controlla soprattutto questi campi nella risorsa Prometheus:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
probeSelector:
|
||||||
|
probeNamespaceSelector:
|
||||||
|
ruleSelector:
|
||||||
|
ruleNamespaceSelector:
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
2. AGGIUNTA REPOSITORY HELM
|
||||||
|
===========================
|
||||||
|
|
||||||
|
COMANDO - aggiungi repository prometheus-community
|
||||||
|
```bash
|
||||||
|
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - aggiorna indice chart Helm
|
||||||
|
```bash
|
||||||
|
helm repo update
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
3. CREA FILE VALUES HELM
|
||||||
|
========================
|
||||||
|
|
||||||
|
FILE - blackbox-values.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- configura i moduli HTTP usati da blackbox-exporter;
|
||||||
|
- espone blackbox-exporter come Service ClusterIP sulla porta 9115;
|
||||||
|
- lascia disabilitato ServiceMonitor perche' lo scraping dei target viene configurato tramite Probe.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-values.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-values.yaml <<'EOF'
|
||||||
|
fullnameOverride: blackbox-exporter
|
||||||
|
|
||||||
|
config:
|
||||||
|
modules:
|
||||||
|
http_2xx:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
valid_http_versions:
|
||||||
|
- HTTP/1.1
|
||||||
|
- HTTP/2.0
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
- 204
|
||||||
|
- 301
|
||||||
|
- 302
|
||||||
|
|
||||||
|
http_post_2xx:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
- 201
|
||||||
|
- 202
|
||||||
|
- 204
|
||||||
|
|
||||||
|
http_k8s_health:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
fail_if_ssl: false
|
||||||
|
fail_if_not_ssl: false
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 9115
|
||||||
|
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
4. INSTALLA BLACKBOX EXPORTER
|
||||||
|
=============================
|
||||||
|
|
||||||
|
COMANDO - installa o aggiorna blackbox-exporter
|
||||||
|
```bash
|
||||||
|
helm upgrade --install blackbox-exporter prometheus-community/prometheus-blackbox-exporter \
|
||||||
|
--namespace monitoring \
|
||||||
|
--create-namespace \
|
||||||
|
-f blackbox-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica pod blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n monitoring | grep blackbox
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica Service blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n monitoring | grep blackbox
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT ATTESO
|
||||||
|
```text
|
||||||
|
blackbox-exporter ClusterIP <cluster-ip> <none> 9115/TCP
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
5. CREA PROBE HTTP PER SERVIZI KUBERNETES INTERNI
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
FILE - blackbox-probes.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- testa endpoint HTTP interni tramite DNS Kubernetes;
|
||||||
|
- usa il modulo http_k8s_health definito in blackbox-values.yaml;
|
||||||
|
- invia le metriche a Prometheus tramite la risorsa Probe del Prometheus Operator.
|
||||||
|
|
||||||
|
Da personalizzare:
|
||||||
|
- my-service
|
||||||
|
- my-namespace
|
||||||
|
- porta del servizio
|
||||||
|
- path HTTP, ad esempio /health, /ready o /
|
||||||
|
- label release se diversa da prometheus
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-probes.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-probes.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: http-services-probe
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: http-services-probe
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_k8s_health
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- http://frontend.idcidp-dev.svc.cluster.local
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - applica Probe servizi interni
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-probes.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica Probe
|
||||||
|
```bash
|
||||||
|
kubectl get probe -n monitoring
|
||||||
|
kubectl describe probe http-services-probe -n monitoring
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - campi importanti della Probe
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
module: http_k8s_health
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- http://my-service.my-namespace.svc.cluster.local:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
6. CREA PROBE HTTP/HTTPS PER INGRESS O URL ESTERNI
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
FILE - blackbox-ingress-probes.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- testa URL esposti tramite Ingress, Gateway, reverse proxy o endpoint pubblici;
|
||||||
|
- usa il modulo generico http_2xx.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-ingress-probes.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-ingress-probes.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: ingress-http-probe
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: ingress-http-probe
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_2xx
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- https://app.example.com/health
|
||||||
|
- https://api.example.com/ready
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - applica Probe endpoint esterni
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-ingress-probes.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
7. VERIFICA METRICHE IN PROMETHEUS
|
||||||
|
==================================
|
||||||
|
|
||||||
|
COMANDO - apri Prometheus in locale con port-forward
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9090:9090
|
||||||
|
```
|
||||||
|
|
||||||
|
Poi apri nel browser:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:9090
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - tutte le probe
|
||||||
|
```promql
|
||||||
|
probe_success
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - probe servizi interni
|
||||||
|
```promql
|
||||||
|
probe_success{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - status code HTTP
|
||||||
|
```promql
|
||||||
|
probe_http_status_code{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - durata probe
|
||||||
|
```promql
|
||||||
|
probe_duration_seconds{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - target falliti
|
||||||
|
```promql
|
||||||
|
probe_success{job="http-services-probe"} == 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Interpretazione:
|
||||||
|
- probe_success = 1: test riuscito.
|
||||||
|
- probe_success = 0: test fallito.
|
||||||
|
- probe_http_status_code: status HTTP ricevuto.
|
||||||
|
- probe_duration_seconds: durata della probe.
|
||||||
|
|
||||||
|
|
||||||
|
8. CREA ALERT PROMETHEUSRULE
|
||||||
|
============================
|
||||||
|
|
||||||
|
FILE - blackbox-http-alerts.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- genera alert quando un target HTTP non risponde correttamente;
|
||||||
|
- genera alert quando un target risponde troppo lentamente.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-http-alerts.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-http-alerts.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: blackbox-http-alerts
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: blackbox-http
|
||||||
|
rules:
|
||||||
|
- alert: BlackboxHttpProbeFailed
|
||||||
|
expr: probe_success == 0
|
||||||
|
for: 2m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "HTTP probe fallita"
|
||||||
|
description: "Il target {{ $labels.instance }} non risponde correttamente da almeno 2 minuti."
|
||||||
|
|
||||||
|
- alert: BlackboxHttpSlowResponse
|
||||||
|
expr: probe_duration_seconds > 2
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "HTTP probe lenta"
|
||||||
|
description: "Il target {{ $labels.instance }} risponde in piu' di 2 secondi da almeno 5 minuti."
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - applica alert
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica PrometheusRule
|
||||||
|
```bash
|
||||||
|
kubectl get prometheusrule -n monitoring | grep blackbox
|
||||||
|
kubectl describe prometheusrule blackbox-http-alerts -n monitoring
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
9. TEST MANUALE BLACKBOX EXPORTER
|
||||||
|
=================================
|
||||||
|
|
||||||
|
COMANDO - port-forward blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/blackbox-exporter 9115:9115
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - esegui probe manuale da un altro terminale
|
||||||
|
```bash
|
||||||
|
curl "http://localhost:9115/probe?target=http://my-service.my-namespace.svc.cluster.local:8080/health&module=http_k8s_health"
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT ATTESO - metriche indicative
|
||||||
|
```text
|
||||||
|
probe_success 1
|
||||||
|
probe_http_status_code 200
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
10. TROUBLESHOOTING
|
||||||
|
===================
|
||||||
|
|
||||||
|
CASO - Prometheus non vede la Probe
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get probe -A
|
||||||
|
kubectl describe probe -n monitoring http-services-probe
|
||||||
|
kubectl get prometheus -n monitoring -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Controlla:
|
||||||
|
- spec.probeSelector
|
||||||
|
- spec.probeNamespaceSelector
|
||||||
|
- metadata.labels della Probe
|
||||||
|
|
||||||
|
CASO - blackbox-exporter non parte
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n monitoring | grep blackbox
|
||||||
|
kubectl logs -n monitoring deploy/blackbox-exporter
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - servizio target non raggiungibile
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n my-namespace
|
||||||
|
kubectl get endpoints -n my-namespace my-service
|
||||||
|
kubectl describe svc -n my-namespace my-service
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - DNS Kubernetes non risolve
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl run dns-test --rm -it --image=busybox:1.36 --restart=Never -- nslookup my-service.my-namespace.svc.cluster.local
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - endpoint HTTPS fallisce per certificati, redirect o header
|
||||||
|
|
||||||
|
Azioni consigliate:
|
||||||
|
- usare il modulo http_2xx per endpoint esterni generici;
|
||||||
|
- verificare se l'endpoint richiede SNI, autenticazione, header custom o path diverso;
|
||||||
|
- aggiungere un modulo dedicato in blackbox-values.yaml se serve una configurazione HTTP specifica.
|
||||||
|
|
||||||
|
|
||||||
|
11. ORDINE DI ESECUZIONE CONSIGLIATO
|
||||||
|
====================================
|
||||||
|
|
||||||
|
COMANDO - sequenza completa
|
||||||
|
```bash
|
||||||
|
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||||
|
helm repo update
|
||||||
|
|
||||||
|
helm upgrade --install blackbox-exporter prometheus-community/prometheus-blackbox-exporter \
|
||||||
|
--namespace monitoring \
|
||||||
|
--create-namespace \
|
||||||
|
-f blackbox-values.yaml
|
||||||
|
|
||||||
|
kubectl apply -f blackbox-probes.yaml
|
||||||
|
kubectl apply -f blackbox-ingress-probes.yaml
|
||||||
|
kubectl apply -f blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
FILE CONSIGLIATI DA VERSIONARE
|
||||||
|
```text
|
||||||
|
blackbox-values.yaml
|
||||||
|
blackbox-probes.yaml
|
||||||
|
blackbox-ingress-probes.yaml
|
||||||
|
blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
12. NOTE PER DEV, QA E PROD
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Per separare gli ambienti e semplificare dashboard e alert, usa Probe distinte:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dev-http-services-probe
|
||||||
|
qa-http-services-probe
|
||||||
|
prod-http-services-probe
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - ambiente dev
|
||||||
|
```promql
|
||||||
|
probe_success{job="dev-http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - target prod falliti
|
||||||
|
```promql
|
||||||
|
probe_success{job="prod-http-services-probe"} == 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Per endpoint critici in produzione, valuta:
|
||||||
|
- interval piu' basso, ad esempio 15s o 30s;
|
||||||
|
- durata for degli alert tra 1m e 5m in base alla criticita';
|
||||||
|
- dashboard Grafana con stato, status code e latenza per target.
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
kubectl cnpg psql pg-devops -n devops
|
||||||
|
|
||||||
|
CREATE DATABASE giteadbtest;
|
||||||
|
CREATE USER giteatest WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE giteadbtest TO giteatest;
|
||||||
|
ALTER DATABASE giteadbtest OWNER TO giteatest;
|
||||||
|
|
||||||
|
helm repo add gitea https://dl.gitea.io/charts/
|
||||||
|
helm repo update
|
||||||
|
|
||||||
|
|
||||||
|
kubectl create namespace gitea
|
||||||
|
|
||||||
|
cat <<EOF |cat >valuestest.yaml -
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: gitea/gitea
|
||||||
|
tag: 1.25.4-rootless
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
|
||||||
|
service:
|
||||||
|
http:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 3000
|
||||||
|
ssh:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 22
|
||||||
|
|
||||||
|
redis-cluster:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: csi-rbdfs-sc
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
postgresql-ha:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
admin:
|
||||||
|
username: gitadmin
|
||||||
|
password: KAYQE1QA7uwUZ8uI
|
||||||
|
email: gitadmin@italiadatacenter.com
|
||||||
|
|
||||||
|
config:
|
||||||
|
database:
|
||||||
|
DB_TYPE: postgres
|
||||||
|
HOST: pg-devops-rw.devops.svc:5432
|
||||||
|
NAME: giteadbtest
|
||||||
|
USER: giteatest
|
||||||
|
PASSWD: KAYQE1QA7uwUZ8uI
|
||||||
|
SSL_MODE: disable
|
||||||
|
|
||||||
|
server:
|
||||||
|
ROOT_URL: https://git2.pigreco66.it/
|
||||||
|
SSH_DOMAIN: git2.pigreco66.it
|
||||||
|
SSH_PORT: 22
|
||||||
|
|
||||||
|
security:
|
||||||
|
INSTALL_LOCK: true
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
helm upgrade --install gitea gitea-charts/gitea --namespace gitea -f values.yaml
|
||||||
|
|
||||||
|
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitea
|
||||||
|
namespace: gitea
|
||||||
|
spec:
|
||||||
|
hostnames:
|
||||||
|
- git.italiadatacenter.com
|
||||||
|
parentRefs:
|
||||||
|
- name: main-gateway
|
||||||
|
namespace: nginx-gateway
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitea-http
|
||||||
|
port: 3000
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-b
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-B/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-B
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -1,7 +1,32 @@
|
|||||||
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
|
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
|
||||||
kubectl create namespace cattle-system
|
kubectl create namespace cattle-system
|
||||||
|
|
||||||
helm install rancher rancher-stable/rancher \
|
helm install rancher rancher-stable/rancher --namespace cattle-system --set hostname=idc.internal --set bootstrapPassword=.... --set ingress.tls.source=rancher
|
||||||
|
|
||||||
|
|
||||||
|
helm upgrade rancher rancher-stable/rancher \
|
||||||
--namespace cattle-system \
|
--namespace cattle-system \
|
||||||
--set hostname=k8s.italiadatacenter.com \
|
--reuse-values \
|
||||||
--set bootstrapPassword=admin
|
--set hostname=idc.internal \
|
||||||
|
--set bootstrapPassword=KAYQE1QA7uwUZ8uI \
|
||||||
|
--set ingress.enabled=false \
|
||||||
|
--set ingress.tls.source=rancher
|
||||||
|
|
||||||
|
Poc-25_sts
|
||||||
|
|
||||||
|
POC-25_sts
|
||||||
|
|
||||||
|
vi sistemarancher.sh
|
||||||
|
# 1. recupera il ClusterIP del service "rancher" già creato dal chart
|
||||||
|
CLUSTERIP=$(kubectl get svc -n cattle-system rancher -o jsonpath='{.spec.clusterIP}')
|
||||||
|
|
||||||
|
# 2. patch del deployment per aggiungere hostAliases
|
||||||
|
kubectl patch deployment rancher -n cattle-system --type='json' \
|
||||||
|
-p="[{\"op\":\"add\",\"path\":\"/spec/template/spec/hostAliases\",\"value\":[{\"ip\":\"$CLUSTERIP\",\"hostnames\":[\"idc.internal\"]}]}]"
|
||||||
|
|
||||||
|
# 3. crea il service NodePort per l'accesso dal browser
|
||||||
|
kubectl expose deployment rancher -n cattle-system --type=NodePort --port=443 --target-port=443 --name=rancher-nodeport
|
||||||
|
|
||||||
|
# 4. riavvia e segui i log
|
||||||
|
kubectl rollout restart deployment rancher -n cattle-system
|
||||||
|
kubectl -n cattle-system logs -l app=rancher -f
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: opens3-console-secrets
|
||||||
|
namespace: minio
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# Endpoint S3 del server MinIO a cui la console si collega.
|
||||||
|
# Cambialo con l'URL reale del tuo MinIO (Service interno o esterno).
|
||||||
|
CONSOLE_MINIO_SERVER: "http://minio.minio.svc.cluster.local:9000"
|
||||||
|
|
||||||
|
# Passphrase e salt usati da opens3/console per cifrare le sessioni
|
||||||
|
# (PBKDF2). Generane di robusti, es.:
|
||||||
|
# openssl rand -base64 32
|
||||||
|
CONSOLE_PBKDF_PASSPHRASE: "OHB576kn9SS4JdD7qG4+hyjRpa353HQqxPQ22z2Do0w="
|
||||||
|
CONSOLE_PBKDF_SALT: "OBHOWF2INklmrtmyI+qNEb3dbV0yz9ZAxiJJCcC6GYw="
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: opens3-console
|
||||||
|
namespace: minio
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: console
|
||||||
|
image: opens3/console:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 9090
|
||||||
|
protocol: TCP
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: opens3-console-secrets
|
||||||
|
# Se il MinIO target usa certificati self-signed, decommenta:
|
||||||
|
# env:
|
||||||
|
# - name: CONSOLE_MINIO_TLS_SKIP_VERIFICATION
|
||||||
|
# value: "on"
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
timeoutSeconds: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: opens3-console
|
||||||
|
namespace: minio
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: httproute-minio-direct
|
||||||
|
spec:
|
||||||
|
hostnames:
|
||||||
|
- idcidp.pigreco66.it
|
||||||
|
parentRefs:
|
||||||
|
- group: gateway.networking.k8s.io
|
||||||
|
kind: Gateway
|
||||||
|
name: main-gateway
|
||||||
|
namespace: nginx-gateway
|
||||||
|
rules:
|
||||||
|
- backendRefs:
|
||||||
|
- group: ""
|
||||||
|
kind: Service
|
||||||
|
name: opens3-console
|
||||||
|
port: 80
|
||||||
|
weight: 1
|
||||||
|
filters:
|
||||||
|
- responseHeaderModifier:
|
||||||
|
remove:
|
||||||
|
- X-Frame-Options
|
||||||
|
- Content-Security-Policy
|
||||||
|
set:
|
||||||
|
- name: X-Frame-Options
|
||||||
|
value: SAMEORIGIN
|
||||||
|
- name: Content-Security-Policy
|
||||||
|
value: frame-ancestors 'self'
|
||||||
|
type: ResponseHeaderModifier
|
||||||
|
matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /minio-console
|
||||||
@@ -0,0 +1,870 @@
|
|||||||
|
BLACKBOX EXPORTER - GUIDA OPERATIVA KUBERNETES
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Stack di partenza
|
||||||
|
-----------------
|
||||||
|
Nel cluster e' gia' installato kube-prometheus-stack nel namespace monitoring:
|
||||||
|
|
||||||
|
```text
|
||||||
|
helm list -A | grep prometheus
|
||||||
|
|
||||||
|
kube-prometheus-stack monitoring 4 2026-08-08 23:55:14.193903052 +0000 UTC deployed kube-prometheus-stack-88.1.5
|
||||||
|
```
|
||||||
|
|
||||||
|
Obiettivo
|
||||||
|
---------
|
||||||
|
Installare prometheus-blackbox-exporter per eseguire test HTTP/HTTPS su servizi Kubernetes interni, Ingress o URL esterni, esportando le metriche verso Prometheus tramite Prometheus Operator.
|
||||||
|
|
||||||
|
Metriche principali:
|
||||||
|
|
||||||
|
```text
|
||||||
|
probe_success
|
||||||
|
probe_duration_seconds
|
||||||
|
probe_http_status_code
|
||||||
|
probe_http_ssl
|
||||||
|
probe_dns_lookup_time_seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
Legenda
|
||||||
|
-------
|
||||||
|
- COMANDO: istruzione da eseguire nel terminale.
|
||||||
|
- FILE: file da creare o aggiornare.
|
||||||
|
- NOTA: informazione da verificare prima di procedere.
|
||||||
|
- OUTPUT ATTESO: risultato indicativo del comando.
|
||||||
|
|
||||||
|
Prerequisiti
|
||||||
|
------------
|
||||||
|
- Accesso kubectl al cluster.
|
||||||
|
- Helm installato.
|
||||||
|
- Namespace monitoring presente o creabile.
|
||||||
|
- kube-prometheus-stack installato con Prometheus Operator.
|
||||||
|
- CRD Probe disponibile: probes.monitoring.coreos.com.
|
||||||
|
|
||||||
|
|
||||||
|
1. VERIFICA PROMETHEUS E PROMETHEUS OPERATOR
|
||||||
|
============================================
|
||||||
|
|
||||||
|
COMANDO - verifica release Helm Prometheus
|
||||||
|
```bash
|
||||||
|
helm list -A | grep prometheus
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica pod Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get pods -A | grep prometheus
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica CRD Probe
|
||||||
|
```bash
|
||||||
|
kubectl get crd probes.monitoring.coreos.com
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica label delle risorse Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get prometheus -A --show-labels
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - controlla selector della risorsa Prometheus
|
||||||
|
```bash
|
||||||
|
kubectl get prometheus -n monitoring -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - label dei manifest
|
||||||
|
Dal comando `kubectl get prometheus -A --show-labels` risulta che Prometheus seleziona le risorse con la label `release=kube-prometheus-stack`.
|
||||||
|
Negli esempi sotto viene quindi usata questa label:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
```
|
||||||
|
|
||||||
|
Se in futuro il tuo Prometheus usa un selector diverso, sostituisci questa label nei manifest Probe e PrometheusRule.
|
||||||
|
Controlla soprattutto questi campi nella risorsa Prometheus:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
probeSelector:
|
||||||
|
probeNamespaceSelector:
|
||||||
|
ruleSelector:
|
||||||
|
ruleNamespaceSelector:
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
2. AGGIUNTA REPOSITORY HELM
|
||||||
|
===========================
|
||||||
|
|
||||||
|
COMANDO - aggiungi repository prometheus-community
|
||||||
|
```bash
|
||||||
|
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - aggiorna indice chart Helm
|
||||||
|
```bash
|
||||||
|
helm repo update
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
3. CREA FILE VALUES HELM
|
||||||
|
========================
|
||||||
|
|
||||||
|
FILE - blackbox-values.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- configura i moduli HTTP usati da blackbox-exporter;
|
||||||
|
- espone blackbox-exporter come Service ClusterIP sulla porta 9115;
|
||||||
|
- lascia disabilitato ServiceMonitor perche' lo scraping dei target viene configurato tramite Probe.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-values.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-values.yaml <<'EOF'
|
||||||
|
fullnameOverride: blackbox-exporter
|
||||||
|
|
||||||
|
config:
|
||||||
|
modules:
|
||||||
|
http_2xx:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
valid_http_versions:
|
||||||
|
- HTTP/1.1
|
||||||
|
- HTTP/2.0
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
- 204
|
||||||
|
- 301
|
||||||
|
- 302
|
||||||
|
|
||||||
|
http_post_2xx:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
- 201
|
||||||
|
- 202
|
||||||
|
- 204
|
||||||
|
|
||||||
|
http_k8s_health:
|
||||||
|
prober: http
|
||||||
|
timeout: 10s
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
preferred_ip_protocol: ip4
|
||||||
|
fail_if_ssl: false
|
||||||
|
fail_if_not_ssl: false
|
||||||
|
valid_status_codes:
|
||||||
|
- 200
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 9115
|
||||||
|
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
4. INSTALLA BLACKBOX EXPORTER
|
||||||
|
=============================
|
||||||
|
|
||||||
|
COMANDO - installa o aggiorna blackbox-exporter
|
||||||
|
```bash
|
||||||
|
helm upgrade --install blackbox-exporter prometheus-community/prometheus-blackbox-exporter \
|
||||||
|
--namespace monitoring \
|
||||||
|
--create-namespace \
|
||||||
|
-f blackbox-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica pod blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n monitoring | grep blackbox
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica Service blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n monitoring | grep blackbox
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT ATTESO
|
||||||
|
```text
|
||||||
|
blackbox-exporter ClusterIP <cluster-ip> <none> 9115/TCP
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
5. CREA PROBE HTTP PER SERVIZI KUBERNETES INTERNI
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
FILE - blackbox-probes.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- testa endpoint HTTP interni tramite DNS Kubernetes;
|
||||||
|
- usa il modulo http_k8s_health definito in blackbox-values.yaml;
|
||||||
|
- invia le metriche a Prometheus tramite la risorsa Probe del Prometheus Operator.
|
||||||
|
|
||||||
|
Da personalizzare:
|
||||||
|
- my-service
|
||||||
|
- my-namespace
|
||||||
|
- porta del servizio
|
||||||
|
- path HTTP, ad esempio /health, /ready o /
|
||||||
|
- label release se diversa da prometheus
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-probes.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-probes.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: http-services-probe
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: http-services-probe
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_k8s_health
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- http://my-service.my-namespace.svc.cluster.local:8080/health
|
||||||
|
- http://another-service.default.svc.cluster.local:80/
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - applica Probe servizi interni
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-probes.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica Probe
|
||||||
|
```bash
|
||||||
|
kubectl get probe -n monitoring
|
||||||
|
kubectl describe probe http-services-probe -n monitoring
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - campi importanti della Probe
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
module: http_k8s_health
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- http://my-service.my-namespace.svc.cluster.local:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
6. CREA PROBE HTTP/HTTPS PER INGRESS O URL ESTERNI
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
FILE - blackbox-ingress-probes.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- testa URL esposti tramite Ingress, Gateway, reverse proxy o endpoint pubblici;
|
||||||
|
- usa il modulo generico http_2xx.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-ingress-probes.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-ingress-probes.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: ingress-http-probe
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: ingress-http-probe
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_2xx
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- https://app.example.com/health
|
||||||
|
- https://api.example.com/ready
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - applica Probe endpoint esterni
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-ingress-probes.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
7. VERIFICA METRICHE IN PROMETHEUS
|
||||||
|
==================================
|
||||||
|
|
||||||
|
COMANDO - apri Prometheus in locale con port-forward
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9090:9090
|
||||||
|
```
|
||||||
|
|
||||||
|
Poi apri nel browser:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:9090
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - tutte le probe
|
||||||
|
```promql
|
||||||
|
probe_success
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - probe servizi interni
|
||||||
|
```promql
|
||||||
|
probe_success{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - status code HTTP
|
||||||
|
```promql
|
||||||
|
probe_http_status_code{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - durata probe
|
||||||
|
```promql
|
||||||
|
probe_duration_seconds{job="http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - target falliti
|
||||||
|
```promql
|
||||||
|
probe_success{job="http-services-probe"} == 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Interpretazione:
|
||||||
|
- probe_success = 1: test riuscito.
|
||||||
|
- probe_success = 0: test fallito.
|
||||||
|
- probe_http_status_code: status HTTP ricevuto.
|
||||||
|
- probe_duration_seconds: durata della probe.
|
||||||
|
|
||||||
|
|
||||||
|
8. CREA DASHBOARD GRAFANA PER LE PROBE
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Obiettivo:
|
||||||
|
- visualizzare lo stato delle probe HTTP;
|
||||||
|
- vedere quali target sono UP o DOWN;
|
||||||
|
- controllare status code e latenza per ogni endpoint;
|
||||||
|
- filtrare la dashboard per job e target.
|
||||||
|
|
||||||
|
COMANDO - apri Grafana in locale con port-forward
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
|
||||||
|
```
|
||||||
|
|
||||||
|
Poi apri nel browser:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - recupera password admin Grafana se non la conosci
|
||||||
|
```bash
|
||||||
|
kubectl get secret -n monitoring kube-prometheus-stack-grafana \
|
||||||
|
-o jsonpath="{.data.admin-password}" | base64 -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Credenziali predefinite tipiche:
|
||||||
|
```text
|
||||||
|
utente: admin
|
||||||
|
password: valore recuperato dal secret
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - datasource Prometheus
|
||||||
|
Con kube-prometheus-stack il datasource Prometheus di solito e' gia' configurato in Grafana.
|
||||||
|
Verifica da Grafana:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Connections -> Data sources -> Prometheus
|
||||||
|
```
|
||||||
|
|
||||||
|
CREAZIONE DASHBOARD DA INTERFACCIA
|
||||||
|
|
||||||
|
1. Vai su Dashboards -> New -> New dashboard.
|
||||||
|
2. Clicca Add visualization.
|
||||||
|
3. Seleziona il datasource Prometheus.
|
||||||
|
4. Crea i pannelli usando le query sotto.
|
||||||
|
5. Salva la dashboard con nome, ad esempio:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Blackbox HTTP Probes
|
||||||
|
```
|
||||||
|
|
||||||
|
VARIABILI CONSIGLIATE
|
||||||
|
|
||||||
|
Variabile job:
|
||||||
|
```text
|
||||||
|
Name: job
|
||||||
|
Type: Query
|
||||||
|
Data source: Prometheus
|
||||||
|
Query: label_values(probe_success, job)
|
||||||
|
Multi-value: enabled
|
||||||
|
Include All option: enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
Variabile instance:
|
||||||
|
```text
|
||||||
|
Name: instance
|
||||||
|
Type: Query
|
||||||
|
Data source: Prometheus
|
||||||
|
Query: label_values(probe_success{job=~"$job"}, instance)
|
||||||
|
Multi-value: enabled
|
||||||
|
Include All option: enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - stato generale probe
|
||||||
|
|
||||||
|
Tipo pannello: Stat
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
min(probe_success{job=~"$job", instance=~"$instance"})
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Unit: none
|
||||||
|
Thresholds:
|
||||||
|
0 = red
|
||||||
|
1 = green
|
||||||
|
Value mappings:
|
||||||
|
0 -> DOWN
|
||||||
|
1 -> UP
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - stato per target
|
||||||
|
|
||||||
|
Tipo pannello: State timeline oppure Table
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
probe_success{job=~"$job", instance=~"$instance"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Legend: {{ instance }}
|
||||||
|
Value mappings:
|
||||||
|
0 -> DOWN
|
||||||
|
1 -> UP
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - target attualmente falliti
|
||||||
|
|
||||||
|
Tipo pannello: Table
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
probe_success{job=~"$job", instance=~"$instance"} == 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Legend: {{ instance }}
|
||||||
|
Mostra colonne: instance, job, value
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - durata probe per target
|
||||||
|
|
||||||
|
Tipo pannello: Time series
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
probe_duration_seconds{job=~"$job", instance=~"$instance"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Unit: seconds
|
||||||
|
Legend: {{ instance }}
|
||||||
|
Thresholds:
|
||||||
|
1 = yellow
|
||||||
|
2 = red
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - status code HTTP
|
||||||
|
|
||||||
|
Tipo pannello: Time series oppure Table
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
probe_http_status_code{job=~"$job", instance=~"$instance"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Unit: none
|
||||||
|
Legend: {{ instance }}
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - percentuale disponibilita' per target
|
||||||
|
|
||||||
|
Tipo pannello: Bar gauge oppure Table
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
avg_over_time(probe_success{job=~"$job", instance=~"$instance"}[24h]) * 100
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Unit: percent
|
||||||
|
Min: 0
|
||||||
|
Max: 100
|
||||||
|
Legend: {{ instance }}
|
||||||
|
Thresholds:
|
||||||
|
95 = yellow
|
||||||
|
99 = green
|
||||||
|
```
|
||||||
|
|
||||||
|
PANNELLO - durata media nelle ultime 24 ore
|
||||||
|
|
||||||
|
Tipo pannello: Bar gauge oppure Table
|
||||||
|
|
||||||
|
Query:
|
||||||
|
```promql
|
||||||
|
avg_over_time(probe_duration_seconds{job=~"$job", instance=~"$instance"}[24h])
|
||||||
|
```
|
||||||
|
|
||||||
|
Configurazione consigliata:
|
||||||
|
```text
|
||||||
|
Unit: seconds
|
||||||
|
Legend: {{ instance }}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY RAPIDE SENZA VARIABILI
|
||||||
|
|
||||||
|
Se vuoi creare una dashboard solo per la Probe di esempio dei servizi interni:
|
||||||
|
|
||||||
|
```promql
|
||||||
|
probe_success{job="http-services-probe"}
|
||||||
|
probe_http_status_code{job="http-services-probe"}
|
||||||
|
probe_duration_seconds{job="http-services-probe"}
|
||||||
|
probe_success{job="http-services-probe"} == 0
|
||||||
|
avg_over_time(probe_success{job="http-services-probe"}[24h]) * 100
|
||||||
|
```
|
||||||
|
|
||||||
|
Per la Probe di esempio degli Ingress o URL esterni:
|
||||||
|
|
||||||
|
```promql
|
||||||
|
probe_success{job="ingress-http-probe"}
|
||||||
|
probe_http_status_code{job="ingress-http-probe"}
|
||||||
|
probe_duration_seconds{job="ingress-http-probe"}
|
||||||
|
probe_success{job="ingress-http-probe"} == 0
|
||||||
|
avg_over_time(probe_success{job="ingress-http-probe"}[24h]) * 100
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
9. CREA ALERT PROMETHEUSRULE
|
||||||
|
============================
|
||||||
|
|
||||||
|
FILE - blackbox-http-alerts.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- genera alert quando un target HTTP non risponde correttamente;
|
||||||
|
- genera alert quando un target risponde troppo lentamente.
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-http-alerts.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-http-alerts.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: blackbox-http-alerts
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: blackbox-http
|
||||||
|
rules:
|
||||||
|
- alert: BlackboxHttpProbeFailed
|
||||||
|
expr: probe_success == 0
|
||||||
|
for: 2m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "HTTP probe fallita"
|
||||||
|
description: "Il target {{ $labels.instance }} non risponde correttamente da almeno 2 minuti."
|
||||||
|
|
||||||
|
- alert: BlackboxHttpSlowResponse
|
||||||
|
expr: probe_duration_seconds > 2
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "HTTP probe lenta"
|
||||||
|
description: "Il target {{ $labels.instance }} risponde in piu' di 2 secondi da almeno 5 minuti."
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
COMANDO - applica alert
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica PrometheusRule
|
||||||
|
```bash
|
||||||
|
kubectl get prometheusrule -n monitoring | grep blackbox
|
||||||
|
kubectl describe prometheusrule blackbox-http-alerts -n monitoring
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
10. CONFIGURA ALERTMANAGER - INVIO EMAIL SU FAIL DI UN SERVIZIO
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
Obiettivo:
|
||||||
|
- inviare una email a un indirizzo specifico quando la probe di un
|
||||||
|
servizio specifico (serviceX) fallisce (alert BlackboxHttpProbeFailed).
|
||||||
|
|
||||||
|
FILE - blackbox-email-alert.yaml
|
||||||
|
|
||||||
|
Descrizione:
|
||||||
|
- crea un receiver email dedicato al servizio da monitorare;
|
||||||
|
- instrada verso quel receiver solo gli alert che riguardano il
|
||||||
|
target specifico, identificato tramite il label instance.
|
||||||
|
|
||||||
|
NOTA - credenziali SMTP
|
||||||
|
Se il server SMTP richiede autenticazione, crea prima un Secret con
|
||||||
|
la password:
|
||||||
|
|
||||||
|
COMANDO - crea secret con password SMTP
|
||||||
|
```bash
|
||||||
|
kubectl create secret generic alertmanager-smtp \
|
||||||
|
-n monitoring --from-literal=password='<SMTP_PASSWORD>'
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - crea blackbox-email-alert.yaml
|
||||||
|
```bash
|
||||||
|
cat > blackbox-email-alert.yaml <<'EOF'
|
||||||
|
apiVersion: monitoring.coreos.com/v1alpha1
|
||||||
|
kind: AlertmanagerConfig
|
||||||
|
metadata:
|
||||||
|
name: blackbox-email-routing
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
route:
|
||||||
|
groupBy: ["alertname", "instance"]
|
||||||
|
groupWait: 30s
|
||||||
|
groupInterval: 5m
|
||||||
|
repeatInterval: 1h
|
||||||
|
receiver: "email-default"
|
||||||
|
routes:
|
||||||
|
- matchers:
|
||||||
|
- name: alertname
|
||||||
|
value: BlackboxHttpProbeFailed
|
||||||
|
matchType: "="
|
||||||
|
- name: instance
|
||||||
|
value: "<SERVIZIO_X_URL_O_HOST>"
|
||||||
|
matchType: "="
|
||||||
|
receiver: "email-servizioX"
|
||||||
|
|
||||||
|
receivers:
|
||||||
|
- name: "email-default"
|
||||||
|
emailConfigs: []
|
||||||
|
|
||||||
|
- name: "email-servizioX"
|
||||||
|
emailConfigs:
|
||||||
|
- to: "<INDIRIZZO_X>"
|
||||||
|
from: "<SMTP_FROM>"
|
||||||
|
smarthost: "<SMTP_HOST>:<SMTP_PORT>"
|
||||||
|
authUsername: "<SMTP_USER>"
|
||||||
|
authPassword:
|
||||||
|
name: alertmanager-smtp
|
||||||
|
key: password
|
||||||
|
requireTLS: true
|
||||||
|
sendResolved: true
|
||||||
|
headers:
|
||||||
|
subject: "[ALERT] Servizio X non raggiungibile"
|
||||||
|
html: |
|
||||||
|
<p>Il servizio <b>{{ "{{" }} .CommonLabels.instance {{ "}}" }}</b> non risponde.</p>
|
||||||
|
<p>{{ "{{" }} .CommonAnnotations.description {{ "}}" }}</p>
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Da personalizzare:
|
||||||
|
- <SERVIZIO_X_URL_O_HOST>: valore del label instance della probe da
|
||||||
|
monitorare (es. http://my-service.my-namespace.svc.cluster.local:8080/health);
|
||||||
|
- <INDIRIZZO_X>: indirizzo email destinatario;
|
||||||
|
- <SMTP_HOST>, <SMTP_PORT>: server SMTP (es. smtp.gmail.com:587);
|
||||||
|
- <SMTP_FROM>: mittente email;
|
||||||
|
- <SMTP_USER>: utente SMTP, se richiesta autenticazione.
|
||||||
|
|
||||||
|
COMANDO - applica la configurazione
|
||||||
|
```bash
|
||||||
|
kubectl apply -f blackbox-email-alert.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica AlertmanagerConfig
|
||||||
|
```bash
|
||||||
|
kubectl get alertmanagerconfig -n monitoring
|
||||||
|
kubectl describe alertmanagerconfig blackbox-email-routing -n monitoring
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTA - matcher su instance vs job
|
||||||
|
Se vuoi far scattare l'email per TUTTI i target di una Probe (job)
|
||||||
|
invece che per un singolo servizio, sostituisci il matcher su
|
||||||
|
`instance` con:
|
||||||
|
```yaml
|
||||||
|
- name: job
|
||||||
|
value: "http-services-probe"
|
||||||
|
matchType: "="
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - verifica alert in Alertmanager
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/kube-prometheus-stack-alertmanager 9093
|
||||||
|
# -> http://localhost:9093, controlla che l'alert BlackboxHttpProbeFailed
|
||||||
|
# per il servizio X sia instradato sul receiver email-servizioX
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
11. TEST MANUALE BLACKBOX EXPORTER
|
||||||
|
==================================
|
||||||
|
|
||||||
|
COMANDO - port-forward blackbox-exporter
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n monitoring svc/blackbox-exporter 9115:9115
|
||||||
|
```
|
||||||
|
|
||||||
|
COMANDO - esegui probe manuale da un altro terminale
|
||||||
|
```bash
|
||||||
|
curl "http://localhost:9115/probe?target=http://my-service.my-namespace.svc.cluster.local:8080/health&module=http_k8s_health"
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT ATTESO - metriche indicative
|
||||||
|
```text
|
||||||
|
probe_success 1
|
||||||
|
probe_http_status_code 200
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
12. TROUBLESHOOTING
|
||||||
|
===================
|
||||||
|
|
||||||
|
CASO - Prometheus non vede la Probe
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get probe -A
|
||||||
|
kubectl describe probe -n monitoring http-services-probe
|
||||||
|
kubectl get prometheus -n monitoring -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Controlla:
|
||||||
|
- spec.probeSelector
|
||||||
|
- spec.probeNamespaceSelector
|
||||||
|
- metadata.labels della Probe
|
||||||
|
|
||||||
|
CASO - blackbox-exporter non parte
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n monitoring | grep blackbox
|
||||||
|
kubectl logs -n monitoring deploy/blackbox-exporter
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - servizio target non raggiungibile
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n my-namespace
|
||||||
|
kubectl get endpoints -n my-namespace my-service
|
||||||
|
kubectl describe svc -n my-namespace my-service
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - DNS Kubernetes non risolve
|
||||||
|
|
||||||
|
COMANDO
|
||||||
|
```bash
|
||||||
|
kubectl run dns-test --rm -it --image=busybox:1.36 --restart=Never -- nslookup my-service.my-namespace.svc.cluster.local
|
||||||
|
```
|
||||||
|
|
||||||
|
CASO - endpoint HTTPS fallisce per certificati, redirect o header
|
||||||
|
|
||||||
|
Azioni consigliate:
|
||||||
|
- usare il modulo http_2xx per endpoint esterni generici;
|
||||||
|
- verificare se l'endpoint richiede SNI, autenticazione, header custom o path diverso;
|
||||||
|
- aggiungere un modulo dedicato in blackbox-values.yaml se serve una configurazione HTTP specifica.
|
||||||
|
|
||||||
|
|
||||||
|
13. ORDINE DI ESECUZIONE CONSIGLIATO
|
||||||
|
====================================
|
||||||
|
|
||||||
|
COMANDO - sequenza completa
|
||||||
|
```bash
|
||||||
|
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||||
|
helm repo update
|
||||||
|
|
||||||
|
helm upgrade --install blackbox-exporter prometheus-community/prometheus-blackbox-exporter \
|
||||||
|
--namespace monitoring \
|
||||||
|
--create-namespace \
|
||||||
|
-f blackbox-values.yaml
|
||||||
|
|
||||||
|
kubectl apply -f blackbox-probes.yaml
|
||||||
|
kubectl apply -f blackbox-ingress-probes.yaml
|
||||||
|
kubectl apply -f blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
FILE CONSIGLIATI DA VERSIONARE
|
||||||
|
```text
|
||||||
|
blackbox-values.yaml
|
||||||
|
blackbox-probes.yaml
|
||||||
|
blackbox-ingress-probes.yaml
|
||||||
|
blackbox-http-alerts.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
14. NOTE PER DEV, QA E PROD
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Per separare gli ambienti e semplificare dashboard e alert, usa Probe distinte:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dev-http-services-probe
|
||||||
|
qa-http-services-probe
|
||||||
|
prod-http-services-probe
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - ambiente dev
|
||||||
|
```promql
|
||||||
|
probe_success{job="dev-http-services-probe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
QUERY PROMQL - target prod falliti
|
||||||
|
```promql
|
||||||
|
probe_success{job="prod-http-services-probe"} == 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Per endpoint critici in produzione, valuta:
|
||||||
|
- interval piu' basso, ad esempio 15s o 30s;
|
||||||
|
- durata for degli alert tra 1m e 5m in base alla criticita';
|
||||||
|
- dashboard Grafana con stato, status code e latenza per target.
|
||||||
@@ -0,0 +1,553 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: <namespace>-<env>-<endpoint>-probe
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: <namespace>-<env>-<endpoint>-probe
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_2xx
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- https://<endpoint>
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: <namespace>-<env>-<endpoint>-dashboard
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
grafana_dashboard: "1"
|
||||||
|
data:
|
||||||
|
<namespace>-<env>-<endpoint>-dashboard.json: |
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 1,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Services UP",
|
||||||
|
"id": 1,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "sum(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Services DOWN",
|
||||||
|
"id": 2,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "count(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}) - sum(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Availability 24h",
|
||||||
|
"id": 3,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 12,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg(avg_over_time(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}[24h])) * 100"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "orange",
|
||||||
|
"value": 99
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": 99.9
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "area"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Avg Latency",
|
||||||
|
"id": 4,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 18,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg(probe_duration_seconds{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}) * 1000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "HTTP Services Status",
|
||||||
|
"id": 5,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "HTTP Status Code",
|
||||||
|
"id": 6,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_http_status_code{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "HTTP Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "HTTP Response Time",
|
||||||
|
"id": 7,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 13
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_duration_seconds{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"} * 1000",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "Currently DOWN",
|
||||||
|
"id": 8,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 22
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"} == 0",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "Availability 24h",
|
||||||
|
"id": 9,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 22
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg_over_time(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}[24h]) * 100",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"decimals": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "P95 Latency - 1h",
|
||||||
|
"id": 10,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 31
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "quantile_over_time(0.95, probe_duration_seconds{job=\"<namespace>-<env>-<endpoint>-probe\",instance=~\"$instance\"}[1h]) * 1000",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "30s",
|
||||||
|
"schemaVersion": 41,
|
||||||
|
"tags": [
|
||||||
|
"blackbox",
|
||||||
|
"http",
|
||||||
|
"monitoring"
|
||||||
|
],
|
||||||
|
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "instance",
|
||||||
|
"label": "Service",
|
||||||
|
"type": "query",
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"definition": "label_values(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\"}, instance)",
|
||||||
|
"query": {
|
||||||
|
"query": "label_values(probe_success{job=\"<namespace>-<env>-<endpoint>-probe\"}, instance)",
|
||||||
|
"refId": "StandardVariableQuery"
|
||||||
|
},
|
||||||
|
"includeAll": true,
|
||||||
|
"multi": true,
|
||||||
|
"allValue": ".*",
|
||||||
|
"refresh": 1,
|
||||||
|
"sort": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-24h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "<namespace>-<env>-<endpoint>-dashboard",
|
||||||
|
"uid": "<namespace>-<env>-<endpoint>-dashboard",
|
||||||
|
"version": 1,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,553 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: Probe
|
||||||
|
metadata:
|
||||||
|
name: <my-http-services-probe>
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
jobName: <my-http-services-probe>
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 15s
|
||||||
|
module: http_k8s_health
|
||||||
|
prober:
|
||||||
|
url: blackbox-exporter.monitoring.svc.cluster.local:9115
|
||||||
|
scheme: http
|
||||||
|
path: /probe
|
||||||
|
targets:
|
||||||
|
staticConfig:
|
||||||
|
static:
|
||||||
|
- http://<my-service>.<my-namespace>.svc.cluster.local:<my-port>/health
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: <my-http-services-dashboard>
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
grafana_dashboard: "1"
|
||||||
|
data:
|
||||||
|
<my-http-services-dashboard>.json: |
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 1,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Services UP",
|
||||||
|
"id": 1,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "sum(probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Services DOWN",
|
||||||
|
"id": 2,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "count(probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"}) - sum(probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Availability 24h",
|
||||||
|
"id": 3,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 12,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg(avg_over_time(probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"}[24h])) * 100"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "orange",
|
||||||
|
"value": 99
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": 99.9
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "area"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Avg Latency",
|
||||||
|
"id": 4,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 6,
|
||||||
|
"x": 18,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg(probe_duration_seconds{job=\"<my-http-services-probe>\",instance=~\"$instance\"}) * 1000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "auto",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "HTTP Services Status",
|
||||||
|
"id": 5,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"}",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "HTTP Status Code",
|
||||||
|
"id": 6,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 5
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_http_status_code{job=\"<my-http-services-probe>\",instance=~\"$instance\"}",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "short",
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "HTTP Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "HTTP Response Time",
|
||||||
|
"id": 7,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 13
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_duration_seconds{job=\"<my-http-services-probe>\",instance=~\"$instance\"} * 1000",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"title": "Currently DOWN",
|
||||||
|
"id": 8,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 22
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"} == 0",
|
||||||
|
"instant": true,
|
||||||
|
"format": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true
|
||||||
|
},
|
||||||
|
"renameByName": {
|
||||||
|
"Value": "Status",
|
||||||
|
"instance": "Service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"cellHeight": "sm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "Availability 24h",
|
||||||
|
"id": 9,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 22
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "avg_over_time(probe_success{job=\"<my-http-services-probe>\",instance=~\"$instance\"}[24h]) * 100",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"decimals": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries",
|
||||||
|
"title": "P95 Latency - 1h",
|
||||||
|
"id": 10,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 31
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"expr": "quantile_over_time(0.95, probe_duration_seconds{job=\"<my-http-services-probe>\",instance=~\"$instance\"}[1h]) * 1000",
|
||||||
|
"legendFormat": "{{instance}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "ms",
|
||||||
|
"decimals": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "30s",
|
||||||
|
"schemaVersion": 41,
|
||||||
|
"tags": [
|
||||||
|
"blackbox",
|
||||||
|
"http",
|
||||||
|
"monitoring"
|
||||||
|
],
|
||||||
|
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "instance",
|
||||||
|
"label": "Service",
|
||||||
|
"type": "query",
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"definition": "label_values(probe_success{job=\"<my-http-services-probe>\"}, instance)",
|
||||||
|
"query": {
|
||||||
|
"query": "label_values(probe_success{job=\"<my-http-services-probe>\"}, instance)",
|
||||||
|
"refId": "StandardVariableQuery"
|
||||||
|
},
|
||||||
|
"includeAll": true,
|
||||||
|
"multi": true,
|
||||||
|
"allValue": ".*",
|
||||||
|
"refresh": 1,
|
||||||
|
"sort": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-24h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "<my-http-services-dashboard>",
|
||||||
|
"uid": "<my-http-services-dashboard>",
|
||||||
|
"version": 1,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
@@ -2,6 +2,13 @@
|
|||||||
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
|
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
|
||||||
helm repo update
|
helm repo update
|
||||||
|
|
||||||
|
helm pull sonarqube/sonarqube --version 2026.1.0
|
||||||
|
|
||||||
|
helm registry login harbor.italiadatacenter.com -u admin
|
||||||
|
(pwd: KAYQE1QA7uwUZ8uI)
|
||||||
|
|
||||||
|
helm push sonarqube-2026.1.0.tgz oci://harbor.italiadatacenter.com/italiadatacenter
|
||||||
|
|
||||||
########### creazione ns e secret db ################
|
########### creazione ns e secret db ################
|
||||||
kubectl create namespace sonarqube
|
kubectl create namespace sonarqube
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# gitops-repo - esempio completo (3 namespace, Fleet su RKE2)
|
||||||
|
|
||||||
|
Repo di esempio pronto da usare come base: GitOps limitato a
|
||||||
|
namespace-A, namespace-B, namespace-C, con Fleet come motore di sync.
|
||||||
|
|
||||||
|
## Struttura
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── bootstrap/ <- file legacy Argo CD (non usati con Fleet)
|
||||||
|
│ ├── 00-namespace.yaml
|
||||||
|
│ ├── 01-appproject.yaml
|
||||||
|
│ └── 02-root.yaml
|
||||||
|
│
|
||||||
|
└── clusters/
|
||||||
|
└── idc/ <- nome cluster/repository scope attuale
|
||||||
|
├── namespace-A/
|
||||||
|
│ ├── application.yaml <- da migrare a Fleet GitRepo
|
||||||
|
│ └── manifests/
|
||||||
|
│ └── deployment.yaml
|
||||||
|
├── namespace-B/
|
||||||
|
│ ├── application.yaml <- da migrare a Fleet GitRepo
|
||||||
|
│ └── manifests/
|
||||||
|
│ └── deployment.yaml
|
||||||
|
└── namespace-C/
|
||||||
|
├── application.yaml <- gia convertito a Fleet GitRepo
|
||||||
|
└── manifests/
|
||||||
|
└── deployment.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cosa applichi a mano con Fleet
|
||||||
|
|
||||||
|
- Applichi a mano i manifest Fleet di tipo GitRepo (uno per namespace o uno aggregato).
|
||||||
|
- I file in clusters/idc/namespace-*/manifests vengono sincronizzati automaticamente da Fleet.
|
||||||
|
- I file in bootstrap sono legacy Argo CD: con Fleet installato, non sono necessari.
|
||||||
|
|
||||||
|
## Bootstrap Fleet - passo per passo
|
||||||
|
|
||||||
|
### 1. Verifica Fleet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n cattle-fleet-system get pods
|
||||||
|
kubectl get crd gitrepos.fleet.cattle.io
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Applica il GitRepo
|
||||||
|
|
||||||
|
Esempio con namespace-C:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f clusters/idc/namespace-C/application.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verifica stato Fleet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fleet-local get gitrepo
|
||||||
|
kubectl -n cattle-fleet-system get bundles
|
||||||
|
kubectl -n cattle-fleet-system get bundledeployments
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repo privato GitHub
|
||||||
|
|
||||||
|
Se il repo e privato, configura le credenziali per Fleet (Secret nel namespace Fleet usato, tipicamente fleet-local o fleet-default).
|
||||||
|
|
||||||
|
## Prima di usare questo repo
|
||||||
|
|
||||||
|
Sostituisci ovunque compare:
|
||||||
|
- <tua-org> -> org/utente reale del tuo repo Git
|
||||||
|
- i deployment di esempio -> i tuoi manifest reali
|
||||||
|
|
||||||
|
## Migrazione consigliata (A e B)
|
||||||
|
|
||||||
|
Attualmente solo namespace-C e gia in formato Fleet.
|
||||||
|
Per allineare tutto:
|
||||||
|
|
||||||
|
1. Converti clusters/idc/namespace-A/application.yaml in GitRepo Fleet.
|
||||||
|
2. Converti clusters/idc/namespace-B/application.yaml in GitRepo Fleet.
|
||||||
|
3. Applica i due manifest e verifica bundle/bundledeployments.
|
||||||
|
|
||||||
|
## Estendere a un quarto namespace in futuro
|
||||||
|
|
||||||
|
1. Crea clusters/idc/namespace-D/manifests con i tuoi YAML.
|
||||||
|
2. Crea clusters/idc/namespace-D/application.yaml in formato Fleet GitRepo.
|
||||||
|
3. Applica il manifest e verifica la generazione dei bundle.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: argocd
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# AppProject con perimetro ristretto a namespace-A, namespace-B,
|
||||||
|
# namespace-C. Qualunque Application che referenzi questo project e
|
||||||
|
# provi a scrivere in un namespace diverso da questi (+ argocd, per le
|
||||||
|
# risorse interne) viene rifiutata da Argo CD stesso.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: AppProject
|
||||||
|
metadata:
|
||||||
|
name: gitops-3ns
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
description: "GitOps limitato a namespace-A, namespace-B, namespace-C"
|
||||||
|
|
||||||
|
sourceRepos:
|
||||||
|
- "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
|
||||||
|
destinations:
|
||||||
|
- namespace: argocd
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-A
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-B
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-C
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
|
||||||
|
clusterResourceWhitelist:
|
||||||
|
- group: ""
|
||||||
|
kind: Namespace
|
||||||
|
|
||||||
|
namespaceResourceWhitelist:
|
||||||
|
- group: "*"
|
||||||
|
kind: "*"
|
||||||
|
|
||||||
|
orphanedResources:
|
||||||
|
warn: true
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# Root "app of apps": punta a gitops/clusters/idc/ nel repo. Grazie a
|
||||||
|
# directory.recurse=true, scopre automaticamente ogni application.yaml
|
||||||
|
# trovato dentro namespace-A/, namespace-B/, namespace-C/ e li applica
|
||||||
|
# come proprie Application figlie.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: root-3ns
|
||||||
|
namespace: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc
|
||||||
|
directory:
|
||||||
|
recurse: true
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: argocd
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
|
retry:
|
||||||
|
limit: 5
|
||||||
|
backoff:
|
||||||
|
duration: 10s
|
||||||
|
factor: 2
|
||||||
|
maxDuration: 3m
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-a
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-A/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-A
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# Esempio di manifest reale — sostituiscilo con le tue risorse
|
||||||
|
# effettive. Ogni file .yaml in questa cartella viene applicato
|
||||||
|
# automaticamente da Argo CD (Application "namespace-a").
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-a
|
||||||
|
namespace: namespace-A
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-a
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-a
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-a
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-a
|
||||||
|
namespace: namespace-A
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-a
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-b
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-B/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-B
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-b
|
||||||
|
namespace: namespace-B
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-b
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-b
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-b
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-b
|
||||||
|
namespace: namespace-B
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-b
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: fleet.cattle.io/v1alpha1
|
||||||
|
kind: GitRepo
|
||||||
|
metadata:
|
||||||
|
name: namespace-c
|
||||||
|
namespace: fleet-local
|
||||||
|
spec:
|
||||||
|
repo: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
branch: main
|
||||||
|
paths:
|
||||||
|
- gitops/clusters/idc/namespace-C/manifests
|
||||||
|
targets:
|
||||||
|
- clusterName: local
|
||||||
|
namespace: namespace-C
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-c
|
||||||
|
namespace: namespace-C
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-c
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-c
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-c
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-c
|
||||||
|
namespace: namespace-C
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-c
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =====================================================================
|
||||||
|
# extract-manifests.sh
|
||||||
|
#
|
||||||
|
# Estrae tutte le risorse namespaced dai namespace indicati, le ripulisce
|
||||||
|
# con kubectl-neat (rimuove resourceVersion, uid, status, managedFields,
|
||||||
|
# creationTimestamp, ecc.) e le salva organizzate per namespace/kind,
|
||||||
|
# pronte per essere committate in un repo GitOps.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./extract-manifests.sh [opzioni] <namespace1> <namespace2> ...
|
||||||
|
# ./extract-manifests.sh [opzioni] --namespaces-file namespaces.txt
|
||||||
|
#
|
||||||
|
# Opzioni:
|
||||||
|
# -o, --output <dir> Directory di output (default: ./export)
|
||||||
|
# -s, --include-secrets Include anche i Secret (in CHIARO, base64 non
|
||||||
|
# cifrato — vedi warning qui sotto). Di default
|
||||||
|
# i Secret vengono SALTATI per sicurezza.
|
||||||
|
# -f, --namespaces-file File con un namespace per riga. Righe vuote e
|
||||||
|
# righe che iniziano con # vengono ignorate.
|
||||||
|
# -k, --kinds <lista> Lista custom di kind separati da virgola,
|
||||||
|
# al posto della discovery automatica
|
||||||
|
# (es. "deployment,service,httproute")
|
||||||
|
# -h, --help Mostra questo help
|
||||||
|
#
|
||||||
|
# Esempi:
|
||||||
|
# ./extract-manifests.sh monitoring minio idcidp-dev
|
||||||
|
# ./extract-manifests.sh -o ./gitops-repo/imported -s monitoring
|
||||||
|
# ./extract-manifests.sh -k "httproute,gateway" nginx-gateway
|
||||||
|
# ./extract-manifests.sh -f ./namespaces.txt -o ./gitops-repo/imported
|
||||||
|
#
|
||||||
|
# Prerequisiti:
|
||||||
|
# - kubectl configurato e puntato al cluster corretto
|
||||||
|
# - kubectl-neat installato (kubectl krew install neat)
|
||||||
|
# https://github.com/itaysk/kubectl-neat
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Default
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
OUTPUT_DIR="./export"
|
||||||
|
INCLUDE_SECRETS="false"
|
||||||
|
CUSTOM_KINDS=""
|
||||||
|
NAMESPACES_FILE=""
|
||||||
|
|
||||||
|
# Kind che non ha senso portare in un repo GitOps: generati/gestiti
|
||||||
|
# automaticamente da controller, non sono mai "desired state" da
|
||||||
|
# dichiarare a mano.
|
||||||
|
EXCLUDED_KINDS="events pods replicasets endpoints endpointslices controllerrevisions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
grep '^#' "$0" | sed -e 's/^#//' -e 's/^ //'
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
load_namespaces_from_file() {
|
||||||
|
local file_path="$1"
|
||||||
|
|
||||||
|
if [[ ! -f "$file_path" ]]; then
|
||||||
|
echo "Errore: file namespace non trovato: $file_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
line="${line%$'\r'}"
|
||||||
|
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
|
||||||
|
line="${line#"${line%%[![:space:]]*}"}"
|
||||||
|
line="${line%"${line##*[![:space:]]}"}"
|
||||||
|
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
|
||||||
|
NAMESPACES+=("$line")
|
||||||
|
done < "$file_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Parsing argomenti
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
NAMESPACES=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-o|--output)
|
||||||
|
OUTPUT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--include-secrets)
|
||||||
|
INCLUDE_SECRETS="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-f|--namespaces-file)
|
||||||
|
NAMESPACES_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-k|--kinds)
|
||||||
|
CUSTOM_KINDS="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Opzione sconosciuta: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
NAMESPACES+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "$NAMESPACES_FILE" ]]; then
|
||||||
|
load_namespaces_from_file "$NAMESPACES_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#NAMESPACES[@]} -eq 0 ]]; then
|
||||||
|
echo "Errore: specifica almeno un namespace o usa --namespaces-file." >&2
|
||||||
|
echo "Uso: $0 [opzioni] <namespace1> <namespace2> ..." >&2
|
||||||
|
echo " o: $0 [opzioni] --namespaces-file namespaces.txt" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Prerequisiti
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "Errore: kubectl non trovato nel PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! kubectl neat --help >/dev/null 2>&1; then
|
||||||
|
echo "Errore: plugin kubectl-neat non trovato." >&2
|
||||||
|
echo "Installa con: kubectl krew install neat" >&2
|
||||||
|
echo "(krew: https://krew.sigs.k8s.io/docs/user-guide/setup/install/)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
echo "==> Output directory: $OUTPUT_DIR"
|
||||||
|
echo "==> Namespace da processare: ${NAMESPACES[*]}"
|
||||||
|
echo "==> Include Secret: $INCLUDE_SECRETS"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ "$INCLUDE_SECRETS" == "true" ]]; then
|
||||||
|
echo "########################################################"
|
||||||
|
echo "# ATTENZIONE: i Secret verranno esportati in CHIARO #"
|
||||||
|
echo "# (base64, NON cifrato). Non committarli in Git così #"
|
||||||
|
echo "# come sono. Usa Sealed Secrets, SOPS o External Secrets #"
|
||||||
|
echo "# Operator prima di aggiungerli al repo. #"
|
||||||
|
echo "########################################################"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Determina i kind namespaced da processare
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
get_kinds() {
|
||||||
|
if [[ -n "$CUSTOM_KINDS" ]]; then
|
||||||
|
echo "$CUSTOM_KINDS" | tr ',' '\n'
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Discovery automatica: tutti i kind namespaced supportati dal cluster
|
||||||
|
# (copre anche le CRD installate, es. httproute, podmonitor, cluster
|
||||||
|
# CNPG, ecc.), escludendo quelli in EXCLUDED_KINDS.
|
||||||
|
kubectl api-resources --namespaced=true --verbs=list -o name 2>/dev/null \
|
||||||
|
| cut -d. -f1 \
|
||||||
|
| sort -u \
|
||||||
|
| while read -r kind; do
|
||||||
|
skip="false"
|
||||||
|
for excl in $EXCLUDED_KINDS; do
|
||||||
|
[[ "$kind" == "$excl" ]] && skip="true" && break
|
||||||
|
done
|
||||||
|
[[ "$skip" == "false" ]] && echo "$kind"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
KINDS=$(get_kinds)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Estrazione
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
TOTAL_EXPORTED=0
|
||||||
|
TOTAL_EMPTY=0
|
||||||
|
TOTAL_ERRORS=0
|
||||||
|
|
||||||
|
for ns in "${NAMESPACES[@]}"; do
|
||||||
|
echo "=== Namespace: $ns ==="
|
||||||
|
|
||||||
|
if ! kubectl get namespace "$ns" >/dev/null 2>&1; then
|
||||||
|
echo " ! Namespace '$ns' non trovato, salto." >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
ns_dir="${OUTPUT_DIR}/${ns}"
|
||||||
|
mkdir -p "$ns_dir"
|
||||||
|
|
||||||
|
while IFS= read -r kind; do
|
||||||
|
[[ -z "$kind" ]] && continue
|
||||||
|
|
||||||
|
# Salta i secret a meno che non richiesti esplicitamente
|
||||||
|
if [[ "$kind" == "secrets" || "$kind" == "secret" ]] && [[ "$INCLUDE_SECRETS" != "true" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Conta quante risorse di questo kind esistono nel namespace, per
|
||||||
|
# evitare di scrivere file vuoti/inutili
|
||||||
|
count=$(kubectl get "$kind" -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
if [[ "$count" -eq 0 ]]; then
|
||||||
|
TOTAL_EMPTY=$((TOTAL_EMPTY + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
out_file="${ns_dir}/${kind}.yaml"
|
||||||
|
|
||||||
|
if kubectl get "$kind" -n "$ns" -o yaml 2>/dev/null | kubectl neat > "$out_file" 2>/dev/null; then
|
||||||
|
# kubectl neat su una List vuota/malformata può comunque produrre
|
||||||
|
# un file quasi-vuoto: verifichiamo che contenga davvero "kind:"
|
||||||
|
if grep -q "^kind:" "$out_file" 2>/dev/null || grep -q "^items:" "$out_file" 2>/dev/null; then
|
||||||
|
echo " + ${kind} (${count})"
|
||||||
|
TOTAL_EXPORTED=$((TOTAL_EXPORTED + 1))
|
||||||
|
else
|
||||||
|
rm -f "$out_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ! Errore esportando ${kind}" >&2
|
||||||
|
rm -f "$out_file"
|
||||||
|
TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done <<< "$KINDS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== Riepilogo ==="
|
||||||
|
echo "Risorse esportate: $TOTAL_EXPORTED"
|
||||||
|
echo "Kind vuoti/saltati: $TOTAL_EMPTY"
|
||||||
|
echo "Errori: $TOTAL_ERRORS"
|
||||||
|
echo ""
|
||||||
|
echo "Output in: $OUTPUT_DIR"
|
||||||
|
echo ""
|
||||||
|
echo "Prossimi passi consigliati:"
|
||||||
|
echo " 1. Rivedi manualmente ogni file: alcuni campi (es. clusterIP,"
|
||||||
|
echo " nodePort, annotazioni iniettate da controller/webhook) vanno"
|
||||||
|
echo " rimossi a mano perché non fanno parte del 'desired state'."
|
||||||
|
echo " 2. Se hai esportato Secret, cifrali (Sealed Secrets / SOPS) prima"
|
||||||
|
echo " di committarli."
|
||||||
|
echo " 3. Riorganizza i file nella struttura del repo GitOps"
|
||||||
|
echo " (infrastructure/ vs apps/, vedi README del repo)."
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
OUTPUT_DIR="./generated-helmops"
|
||||||
|
API_VERSION="fleet.cattle.io/v1alpha1"
|
||||||
|
RESOURCE_KIND="HelmOp"
|
||||||
|
VALUES_ARGS=()
|
||||||
|
WORKSPACE_NAMESPACE="fleet-local"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./generate-fleet-helmops-from-helm.sh [options]
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Legge le release presenti con `helm list -A`, recupera metadata e values
|
||||||
|
per ogni release e genera un file YAML per release in formato HelmOp-style.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-o, --output-dir <dir> Directory di output (default: ./generated-helmops)
|
||||||
|
-w, --workspace-namespace <ns>
|
||||||
|
Namespace dove creare la risorsa HelmOp
|
||||||
|
(default: fleet-local)
|
||||||
|
--api-version <value> apiVersion del manifest generato
|
||||||
|
(default: fleet.cattle.io/v1alpha1)
|
||||||
|
--kind <value> kind del manifest generato (default: HelmOp)
|
||||||
|
-a, --all-values Usa `helm get values -a -o yaml`
|
||||||
|
-h, --help Mostra questo help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
./generate-fleet-helmops-from-helm.sh
|
||||||
|
./generate-fleet-helmops-from-helm.sh -o ./clusters/idc/imported
|
||||||
|
./generate-fleet-helmops-from-helm.sh -w fleet-default
|
||||||
|
./generate-fleet-helmops-from-helm.sh --kind HelmChart --api-version helm.cattle.io/v1
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "Errore: comando richiesto non trovato: $cmd" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
local value="$1"
|
||||||
|
value="${value#"${value%%[![:space:]]*}"}"
|
||||||
|
value="${value%"${value##*[![:space:]]}"}"
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_file_name() {
|
||||||
|
printf '%s' "$1" | tr '/\\:' '---'
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_yaml_scalar() {
|
||||||
|
local key="$1"
|
||||||
|
local content="$2"
|
||||||
|
|
||||||
|
printf '%s\n' "$content" \
|
||||||
|
| sed -n "s/^[[:space:]]*${key}:[[:space:]]*//p" \
|
||||||
|
| head -n 1 \
|
||||||
|
| sed 's/^"//; s/"$//; s/^\x27//; s/\x27$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_first_source() {
|
||||||
|
local content="$1"
|
||||||
|
|
||||||
|
awk '
|
||||||
|
/^sources:/ { in_sources=1; next }
|
||||||
|
in_sources && /^[^[:space:]-]/ { exit }
|
||||||
|
in_sources && /^[[:space:]]*-[[:space:]]*/ {
|
||||||
|
sub(/^[[:space:]]*-[[:space:]]*/, "")
|
||||||
|
print
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' <<< "$content"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_chart_name_from_ref() {
|
||||||
|
local chart_ref="$1"
|
||||||
|
|
||||||
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
||||||
|
printf '%s' "${BASH_REMATCH[1]}"
|
||||||
|
else
|
||||||
|
printf '%s' "$chart_ref"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_chart_version_from_ref() {
|
||||||
|
local chart_ref="$1"
|
||||||
|
|
||||||
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
||||||
|
printf '%s' "${BASH_REMATCH[2]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
find_repo_url_from_local_cache() {
|
||||||
|
local chart_name="$1"
|
||||||
|
local chart_version="$2"
|
||||||
|
local search_json=""
|
||||||
|
local repo_alias=""
|
||||||
|
|
||||||
|
[[ -z "$chart_name" ]] && return 0
|
||||||
|
|
||||||
|
search_json="$(helm search repo "$chart_name" --versions -o json 2>/dev/null || true)"
|
||||||
|
[[ -z "$search_json" || "$search_json" == "[]" ]] && return 0
|
||||||
|
|
||||||
|
if [[ -n "$chart_version" ]]; then
|
||||||
|
repo_alias="$(jq -r --arg chart "$chart_name" --arg version "$chart_version" '
|
||||||
|
map(select((.name | split("/") | last) == $chart and .version == $version))
|
||||||
|
| .[0].name // empty
|
||||||
|
' <<< "$search_json")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_alias" ]]; then
|
||||||
|
repo_alias="$(jq -r --arg chart "$chart_name" '
|
||||||
|
map(select((.name | split("/") | last) == $chart))
|
||||||
|
| .[0].name // empty
|
||||||
|
' <<< "$search_json")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$repo_alias" ]] && return 0
|
||||||
|
|
||||||
|
repo_alias="${repo_alias%%/*}"
|
||||||
|
|
||||||
|
helm repo list -o json 2>/dev/null \
|
||||||
|
| jq -r --arg alias "$repo_alias" 'map(select(.name == $alias)) | .[0].url // empty'
|
||||||
|
}
|
||||||
|
|
||||||
|
indent_file() {
|
||||||
|
local file_path="$1"
|
||||||
|
sed 's/^/ /' "$file_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-o|--output-dir)
|
||||||
|
OUTPUT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-w|--workspace-namespace)
|
||||||
|
WORKSPACE_NAMESPACE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--api-version)
|
||||||
|
API_VERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--kind)
|
||||||
|
RESOURCE_KIND="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-a|--all-values)
|
||||||
|
VALUES_ARGS=(-a)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Opzione sconosciuta: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
require_cmd helm
|
||||||
|
require_cmd jq
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
releases_json="$(helm list -A -o json)"
|
||||||
|
release_count="$(jq 'length' <<< "$releases_json")"
|
||||||
|
|
||||||
|
if [[ "$release_count" -eq 0 ]]; then
|
||||||
|
echo "Nessuna release Helm trovata." >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Release trovate: $release_count"
|
||||||
|
echo "==> Directory output: $OUTPUT_DIR"
|
||||||
|
|
||||||
|
generated_count=0
|
||||||
|
warning_count=0
|
||||||
|
|
||||||
|
while IFS= read -r release; do
|
||||||
|
name="$(jq -r '.name' <<< "$release")"
|
||||||
|
namespace="$(jq -r '.namespace' <<< "$release")"
|
||||||
|
chart_ref="$(jq -r '.chart // ""' <<< "$release")"
|
||||||
|
|
||||||
|
metadata_yaml="$(helm get metadata "$name" -n "$namespace" -o yaml 2>/dev/null || true)"
|
||||||
|
if [[ -z "$metadata_yaml" ]]; then
|
||||||
|
echo "! Impossibile leggere metadata per ${namespace}/${name}, salto." >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repo "$metadata_yaml")")"
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repository "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repoURL "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_first_source "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chart_name="$(trim "$(extract_yaml_scalar chart "$metadata_yaml")")"
|
||||||
|
chart_version="$(trim "$(extract_yaml_scalar version "$metadata_yaml")")"
|
||||||
|
|
||||||
|
if [[ -z "$chart_name" ]]; then
|
||||||
|
chart_name="$(extract_chart_name_from_ref "$chart_ref")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$chart_version" ]]; then
|
||||||
|
chart_version="$(extract_chart_version_from_ref "$chart_ref")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(find_repo_url_from_local_cache "$chart_name" "$chart_version")")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="REPO_URL_NOT_FOUND"
|
||||||
|
echo "! Repo URL non trovato in metadata o cache locale per ${namespace}/${name}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$chart_name" ]]; then
|
||||||
|
chart_name="CHART_NAME_NOT_FOUND"
|
||||||
|
echo "! Chart name non trovato per ${namespace}/${name}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
values_file="$(mktemp)"
|
||||||
|
if ! helm get values "$name" -n "$namespace" "${VALUES_ARGS[@]}" -o yaml > "$values_file" 2>/dev/null; then
|
||||||
|
printf '{}\n' > "$values_file"
|
||||||
|
echo "! Values non disponibili per ${namespace}/${name}, uso {}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -s "$values_file" ]]; then
|
||||||
|
printf '{}\n' > "$values_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
values_compact="$(tr -d '[:space:]' < "$values_file")"
|
||||||
|
|
||||||
|
ns_dir="${OUTPUT_DIR}/${namespace}"
|
||||||
|
mkdir -p "$ns_dir"
|
||||||
|
|
||||||
|
safe_name="$(safe_file_name "$name")"
|
||||||
|
out_file="${ns_dir}/${safe_name}-helmop.yaml"
|
||||||
|
|
||||||
|
cat > "$out_file" <<EOF
|
||||||
|
apiVersion: ${API_VERSION}
|
||||||
|
kind: ${RESOURCE_KIND}
|
||||||
|
metadata:
|
||||||
|
name: ${safe_name}
|
||||||
|
namespace: ${WORKSPACE_NAMESPACE}
|
||||||
|
spec:
|
||||||
|
namespace: ${namespace}
|
||||||
|
helm:
|
||||||
|
releaseName: ${name}
|
||||||
|
repo: ${repo_url}
|
||||||
|
chart: ${chart_name}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [[ -n "$chart_version" ]]; then
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
version: ${chart_version}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$values_compact" == "{}" ]]; then
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
values: {}
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
values:
|
||||||
|
$(indent_file "$values_file")
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$values_file"
|
||||||
|
|
||||||
|
echo "+ Generato ${out_file} da ${namespace}/${name}"
|
||||||
|
generated_count=$((generated_count + 1))
|
||||||
|
done < <(jq -c '.[]' <<< "$releases_json")
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Riepilogo ==="
|
||||||
|
echo "File generati: $generated_count"
|
||||||
|
echo "Warning: $warning_count"
|
||||||
|
echo "Output: $OUTPUT_DIR"
|
||||||
|
echo "Workspace namespace: $WORKSPACE_NAMESPACE"
|
||||||
|
echo ""
|
||||||
|
echo "Nota: il repo URL viene letto da 'helm get metadata' e, se assente,"
|
||||||
|
echo " viene cercato nella cache locale di 'helm repo list/search repo'."
|
||||||
|
echo "Se vedi REPO_URL_NOT_FOUND, completa il campo repo manualmente."
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Aggiunge un hostname a spec.template.spec.hostAliases del Deployment cert-manager.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./add-cert-manager-hostalias.sh <hostname>
|
||||||
|
#
|
||||||
|
# Esempio:
|
||||||
|
# ./add-cert-manager-hostalias.sh main-gateway-nginx.nginx-gateway.svc.cluster.local
|
||||||
|
# ./add-cert-manager-hostalias.sh api.internal
|
||||||
|
|
||||||
|
DEPLOYMENT_NAME="cert-manager"
|
||||||
|
DEPLOYMENT_NS="cert-manager"
|
||||||
|
TARGET_IP="10.43.37.118"
|
||||||
|
HOSTNAME_VAL="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$HOSTNAME_VAL" ]]; then
|
||||||
|
echo "Uso: $0 <hostname>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "Errore: kubectl non trovato nel PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
echo "Errore: jq non trovato nel PATH" >&2
|
||||||
|
echo "Installa jq e riprova." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Idempotenza: controlla solo il blocco hostAliases associato a TARGET_IP.
|
||||||
|
EXISTING_HOSTNAMES="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o jsonpath="{.spec.template.spec.hostAliases[?(@.ip=='${TARGET_IP}')].hostnames[*]}" 2>/dev/null || true)"
|
||||||
|
if echo " $EXISTING_HOSTNAMES " | grep -Fq " $HOSTNAME_VAL "; then
|
||||||
|
echo "Hostname '$HOSTNAME_VAL' gia presente per IP ${TARGET_IP} in ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}. Nessuna modifica."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_JSON="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o json)"
|
||||||
|
|
||||||
|
UPDATED_HOST_ALIASES="$({
|
||||||
|
echo "$DEPLOY_JSON" | jq -c --arg ip "$TARGET_IP" --arg hostname "$HOSTNAME_VAL" '
|
||||||
|
(.spec.template.spec.hostAliases //= [])
|
||||||
|
| if any(.spec.template.spec.hostAliases[]?; .ip == $ip) then
|
||||||
|
.spec.template.spec.hostAliases |= map(
|
||||||
|
if .ip == $ip then
|
||||||
|
if ((.hostnames // []) | index($hostname)) then
|
||||||
|
.
|
||||||
|
else
|
||||||
|
.hostnames = ((.hostnames // []) + [$hostname])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
.
|
||||||
|
end
|
||||||
|
)
|
||||||
|
else
|
||||||
|
.spec.template.spec.hostAliases += [{"ip": $ip, "hostnames": [$hostname]}]
|
||||||
|
end
|
||||||
|
| .spec.template.spec.hostAliases
|
||||||
|
'
|
||||||
|
} )"
|
||||||
|
|
||||||
|
PATCH_PAYLOAD="$(jq -cn --argjson hostAliases "$UPDATED_HOST_ALIASES" '{spec:{template:{spec:{hostAliases:$hostAliases}}}}')"
|
||||||
|
|
||||||
|
kubectl patch deployment "$DEPLOYMENT_NAME" \
|
||||||
|
-n "$DEPLOYMENT_NS" \
|
||||||
|
--type=merge \
|
||||||
|
-p "$PATCH_PAYLOAD" >/dev/null
|
||||||
|
|
||||||
|
echo "Hostname aggiunto con successo."
|
||||||
|
echo " Deployment: ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}"
|
||||||
|
echo " IP : ${TARGET_IP}"
|
||||||
|
echo " Hostname : ${HOSTNAME_VAL}"
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Aggiunge un hostname a spec.template.spec.hostAliases del Deployment blackbox.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./add-hostalias.sh <hostname> <deployment_name> <deployment_namespace>
|
||||||
|
#
|
||||||
|
# Esempio:
|
||||||
|
# ./add-hostalias.sh idcidcp.pigreco66.it cert-manager cert-manager
|
||||||
|
#
|
||||||
|
|
||||||
|
DEPLOYMENT_NAME="${2:-}"
|
||||||
|
DEPLOYMENT_NS="${3:-}"
|
||||||
|
TARGET_IP="10.43.37.118"
|
||||||
|
HOSTNAME_VAL="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$HOSTNAME_VAL" ]]; then
|
||||||
|
echo "Uso: $0 <hostname>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "Errore: kubectl non trovato nel PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
echo "Errore: jq non trovato nel PATH" >&2
|
||||||
|
echo "Installa jq e riprova." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Idempotenza: controlla solo il blocco hostAliases associato a TARGET_IP.
|
||||||
|
EXISTING_HOSTNAMES="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o jsonpath="{.spec.template.spec.hostAliases[?(@.ip=='${TARGET_IP}')].hostnames[*]}" 2>/dev/null || true)"
|
||||||
|
if echo " $EXISTING_HOSTNAMES " | grep -Fq " $HOSTNAME_VAL "; then
|
||||||
|
echo "Hostname '$HOSTNAME_VAL' gia presente per IP ${TARGET_IP} in ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}. Nessuna modifica."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_JSON="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o json)"
|
||||||
|
|
||||||
|
UPDATED_HOST_ALIASES="$({
|
||||||
|
echo "$DEPLOY_JSON" | jq -c --arg ip "$TARGET_IP" --arg hostname "$HOSTNAME_VAL" '
|
||||||
|
(.spec.template.spec.hostAliases //= [])
|
||||||
|
| if any(.spec.template.spec.hostAliases[]?; .ip == $ip) then
|
||||||
|
.spec.template.spec.hostAliases |= map(
|
||||||
|
if .ip == $ip then
|
||||||
|
if ((.hostnames // []) | index($hostname)) then
|
||||||
|
.
|
||||||
|
else
|
||||||
|
.hostnames = ((.hostnames // []) + [$hostname])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
.
|
||||||
|
end
|
||||||
|
)
|
||||||
|
else
|
||||||
|
.spec.template.spec.hostAliases += [{"ip": $ip, "hostnames": [$hostname]}]
|
||||||
|
end
|
||||||
|
| .spec.template.spec.hostAliases
|
||||||
|
'
|
||||||
|
} )"
|
||||||
|
|
||||||
|
PATCH_PAYLOAD="$(jq -cn --argjson hostAliases "$UPDATED_HOST_ALIASES" '{spec:{template:{spec:{hostAliases:$hostAliases}}}}')"
|
||||||
|
|
||||||
|
kubectl patch deployment "$DEPLOYMENT_NAME" \
|
||||||
|
-n "$DEPLOYMENT_NS" \
|
||||||
|
--type=merge \
|
||||||
|
-p "$PATCH_PAYLOAD" >/dev/null
|
||||||
|
|
||||||
|
echo "Hostname aggiunto con successo."
|
||||||
|
echo " Deployment: ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}"
|
||||||
|
echo " IP : ${TARGET_IP}"
|
||||||
|
echo " Hostname : ${HOSTNAME_VAL}"
|
||||||
@@ -35,6 +35,7 @@ fi
|
|||||||
# Per calcolare il token usa host pulito (senza schema e path)
|
# Per calcolare il token usa host pulito (senza schema e path)
|
||||||
host_for_token="${endpoint#*://}"
|
host_for_token="${endpoint#*://}"
|
||||||
host_for_token="${host_for_token%%/*}"
|
host_for_token="${host_for_token%%/*}"
|
||||||
|
host_no_port="${host_for_token%%:*}"
|
||||||
token="${host_for_token%%.*}"
|
token="${host_for_token%%.*}"
|
||||||
|
|
||||||
if [[ -z "$token" ]]; then
|
if [[ -z "$token" ]]; then
|
||||||
@@ -42,5 +43,20 @@ if [[ -z "$token" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Se l'hostname non e nel dominio *.italiadatacenter.com, aggiungilo anche a cert-manager hostAliases.
|
||||||
|
if [[ "$host_no_port" != *.italiadatacenter.com ]]; then
|
||||||
|
HOSTALIAS_SCRIPT="/root/work/pipeline/add-hostalias.sh"
|
||||||
|
if [[ -x "$HOSTALIAS_SCRIPT" ]]; then
|
||||||
|
"$HOSTALIAS_SCRIPT" "$host_no_port" "cert-manager" "cert-manager"
|
||||||
|
"$HOSTALIAS_SCRIPT" "$host_no_port" "blackbox-exporter" "monitoring"
|
||||||
|
elif [[ -f "$HOSTALIAS_SCRIPT" ]]; then
|
||||||
|
bash "$HOSTALIAS_SCRIPT" "$host_no_port" "cert-manager" "cert-manager"
|
||||||
|
bash "$HOSTALIAS_SCRIPT" "$host_no_port" "blackbox-exporter" "monitoring"
|
||||||
|
else
|
||||||
|
echo "Errore: script non trovato: $HOSTALIAS_SCRIPT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Output richiesto: <endpoint> https-<token> <token>-secret
|
# Output richiesto: <endpoint> https-<token> <token>-secret
|
||||||
/root/work/pipeline/add-listener.sh $endpoint https-$token $token-secret
|
/root/work/pipeline/add-listener.sh $endpoint https-$token $token-secret
|
||||||
|
|||||||
@@ -6,6 +6,19 @@ VALUES_DIR="env/$ENV"
|
|||||||
PROPERTIES_FILE="properties.env"
|
PROPERTIES_FILE="properties.env"
|
||||||
YAML_DIR="kubernetes"
|
YAML_DIR="kubernetes"
|
||||||
|
|
||||||
|
# Ricava il nome progetto dalle variabili esposte da Gitea/GitHub Actions.
|
||||||
|
# Fallback locale: nome della directory del repository.
|
||||||
|
PROJECT_NAME="${GITHUB_REPOSITORY_NAME:-${GITEA_REPOSITORY_NAME:-}}"
|
||||||
|
if [ -z "$PROJECT_NAME" ] && [ -n "${GITHUB_REPOSITORY:-}" ]; then
|
||||||
|
PROJECT_NAME="${GITHUB_REPOSITORY##*/}"
|
||||||
|
fi
|
||||||
|
if [ -z "$PROJECT_NAME" ] && [ -n "${GITEA_REPOSITORY:-}" ]; then
|
||||||
|
PROJECT_NAME="${GITEA_REPOSITORY##*/}"
|
||||||
|
fi
|
||||||
|
if [ -z "$PROJECT_NAME" ]; then
|
||||||
|
PROJECT_NAME=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
|
||||||
|
fi
|
||||||
|
|
||||||
# Estrai l'hash completo del commit e crea una variabile temporanea per la sostituzione
|
# Estrai l'hash completo del commit e crea una variabile temporanea per la sostituzione
|
||||||
TAG=$(git rev-parse HEAD)
|
TAG=$(git rev-parse HEAD)
|
||||||
TMP_TAG_FILE=$(mktemp)
|
TMP_TAG_FILE=$(mktemp)
|
||||||
@@ -24,6 +37,9 @@ if [ ! -f "$PROPERTIES_FILE" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Costruisce il nome del namespace come <project_name>-<env>
|
||||||
|
NAMESPACE="${PROJECT_NAME}-${ENV}"
|
||||||
|
|
||||||
# Crea una lista key=value temporanea partendo da tutti i file *.env in env/$ENV e aggiunge env dinamico
|
# Crea una lista key=value temporanea partendo da tutti i file *.env in env/$ENV e aggiunge env dinamico
|
||||||
> "$TMP_VALUES_FILE"
|
> "$TMP_VALUES_FILE"
|
||||||
for env_file in "$VALUES_DIR"/*.env; do
|
for env_file in "$VALUES_DIR"/*.env; do
|
||||||
@@ -31,6 +47,19 @@ for env_file in "$VALUES_DIR"/*.env; do
|
|||||||
printf '\n' >> "$TMP_VALUES_FILE"
|
printf '\n' >> "$TMP_VALUES_FILE"
|
||||||
done
|
done
|
||||||
printf '\nenv=%s\n' "$ENV" >> "$TMP_VALUES_FILE"
|
printf '\nenv=%s\n' "$ENV" >> "$TMP_VALUES_FILE"
|
||||||
|
printf 'namespace=%s\n' "$NAMESPACE" >> "$TMP_VALUES_FILE"
|
||||||
|
printf 'project=%s\n' "$PROJECT_NAME" >> "$TMP_VALUES_FILE"
|
||||||
|
|
||||||
|
# Ricava endpoint se presente e genera le variabili derivate per le sostituzioni YAML.
|
||||||
|
ENDPOINT_VAL=$(grep -E '^[[:space:]]*endpoint[[:space:]]*=' "$TMP_VALUES_FILE" "$PROPERTIES_FILE" 2>/dev/null | tail -n 1 | sed -E 's/.*endpoint[[:space:]]*=[[:space:]]*//' | tr -d '\r\n[:space:]"' || true)
|
||||||
|
if [ -n "$ENDPOINT_VAL" ]; then
|
||||||
|
ENDPOINT_NODOT=$(echo "$ENDPOINT_VAL" | tr '.' '-')
|
||||||
|
ENDPOINT_NOSPACE=$(echo "$ENDPOINT_VAL" | tr -d '.')
|
||||||
|
|
||||||
|
printf 'endpoint-nodot=%s\n' "$ENDPOINT_NODOT" >> "$TMP_VALUES_FILE"
|
||||||
|
printf 'endpoint-nospace=%s\n' "$ENDPOINT_NOSPACE" >> "$TMP_VALUES_FILE"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
# Trova tutti i file .yaml nella directory kubernetes e sottodirectory
|
# Trova tutti i file .yaml nella directory kubernetes e sottodirectory
|
||||||
find "$YAML_DIR" -type f -name "*.yaml" | while read YAML_FILE; do
|
find "$YAML_DIR" -type f -name "*.yaml" | while read YAML_FILE; do
|
||||||
|
|||||||
+7
-39
@@ -7,52 +7,20 @@ ENVIRONMENT="${1:-dev}"
|
|||||||
|
|
||||||
YAML_DIR="kubernetes"
|
YAML_DIR="kubernetes"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Cerca risorse postgresql.cnpg.io/v1 nei manifest e deploya una ConfigMap
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
CNPG_FILE=$(grep -rl "postgresql.cnpg.io/v1" "$YAML_DIR" 2>/dev/null | head -1 || true)
|
|
||||||
|
|
||||||
if [ -n "$CNPG_FILE" ]; then
|
|
||||||
echo "Trovata risorsa postgresql.cnpg.io/v1 in: $CNPG_FILE"
|
|
||||||
|
|
||||||
# Estrae metadata.name dal manifest CNPG preferendo yq, altrimenti awk
|
|
||||||
if command -v yq >/dev/null 2>&1; then
|
|
||||||
PG_NAME=$(yq eval 'select(.apiVersion == "postgresql.cnpg.io/v1") | .metadata.name' "$CNPG_FILE")
|
|
||||||
else
|
|
||||||
PG_NAME=$(awk '/postgresql\.cnpg\.io\/v1/{found=1} found && /^metadata:/{meta=1} meta && /^\s+name:/{print $2; exit}' "$CNPG_FILE")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ricava il namespace dal Role namespace-deployer presente nel cluster
|
|
||||||
PG_NS=$(kubectl --kubeconfig=./kubeconfig get role namespace-deployer \
|
|
||||||
--no-headers \
|
|
||||||
-o custom-columns='NS:.metadata.namespace' 2>/dev/null | head -1 || true)
|
|
||||||
#PG_NS="${PG_NS:-default}"
|
|
||||||
|
|
||||||
if [ -z "$PG_NAME" ]; then
|
|
||||||
echo "⚠️ Impossibile estrarre metadata.name dal cluster CNPG, skip ConfigMap." >&2
|
|
||||||
else
|
|
||||||
echo " → cluster: $PG_NAME namespace: $PG_NS"
|
|
||||||
kubectl --kubeconfig=./kubeconfig apply -f - <<EOF
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: service-config
|
|
||||||
namespace: ${PG_NS}
|
|
||||||
data:
|
|
||||||
tipodb: "postgres"
|
|
||||||
urldb: "${PG_NAME}.${PG_NS}.svc.cluster.local"
|
|
||||||
EOF
|
|
||||||
echo "ConfigMap db-config deployata in namespace ${PG_NS}."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Deploy di tutti i manifest Kubernetes
|
# Deploy di tutti i manifest Kubernetes
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
find "$YAML_DIR" -type d | while read DIR; do
|
find "$YAML_DIR" -type d | while read DIR; do
|
||||||
if ls "$DIR"/*.yaml 1> /dev/null 2>&1; then
|
if ls "$DIR"/*.yaml 1> /dev/null 2>&1; then
|
||||||
echo "Deploy delle risorse nella directory $DIR..."
|
if [ "$(basename "$DIR")" = "monitoring" ]; then
|
||||||
kubectl --kubeconfig=./kubeconfig apply -f "$DIR"
|
echo "Deploy delle risorse di monitoring nella directory $DIR con kubeconfig dedicato..."
|
||||||
|
kubectl --kubeconfig=/root/work/pipeline/kc apply -f "$DIR"
|
||||||
|
else
|
||||||
|
echo "Deploy delle risorse nella directory $DIR..."
|
||||||
|
kubectl --kubeconfig=./kubeconfig apply -f "$DIR"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
. ./.profile
|
||||||
|
cd /project/inbound_figc
|
||||||
|
rm -f *.csv
|
||||||
|
rm -f *.csv_int*
|
||||||
|
|
||||||
|
./getftp.sh
|
||||||
|
./loadpgare.sh csexc17f.csv ana
|
||||||
|
./loadpgare.sh cseri17f.csv imp
|
||||||
|
./loadpgare.sh cserc17f.csv cal
|
||||||
|
./loadpgare.sh csezc17f.csv cla
|
||||||
|
#./loadpgare.sh cseyc17f.csv
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp cserc17f.csv_int_utf8_nobom.csv db/postgresql-1-postgresql-0:/etc/cserc17f_2load_utf8_nobom.csv
|
||||||
|
/usr/local/bin/kubectl cp cseri17f.csv_int_utf8_nobom.csv db/postgresql-1-postgresql-0:/etc/cseri17f_2load_utf8_nobom.csv
|
||||||
|
/usr/local/bin/kubectl cp csexc17f.csv_int_utf8_nobom.csv db/postgresql-1-postgresql-0:/etc/csexc17f_2load_utf8_nobom.csv
|
||||||
|
/usr/local/bin/kubectl cp csezc17f.csv_int_utf8_nobom.csv db/postgresql-1-postgresql-0:/etc/csezc17f_2load_utf8_nobom.csv
|
||||||
|
#k cp csezc17f.csv_int_utf8_nobom.csv db/postgresql-1-postgresql-0:/etc/csezc17f_2load_utf8_nobom.csv
|
||||||
|
|
||||||
|
name=$(date '+%Y-%m-%d')
|
||||||
|
tar -zcvf "$name.tar.gz" *.csv
|
||||||
|
mv *.gz ./arch
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp pgareload.sql db/postgresql-1-postgresql-0:/etc/pgareload.sql
|
||||||
|
/usr/local/bin/kubectl exec -it postgresql-1-postgresql-0 -c postgresql-server -n db -- psql -U postgres -d pgare -f /etc/pgareload.sql
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp loadclub.sql db/postgresql-1-postgresql-0:/etc/loadclub.sql
|
||||||
|
/usr/local/bin/kubectl exec -it postgresql-1-postgresql-0 -c postgresql-server -n db -- psql -U postgres -d segdigi -f /etc/loadclub.sql
|
||||||
|
|
||||||
|
sleep 120
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp partite_ftp.sql db/postgresql-1-postgresql-0:/etc/partite_ftp.sql
|
||||||
|
/usr/local/bin/kubectl exec -it postgresql-1-postgresql-0 -c postgresql-server -n db -- psql -U postgres -d gare -f /etc/partite_ftp.sql
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp campionati_ftp.sql db/postgresql-1-postgresql-0:/etc/campionati_ftp.sql
|
||||||
|
kubectl exec -it postgresql-1-postgresql-0 -c postgresql-server -n db -- psql -U postgres -d gare -f /etc/campionati_ftp.sql
|
||||||
|
|
||||||
|
/usr/local/bin/kubectl cp companies_ftp.sql db/postgresql-1-postgresql-0:/etc/companies_ftp.sql
|
||||||
|
/usr/local/bin/kubectl exec -it postgresql-1-postgresql-0 -c postgresql-server -n db -- psql -U postgres -d companies -f /etc/companies_ftp.sql
|
||||||
Reference in New Issue
Block a user