Workload
Il livello tra il pod e il namespace. È dove si risponde alla domanda che conta davvero in un incident: il servizio è giù o solo degradato?
Un pod che restarta mentre le altre repliche reggono è un ticket. Lo stesso pod quando le repliche disponibili sono zero è un incident.
| Triage | disponibilità e rollout |
| Deployment · StatefulSet · DaemonSet | |
| Job e CronJob | |
| Consumo aggregato | CPU, memoria, restart |
| Sbilanciamento tra repliche | |
| HPA · PDB | |
Comandi oc · Alert |
Il join fondamentale
Le metriche di cAdvisor e kube-state-metrics sono per pod: non portano il nome del Deployment. La recording rule preinstallata risolve la catena Pod → ReplicaSet → owner:
* on(namespace, pod) group_left(workload, workload_type) max by (namespace, pod, workload, workload_type) (namespace_workload_pod:kube_pod_owner:relabel)Gestisce insieme Deployment, StatefulSet, DaemonSet e Job, esponendo workload e workload_type.
Verifica che esista sul tuo cluster:
# numero di seriecount by (workload_type) (namespace_workload_pod:kube_pod_owner:relabel)Se manca, il ripiego è label_replace sull’hash del ReplicaSet — funziona ma si rompe sui nomi contenenti trattini seguiti da stringhe alfanumeriche:
* on(namespace, pod) group_left(deployment) label_replace( kube_pod_owner{owner_kind="ReplicaSet"}, "deployment", "$1", "owner_name", "^(.+)-[a-z0-9]+$" )Triage
T1. Workload con repliche mancanti
# conteggio( kube_deployment_status_replicas_available{namespace!~"kube-.*|openshift-.*|default"} < kube_deployment_spec_replicas{namespace!~"kube-.*|openshift-.*|default"})T2. Workload completamente giù
# elenco: ogni serie restituita soddisfa la condizionekube_deployment_status_replicas_available{namespace!~"kube-.*|openshift-.*|default"} == 0andkube_deployment_spec_replicas{namespace!~"kube-.*|openshift-.*|default"} > 0I casi da guardare per primi: il servizio non risponde.
T3. Frazione di repliche disponibili
# percentuale 0-100100 * ( topk(20, kube_deployment_status_replicas_available{namespace!~"kube-.*|openshift-.*|default"} / kube_deployment_spec_replicas{namespace!~"kube-.*|openshift-.*|default"} ) < 1)Ordina per gravità reale: 0.5 su un servizio a 2 repliche è più serio di 0.9 su uno a 10.
T4. Rollout bloccati
# elenco: ogni serie restituita soddisfa la condizionekube_deployment_status_condition{condition="Progressing", status="false"} == 1T5. Restart per workload
# conteggio nelle ultime 6 oretopk(20, sum by (namespace, workload, workload_type) ( increase(kube_pod_container_status_restarts_total{ namespace!~"kube-.*|openshift-.*|default" }[6h]) * on(namespace, pod) group_left(workload, workload_type) max by (namespace, pod, workload, workload_type) (namespace_workload_pod:kube_pod_owner:relabel) )) > 0Deployment
Repliche: desiderate, disponibili, pronte, aggiornate
# conteggio · sostituisci $nskube_deployment_spec_replicas{namespace="$ns"}# conteggio · sostituisci $nskube_deployment_status_replicas_available{namespace="$ns"}# conteggio · sostituisci $nskube_deployment_status_replicas_ready{namespace="$ns"}# conteggio · sostituisci $nskube_deployment_status_replicas_updated{namespace="$ns"}I quattro numeri raccontano insieme lo stato del rollout:
| Situazione | Lettura |
|---|---|
updated < spec | rollout in corso o bloccato |
available < ready | i pod sono pronti ma il minReadySeconds non è ancora trascorso |
ready < available | anomalia: pod che hanno perso la readiness dopo essere stati disponibili |
available == 0, spec > 0 | servizio giù |
Deployment in rollout
# conteggiokube_deployment_status_replicas_updated{namespace!~"kube-.*|openshift-.*|default"}!=kube_deployment_spec_replicas{namespace!~"kube-.*|openshift-.*|default"}Rollout fermo da troppo tempo
# secondi( kube_deployment_status_replicas_updated != kube_deployment_spec_replicas)and( (time() - kube_deployment_status_observed_generation) > 600)Il progressDeadlineSeconds di default è 600. Superato, il Deployment va in Progressing=False con ProgressDeadlineExceeded e smette di provarci.
Generazione osservata vs desiderata
# differenza fra generazione desiderata e osservata: 0 = allineato · sostituisci $nskube_deployment_metadata_generation{namespace="$ns"}-kube_deployment_status_observed_generation{namespace="$ns"}Diverso da zero = il controller non ha ancora preso in carico l’ultima modifica. Se resta diverso da zero, il deployment controller è in affanno o bloccato.
Strategia di rollout
# numero di pod, o percentuale se il manifest la esprime così · sostituisci $nskube_deployment_spec_strategy_rollingupdate_max_unavailable{namespace="$ns"}# numero di pod, o percentuale se il manifest la esprime così · sostituisci $nskube_deployment_spec_strategy_rollingupdate_max_surge{namespace="$ns"}maxUnavailable alto su un servizio a poche repliche significa che durante ogni deploy il servizio è degradato. Su un frontend con SLA, maxUnavailable: 0 e maxSurge: 1 è la configurazione corretta — costa una replica in più durante il rollout.
Condizioni
# elenco: ogni serie restituita soddisfa la condizione · sostituisci $nskube_deployment_status_condition{namespace="$ns"} == 1condition | status | Significato |
|---|---|---|
Available | false | meno repliche disponibili del minAvailable implicito |
Progressing | false | rollout fallito o in stallo |
ReplicaFailure | true | il ReplicaSet non riesce a creare pod: quota, SCC, node selector |
ReplicaFailure=True è quello che si dimentica: il rollout sembra fermo senza motivo, e la causa è che il ReplicaSet non può nemmeno creare i pod.
oc describe rs -n $ns -l app=$workload | sed -n '/Events:/,$p'StatefulSet
# conteggio · sostituisci $nskube_statefulset_replicas{namespace="$ns"}# conteggio · sostituisci $nskube_statefulset_status_replicas_ready{namespace="$ns"}# conteggio · sostituisci $nskube_statefulset_status_replicas_current{namespace="$ns"}# conteggio · sostituisci $nskube_statefulset_status_replicas_updated{namespace="$ns"}StatefulSet degradati
# conteggiokube_statefulset_status_replicas_ready{namespace!~"kube-.*|openshift-.*|default"}<kube_statefulset_replicas{namespace!~"kube-.*|openshift-.*|default"}Revisione corrente vs aggiornata
# sempre 1: il label revision porta l'hash della ControllerRevision · sostituisci $nskube_statefulset_status_current_revision{namespace="$ns"}# sempre 1: il label revision porta l'hash della ControllerRevision · sostituisci $nskube_statefulset_status_update_revision{namespace="$ns"}Gli StatefulSet aggiornano un pod alla volta, in ordine inverso di ordinale, e si fermano al primo che non diventa Ready. Un rollout bloccato su un pod significa che tutti quelli con ordinale inferiore restano alla versione vecchia, indefinitamente.
oc get sts -n $ns $workload -o jsonpath='{.status}' | jqoc rollout status sts/$workload -n $ns --timeout=30sOrdinale del pod bloccato
# elenco: ogni serie restituita soddisfa la condizione · sostituisci $ns, $workloadkube_pod_status_ready{namespace="$ns", pod=~"$workload-[0-9]+", condition="false"} == 1Il pod con l’ordinale più alto non pronto è quello che blocca la catena.
DaemonSet
# numero di pod del DaemonSet · sostituisci $nskube_daemonset_status_desired_number_scheduled{namespace="$ns"}# numero di pod del DaemonSet · sostituisci $nskube_daemonset_status_number_ready{namespace="$ns"}# numero di pod del DaemonSet · sostituisci $nskube_daemonset_status_number_unavailable{namespace="$ns"}DaemonSet incompleti
# numero di pod del DaemonSetkube_daemonset_status_number_ready!=kube_daemonset_status_desired_number_scheduledQuery da tenere d’occhio anche sui namespace di piattaforma, senza il filtro applicativo: ovnkube-node, node-exporter, machine-config-daemon sono DaemonSet, e se non sono completi hai nodi con funzionalità mancanti che si manifestano come problemi applicativi apparentemente casuali.
# numero di pod del DaemonSetkube_daemonset_status_number_ready{namespace=~"openshift-.*"}!=kube_daemonset_status_desired_number_scheduled{namespace=~"openshift-.*"}Su quali nodi manca
oc get pods -n $ns -l app=$ds -o wide --sort-by=.spec.nodeNameoc get nodes -o name | sed 's|node/||' | sort > /tmp/all-nodesoc get pods -n $ns -l app=$ds -o jsonpath='{range .items[*]}{.spec.nodeName}{"\n"}{end}' | sort > /tmp/ds-nodescomm -23 /tmp/all-nodes /tmp/ds-nodesI nodi elencati non hanno il pod del DaemonSet: taint non tollerato, risorse insufficienti, o il pod è in Pending.
Misscheduled
# numero di pod del DaemonSetkube_daemonset_status_number_misscheduled > 0Pod del DaemonSet su nodi dove non dovrebbero stare: succede quando si cambia il nodeSelector e i vecchi pod non vengono rimossi.
Job e CronJob
Job falliti
# numero di pod del Jobkube_job_status_failed{namespace!~"kube-.*|openshift-.*|default"} > 0Job attivi
# numero di pod del Jobkube_job_status_active{namespace!~"kube-.*|openshift-.*|default"} > 0Job che girano da troppo
# secondi(time() - kube_job_status_start_time{namespace!~"kube-.*|openshift-.*|default"}) / 60> 60andkube_job_status_active > 0Job attivi da più di un’ora. Senza activeDeadlineSeconds, un Job appeso resta appeso per sempre e occupa risorse.
Durata dei Job completati
# minuti · sostituisci $ns( kube_job_status_completion_time{namespace="$ns"} - kube_job_status_start_time{namespace="$ns"}) / 60Minuti di esecuzione. Un aumento della durata nel tempo, a parità di dati, è una regressione da segnalare.
CronJob: ultima schedulazione
# ore(time() - kube_cronjob_status_last_schedule_time{namespace!~"kube-.*|openshift-.*|default"}) / 3600Ore dall’ultima esecuzione. Confronta con la frequenza dichiarata:
# sempre 1: il label schedule porta l'espressione cron · sostituisci $nskube_cronjob_info{namespace="$ns"}Il label schedule porta l’espressione cron.
CronJob sospesi
# elenco: ogni serie restituita soddisfa la condizionekube_cronjob_spec_suspend{namespace!~"kube-.*|openshift-.*|default"} == 1Un CronJob sospeso e dimenticato è la causa classica di elaborazioni ferme senza nessun errore in evidenza.
CronJob che non parte da troppo
# secondi(time() - kube_cronjob_status_last_schedule_time) > 86400andkube_cronjob_spec_suspend == 0Non sospeso ma fermo da più di un giorno. Cause: concurrencyPolicy: Forbid con un job precedente ancora appeso, startingDeadlineSeconds superato, controller in errore.
Job non ripuliti
# numero di seriecount by (namespace) (kube_job_complete{namespace!~"kube-.*|openshift-.*|default"} == 1)Senza ttlSecondsAfterFinished, i Job completati restano nell’API e gonfiano etcd. Su cluster con CronJob frequenti se ne accumulano migliaia.
oc get jobs -A --no-headers | wc -loc get jobs -n $ns --sort-by=.status.completionTime | head -20Consumo aggregato per workload
CPU
# core CPUtopk(20, sum by (namespace, workload, workload_type) ( rate(container_cpu_usage_seconds_total{ namespace!~"kube-.*|openshift-.*|default", container!="", container!="POD" }[5m]) * on(namespace, pod) group_left(workload, workload_type) max by (namespace, pod, workload, workload_type) (namespace_workload_pod:kube_pod_owner:relabel) ))Memoria
# GiBtopk(20, sum by (namespace, workload, workload_type) ( container_memory_working_set_bytes{ namespace!~"kube-.*|openshift-.*|default", container!="", container!="POD" } * on(namespace, pod) group_left(workload, workload_type) max by (namespace, pod, workload, workload_type) (namespace_workload_pod:kube_pod_owner:relabel) )) / 1024^3CPU media per replica
# core CPU · sostituisci $nssum by (namespace, workload) ( rate(container_cpu_usage_seconds_total{namespace="$ns", container!="", container!="POD"}[5m]) * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel{workload_type="deployment"}))/sum by (namespace, workload) ( count by (namespace, pod) (kube_pod_info{namespace="$ns"}) * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel{workload_type="deployment"}))Serve per decidere se scalare orizzontalmente ha senso: se la media per replica non scende aggiungendo repliche, il carico non è distribuito — sessioni sticky, lock, singolo consumer di coda.
Crescita nelle ultime 24 ore
# byte · sostituisci $nssum by (namespace, workload) ( container_memory_working_set_bytes{namespace="$ns", container!="", container!="POD"} * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel))-sum by (namespace, workload) ( container_memory_working_set_bytes{namespace="$ns", container!="", container!="POD"} offset 24h * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel))Se il workload è stato riavviato nel frattempo il confronto non ha senso: incrocia sempre con i restart.
Frazione di repliche che ha restartato
# numero di serie · sostituisci $nscount by (namespace, workload) ( (increase(kube_pod_container_status_restarts_total{namespace="$ns"}[6h]) > 0) * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel))/count by (namespace, workload) ( kube_pod_info{namespace="$ns"} * on(namespace, pod) group_left(workload) max by (namespace, pod, workload) (namespace_workload_pod:kube_pod_owner:relabel))1 = tutte, quindi il problema è del workload. < 0.3 = solo alcune, guarda i nodi su cui girano.
Sbilanciamento tra repliche
Repliche stateless dietro lo stesso Service devono comportarsi in modo simile. Le deviazioni sono diagnostiche.
CPU
# core CPU · sostituisci $ns, $workloadsum by (pod) ( rate(container_cpu_usage_seconds_total{ namespace="$ns", pod=~"$workload-.*", container!="", container!="POD" }[5m]))Memoria
# MiB · sostituisci $ns, $workloadsum by (pod) ( container_memory_working_set_bytes{ namespace="$ns", pod=~"$workload-.*", container!="", container!="POD" }) / 1024^2Traffico ricevuto
# MiB · sostituisci $ns, $workloadsum by (pod) ( rate(container_network_receive_bytes_total{namespace="$ns", pod=~"$workload-.*"}[5m])) / 1024^2Una replica a zero traffico è fuori dagli endpoint (readiness fallita). Una a 5× le altre indica sessioni sticky o un client che non rifà la risoluzione DNS.
Coefficiente di variazione
# byte · sostituisci $ns, $workloadstddev by (namespace) ( sum by (namespace, pod) ( container_memory_working_set_bytes{namespace="$ns", pod=~"$workload-.*", container!="", container!="POD"} ))/avg by (namespace) ( sum by (namespace, pod) ( container_memory_working_set_bytes{namespace="$ns", pod=~"$workload-.*", container!="", container!="POD"} ))Deviazione standard normalizzata sulla media. Sotto 0.2 le repliche sono omogenee. Sopra 0.5 c’è qualcosa che le rende diverse tra loro, e vale la pena capire cosa prima di dimensionare.
Distribuzione sui nodi
# numero di serie · sostituisci $ns, $workloadcount by (node) ( kube_pod_info{namespace="$ns", pod=~"$workload-.*"})Tutte le repliche sullo stesso nodo = manca l’anti-affinity, e un reboot di quel nodo porta giù il servizio nonostante le repliche multiple.
oc get pod -n $ns -l app=$workload -o json | jq '.items[0].spec.affinity'Versioni diverse in esecuzione
# numero di serie · sostituisci $ns, $workloadcount by (namespace, image) ( kube_pod_container_info{namespace="$ns", pod=~"$workload-.*"})Più di una riga fuori da un rollout attivo = rollout parziale rimasto a metà.
HPA
# conteggio · sostituisci $nskube_horizontalpodautoscaler_status_current_replicas{namespace="$ns"}# conteggio · sostituisci $nskube_horizontalpodautoscaler_status_desired_replicas{namespace="$ns"}# conteggio · sostituisci $nskube_horizontalpodautoscaler_spec_min_replicas{namespace="$ns"}# conteggio · sostituisci $nskube_horizontalpodautoscaler_spec_max_replicas{namespace="$ns"}HPA al massimo
# conteggiokube_horizontalpodautoscaler_status_current_replicas==kube_horizontalpodautoscaler_spec_max_replicasL’HPA ha esaurito il margine: da qui in poi il carico non viene più assorbito. È il momento in cui bisogna decidere se alzare maxReplicas o se il problema è a valle (database, dipendenza).
HPA che non riesce a scalare
# elenco: ogni serie restituita soddisfa la condizionekube_horizontalpodautoscaler_status_condition{condition="ScalingLimited", status="true"} == 1# elenco: ogni serie restituita soddisfa la condizionekube_horizontalpodautoscaler_status_condition{condition="AbleToScale", status="false"} == 1AbleToScale=False significa che l’HPA non riesce nemmeno a leggere le metriche: metrics-server assente, o le request non sono impostate (l’HPA su CPU richiede requests.cpu, altrimenti non ha un denominatore).
oc describe hpa -n $ns $hpa | sed -n '/Conditions:/,$p'oc adm top pod -n $nsFlapping
# numero di variazioni nella finestra · sostituisci $nschanges(kube_horizontalpodautoscaler_status_desired_replicas{namespace="$ns"}[1h])Molti cambi in un’ora = l’HPA sta oscillando. Si corregge con behavior.scaleDown.stabilizationWindowSeconds.
PodDisruptionBudget
# numero di pod · sostituisci $nskube_poddisruptionbudget_status_desired_healthy{namespace="$ns"}# numero di pod · sostituisci $nskube_poddisruptionbudget_status_current_healthy{namespace="$ns"}# numero di pod · sostituisci $nskube_poddisruptionbudget_status_pod_disruptions_allowed{namespace="$ns"}PDB che bloccano il drain
# elenco: ogni serie restituita soddisfa la condizionekube_poddisruptionbudget_status_pod_disruptions_allowed == 0Query da lanciare prima di ogni manutenzione dei nodi. Un PDB con zero disruption consentite blocca oc adm drain indefinitamente, e te ne accorgi a finestra di manutenzione già aperta.
oc get pdb -Aoc get events -A --field-selector reason=EvictionBlocked --sort-by=.lastTimestamp | tailPDB mal configurati
# conteggiokube_poddisruptionbudget_status_desired_healthy>=kube_poddisruptionbudget_status_expected_podsminAvailable uguale o maggiore del numero di repliche: il PDB non permetterà mai nessuna disruption. È un errore di configurazione, non una scelta.
Workload senza PDB
Non c’è una metrica diretta. Confronto lato oc:
oc get deploy -n $ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | sort > /tmp/deploysoc get pdb -n $ns -o jsonpath='{range .items[*]}{.spec.selector.matchLabels.app}{"\n"}{end}' | sort > /tmp/pdbscomm -23 /tmp/deploys /tmp/pdbsSu workload di produzione con più repliche, l’assenza di PDB significa che un drain può portarle giù tutte insieme.
Comandi oc
# Stato di tutti i workload di un namespaceoc get deploy,sts,ds,cronjob -n $ns
# Rollout in corsooc rollout status deploy/$workload -n $ns --timeout=60s
# Storico e rollbackoc rollout history deploy/$workload -n $nsoc rollout undo deploy/$workload -n $nsoc rollout undo deploy/$workload -n $ns --to-revision=3
# Riavvio controllato (rolling, non delete)oc rollout restart deploy/$workload -n $ns
# Perché il ReplicaSet non crea podoc describe rs -n $ns -l app=$workload | sed -n '/Events:/,$p'
# Deployment degradati in tutto il clusteroc get deploy -A -o json | jq -r ' .items[] | select(.status.availableReplicas // 0 < .spec.replicas) | "\(.metadata.namespace)\t\(.metadata.name)\t\(.status.availableReplicas // 0)/\(.spec.replicas)"'
# Job fallitioc get jobs -A --field-selector status.successful=0 -o wide
# Log dell'ultimo pod di un CronJoboc logs -n $ns job/$(oc get jobs -n $ns --sort-by=.status.startTime -o jsonpath='{.items[-1].metadata.name}')
# Anti-affinity configurataoc get deploy -n $ns $workload -o jsonpath='{.spec.template.spec.affinity}' | jq
# Scale manualeoc scale deploy/$workload -n $ns --replicas=5Alert
apiVersion: monitoring.coreos.com/v1kind: PrometheusRulemetadata: name: workload-health namespace: <ns> labels: role: alert-rulesspec: groups: - name: workload.availability rules: - alert: DeploymentDown expr: | kube_deployment_status_replicas_available == 0 and kube_deployment_spec_replicas > 0 for: 5m labels: severity: critical annotations: summary: "{{ $labels.deployment }} ({{ $labels.namespace }}): nessuna replica disponibile" description: "Servizio non raggiungibile da 5 minuti."
- alert: DeploymentReplicasMismatch expr: | kube_deployment_status_replicas_available < kube_deployment_spec_replicas for: 20m labels: severity: warning annotations: summary: "{{ $labels.deployment }}: {{ $value }} repliche disponibili su quelle attese" description: "Capacità ridotta da 20 minuti. Verificare se è un rollout in corso o pod che non partono."
- alert: DeploymentRolloutStuck expr: | kube_deployment_status_condition{condition="Progressing", status="false"} == 1 for: 15m labels: severity: warning annotations: summary: "{{ $labels.deployment }}: rollout in stallo" description: "ProgressDeadlineExceeded. Verificare oc describe rs per il motivo."
- alert: StatefulSetDegraded expr: | kube_statefulset_status_replicas_ready < kube_statefulset_replicas for: 20m labels: severity: warning annotations: summary: "{{ $labels.statefulset }}: {{ $value }} repliche ready sulle attese" description: "Gli StatefulSet aggiornano un pod alla volta: un pod bloccato ferma tutta la catena."
- alert: DaemonSetIncomplete expr: | kube_daemonset_status_number_ready != kube_daemonset_status_desired_number_scheduled for: 30m labels: severity: warning annotations: summary: "{{ $labels.daemonset }}: manca su {{ $value }} nodi"
- name: workload.jobs rules: - alert: JobFailed expr: kube_job_status_failed > 0 for: 5m labels: severity: warning annotations: summary: "Job {{ $labels.job_name }} ({{ $labels.namespace }}) fallito"
- alert: JobRunningTooLong expr: | (time() - kube_job_status_start_time) > 3600 and kube_job_status_active > 0 for: 10m labels: severity: warning annotations: summary: "Job {{ $labels.job_name }} attivo da oltre un'ora" description: "Senza activeDeadlineSeconds un Job appeso resta appeso indefinitamente."
- alert: CronJobNotScheduled expr: | (time() - kube_cronjob_status_last_schedule_time) > 86400 and kube_cronjob_spec_suspend == 0 for: 1h labels: severity: warning annotations: summary: "CronJob {{ $labels.cronjob }} non parte da oltre 24 ore"
- name: workload.scaling rules: - alert: HPAAtMaxReplicas expr: | kube_horizontalpodautoscaler_status_current_replicas == kube_horizontalpodautoscaler_spec_max_replicas for: 30m labels: severity: warning annotations: summary: "HPA {{ $labels.horizontalpodautoscaler }} al massimo delle repliche" description: "Margine esaurito: il carico ulteriore non viene più assorbito."
- alert: HPAUnableToScale expr: | kube_horizontalpodautoscaler_status_condition{condition="AbleToScale", status="false"} == 1 for: 15m labels: severity: warning annotations: summary: "HPA {{ $labels.horizontalpodautoscaler }} non riesce a scalare" description: "Verificare metrics-server e che i pod abbiano requests.cpu impostate."
- alert: PDBBlocksDrain expr: kube_poddisruptionbudget_status_pod_disruptions_allowed == 0 for: 1h labels: severity: info annotations: summary: "PDB {{ $labels.poddisruptionbudget }}: zero disruption consentite" description: "Un drain dei nodi si bloccherà su questo PDB. Verificare prima della manutenzione."Vedi anche
- Pod / Container — il livello sotto
- Namespace — il livello sopra
- Nodo — PDB e drain