This commit is contained in:
alessandro
2026-09-21 10:00:14 +02:00
11 changed files with 578 additions and 8 deletions
@@ -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.
@@ -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
+121 -5
View File
@@ -619,6 +619,11 @@ spec:
EOF
```
COMANDO - applica alert
```bash
kubectl apply -f blackbox-http-alerts.yaml
@@ -631,8 +636,119 @@ kubectl describe prometheusrule blackbox-http-alerts -n monitoring
```
10. TEST MANUALE BLACKBOX EXPORTER
=================================
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
@@ -651,7 +767,7 @@ probe_http_status_code 200
```
11. TROUBLESHOOTING
12. TROUBLESHOOTING
===================
CASO - Prometheus non vede la Probe
@@ -700,7 +816,7 @@ Azioni consigliate:
- aggiungere un modulo dedicato in blackbox-values.yaml se serve una configurazione HTTP specifica.
12. ORDINE DI ESECUZIONE CONSIGLIATO
13. ORDINE DI ESECUZIONE CONSIGLIATO
====================================
COMANDO - sequenza completa
@@ -727,7 +843,7 @@ blackbox-http-alerts.yaml
```
13. NOTE PER DEV, QA E PROD
14. NOTE PER DEV, QA E PROD
===========================
Per separare gli ambienti e semplificare dashboard e alert, usa Probe distinte: