
No universo do DevOps, a confiabilidade de aplicações em produção é tão importante quanto a velocidade de entrega. Mas como garantir que seus Pods no Kubernetes não apenas estejam rodando, mas também sejam resilientes, saudáveis e corretamente configurados?
A transformação digital exige mais do que automação básica. Exige visibilidade inteligente e validação proativa. Se existe uma linguagem que se tornou a ferramenta preferida do engenheiro de DevOps para integrar e coordenar serviços complexos, essa linguagem é o Python.
Neste guia prático, você aprenderá a usar Python para DevOps para criar um sistema de auditoria automatizada que valida health checks, resource limits e o estado geral dos Pods em seu cluster Kubernetes. Vamos além do simples “está rodando?” e mergulharemos na qualidade real da sua infraestrutura.
Imagine que você é responsável por um cluster Kubernetes com dezenas de aplicações distribuídas em múltiplos namespaces. Tudo parece estar funcionando: o comando kubectl get pods mostra a maioria dos Pods com status “Running”.
Mas então, em uma sexta-feira à noite, começam os problemas:
O pior: você descobriu tudo isso reagindo a incidentes ao invés de preveni-los.
A solução é simples e elegante: um script Python que audita proativamente todos os Pods do cluster, verificando:
✅ Se todos os containers estão prontos e saudáveis
✅ Se liveness probes estão configurados (para restart automático)
✅ Se readiness probes estão configurados (para controle de tráfego)
✅ Se resource limits estão definidos (para governança de recursos)
Com essa visibilidade, você transforma sua postura de reativa para proativa, identificando problemas antes que eles afetem os usuários.
O Python para DevOps não é apenas uma escolha técnica, é uma vantagem estratégica:
Sintaxe Clara e Expressiva
Python permite que você escreva scripts complexos que parecem prosa em inglês. Isso facilita a manutenção e colaboração entre equipes.
Ecossistema Rico
O kubernetes-client é o SDK oficial mantido pela comunidade Kubernetes. Ele traduz toda a complexidade da API REST em classes e métodos intuitivos.
Integração Natural
O SDK herda automaticamente as credenciais do kubectl do arquivo ~/.kube/config, tornando a autenticação trivial.
Rápido Desenvolvimento
A tipagem dinâmica e as bibliotecas robustas permitem criar ferramentas de automação em minutos, não dias.
Redução de MTTR (Mean Time To Recovery)
Scripts Python podem diagnosticar problemas em segundos, enquanto investigação manual levaria minutos ou horas.
Prevenção de Incidentes
Auditoria contínua identifica configurações problemáticas antes de causarem falhas.
Governança e Compliance
Valide automaticamente que todos os recursos seguem as políticas de segurança e resource management da organização.
Escalabilidade
O mesmo script funciona para 10 ou 1000 Pods, sem esforço adicional.
Antes de mergulharmos no código, vamos configurar um ambiente de desenvolvimento profissional. Trabalhar com ambientes virtuais é uma prática essencial no desenvolvimento Python.
python3 -m venv .venv
Este comando cria um ambiente isolado na pasta .venv, contendo uma cópia dedicada do interpretador Python e do pip. O isolamento evita conflitos entre dependências de diferentes projetos.
source .venv/bin/activate
No Windows:
.venv\\Scripts\\activate
Você verá (.venv) no prompt, indicando que o ambiente está ativo.
python3 -m pip install -U pip
A flag -U atualiza o pip para a versão mais recente, garantindo acesso a correções de segurança e melhor compatibilidade.
pip install kubernetes tabulate
pip freeze > requirements.txt
Isso documenta exatamente quais versões estão instaladas, facilitando a reprodução do ambiente.
Adicione ao .gitignore:
.venv/
__pycache__/
*.pyc
Agora vamos ao código que resolve nosso problema:
import re
from kubernetes import config
from kubernetes import client
from tabulate import tabulate
config.load_kube_config()
v1 = client.CoreV1Api()
emojis = {
'Running': '🟢',
'Pending': '🟡'
}
emojis_status = {
True: '🟢',
False: '🔴'
}
result = []
pods = v1.list_pod_for_all_namespaces()
if pods:
for pod in pods.items:
namespace = pod.metadata.namespace
name = pod.metadata.name
containers = pod.spec.containers
containers_statuses = pod.status.container_statuses
containers_ready = 0
containers_liveness_probe = 0
containers_readiness_probe = 0
containers_resources = 0
for container_status in containers_statuses:
ready = container_status.ready
if ready:
containers_ready += 1
for container in containers:
liveness_probe = container.liveness_probe
readiness_probe = container.readiness_probe
resources = container.resources
if liveness_probe:
containers_liveness_probe += 1
if readiness_probe:
containers_readiness_probe += 1
if resources:
containers_resources += 1
total_containers = len(containers)
status = pod.status.phase
if status in emojis:
emoji = emojis.get(status)
status = f'{emoji} {status}'
containers_status_result = f'{containers_ready}/{total_containers}'
status_readiness_probe = False
status_liveness_probe = False
status_resources = False
if containers_readiness_probe == total_containers:
status_readiness_probe = True
if containers_liveness_probe == total_containers:
status_liveness_probe = True
if containers_resources == total_containers:
status_resources = True
status_liveness_probe_view = emojis_status.get(status_liveness_probe)
status_readiness_probe_view = emojis_status.get(status_readiness_probe)
status_resources_view = emojis_status.get(status_resources)
row = [
namespace,
name,
status,
containers_status_result,
status_liveness_probe_view,
status_readiness_probe_view,
status_resources_view
]
result.append(row)
headers = ['Namespace', 'Nome', 'Status', 'READY', 'Liveness', 'Readiness', 'Resources']
print('')
print(tabulate(result, headers=headers, tablefmt='simple'))
Vamos dissecar cada parte do script, entendendo como ele implementa as melhores práticas de Python e DevOps.
import re
from kubernetes import config
from kubernetes import client
from tabulate import tabulate
Importações Essenciais:
re: Módulo de expressões regulares do Python (importado mas não utilizado neste script específico)kubernetes.config: Gerencia a configuração e autenticação com o clusterkubernetes.client: Fornece as classes para interagir com a API do Kubernetestabulate: Biblioteca para formatação elegante de tabelas no terminalPrincípio PEP-8: Os imports estão organizados de forma clara, facilitando a leitura e manutenção do código.
config.load_kube_config()
v1 = client.CoreV1Api()
config.load_kube_config()
Este é o ponto crucial de autenticação. A função procura automaticamente o arquivo ~/.kube/config (ou a variável de ambiente KUBECONFIG) e carrega:
Isso significa que o script herda automaticamente as mesmas permissões que você tem no kubectl, sem necessidade de gerenciar credenciais manualmente.
client.CoreV1Api()
Cria uma instância do cliente da API Core V1 do Kubernetes, que fornece acesso aos recursos fundamentais:
emojis = {
'Running': '🟢',
'Pending': '🟡'
}
emojis_status = {
True: '🟢',
False: '🔴'
}
Design Intuitivo:
O primeiro dicionário mapeia os estados dos Pods para representações visuais:
O segundo dicionário transforma valores booleanos em indicadores visuais:
Princípio PEP-20 “Explicit is better than implicit”:
Os emojis tornam os resultados imediatamente compreensíveis, sem necessidade de consultar documentação.
result = []
pods = v1.list_pod_for_all_namespaces()
result = []
Inicializa uma lista vazia que armazenará os dados de auditoria de cada Pod. Cada elemento será uma lista representando uma linha da tabela final.
v1.list_pod_for_all_namespaces()
Este método faz uma chamada REST à API do Kubernetes (GET /api/v1/pods) e retorna um objeto contendo todos os Pods de todos os namespaces do cluster. É o equivalente programático de:
kubectl get pods -A
if pods:
for pod in pods.items:
namespace = pod.metadata.namespace
name = pod.metadata.name
containers = pod.spec.containers
containers_statuses = pod.status.container_statuses
Estrutura Condicional:
O if pods: garante que só processamos se houver Pods no cluster, evitando erros em clusters vazios.
Iteração sobre Pods:
pods.items contém a lista de objetos Pod retornados pela API.
Extração de Metadados:
pod.metadata.namespace: Namespace onde o Pod está executandopod.metadata.name: Nome único do Podpod.spec.containers: Lista de especificações dos containers (configuração desejada)pod.status.container_statuses: Lista de status atuais dos containers (estado real) containers_ready = 0
containers_liveness_probe = 0
containers_readiness_probe = 0
containers_resources = 0
Inicialização de Contadores:
Estas variáveis rastreiam quantos containers em cada Pod possuem as configurações críticas:
containers_ready: Quantos containers estão prontos e aceitando requisiçõescontainers_liveness_probe: Quantos têm health check para detecção de travamentoscontainers_readiness_probe: Quantos têm health check para controle de tráfegocontainers_resources: Quantos têm limits/requests de CPU e memória definidosPrincípio PEP-8:
Nomes de variáveis em snake_case descritivos tornam o código autodocumentado.
for container_status in containers_statuses:
ready = container_status.ready
if ready:
containers_ready += 1
Loop de Verificação de Prontidão:
Este loop itera sobre o status atual de cada container e incrementa o contador quando encontra containers prontos.
Atributo ready:
Um container está “ready” quando:
Esta informação é crítica porque um Pod pode estar “Running” mas com containers não prontos, causando falhas de requisições.
for container in containers:
liveness_probe = container.liveness_probe
readiness_probe = container.readiness_probe
resources = container.resources
if liveness_probe:
containers_liveness_probe += 1
if readiness_probe:
containers_readiness_probe += 1
if resources:
containers_resources += 1
Loop de Inspeção de Especificações:
Este é o coração da auditoria. Para cada container, verificamos três configurações críticas:
Liveness Probe:
Readiness Probe:
Resources (limits/requests):
Princípio PEP-20 “Simple is better than complex”:
Estruturas condicionais diretas tornam a lógica clara e fácil de entender.
total_containers = len(containers)
status = pod.status.phase
if status in emojis:
emoji = emojis.get(status)
status = f'{emoji} {status}'
containers_status_result = f'{containers_ready}/{total_containers}'
Contagem Total:
len(containers) nos dá o número total de containers definidos no Pod.
Formatação Visual do Status:
Se o status do Pod está no dicionário emojis, adicionamos o emoji correspondente para visualização imediata.
Formato Ready:
containers_ready/total_containers mostra quantos containers estão prontos em relação ao total (ex: “2/3” significa que 1 container ainda não está pronto).
F-strings (PEP-498):
A sintaxe f'{emoji} {status}' é mais legível e performática que concatenação tradicional ou .format().
status_readiness_probe = False
status_liveness_probe = False
status_resources = False
if containers_readiness_probe == total_containers:
status_readiness_probe = True
if containers_liveness_probe == total_containers:
status_liveness_probe = True
if containers_resources == total_containers:
status_resources = True
Lógica de Validação:
Estas variáveis booleanas determinam se todos os containers do Pod têm as configurações necessárias:
True se 100% dos containers estiverem configuradosPor que isso é importante:
Em produção, não basta ter “alguns” containers configurados corretamente. A ausência de health checks ou resource limits em qualquer container pode causar falhas no Pod inteiro.
Princípio “Explicit is better than implicit”:
Inicializamos com False e explicitamente mudamos para True apenas quando a condição é satisfeita.
status_liveness_probe_view = emojis_status.get(status_liveness_probe)
status_readiness_probe_view = emojis_status.get(status_readiness_probe)
status_resources_view = emojis_status.get(status_resources)
Mapeamento Visual:
Convertemos os booleanos em emojis usando o dicionário emojis_status:
True → 🟢 (configurado corretamente)False → 🔴 (configuração ausente)Benefício UX:
Em uma tabela com centenas de Pods, os emojis permitem identificar problemas instantaneamente sem ler texto.
row = [
namespace,
name,
status,
containers_status_result,
status_liveness_probe_view,
status_readiness_probe_view,
status_resources_view
]
result.append(row)
Estrutura de Dados:
Cada linha contém exatamente 7 elementos na ordem:
Append à Lista:
Adicionamos cada linha à lista result, construindo gradualmente a tabela completa.
Princípio de Organização:
A ordem dos elementos corresponde exatamente aos headers definidos no final, tornando o código previsível.
headers = ['Namespace', 'Nome', 'Status', 'READY', 'Liveness', 'Readiness', 'Resources']
print('')
print(tabulate(result, headers=headers, tablefmt='simple'))
Headers Descritivos:
Define os cabeçalhos das colunas de forma clara e profissional.
Biblioteca Tabulate:
tabulate() transforma automaticamente a lista de listas em uma tabela ASCII formatada com:
Formato ‘simple’:
Cria uma tabela limpa com linhas separadoras horizontais, ideal para terminais e logs.
Print Vazio Inicial:
O print('') adiciona uma linha em branco antes da tabela, melhorando a legibilidade no terminal.
Salve o código em um arquivo chamado k8s_pod_audit.py e execute:
python k8s_pod_audit.py
Namespace Nome Status READY Liveness Readiness Resources
------------- ------------------------------------- ---------- ------- --------- ---------- -----------
argocd argocd-server-76f9b87d6b-z6wh6 🟢 Running 1/1 🟢 🟢 🟢
cert-manager cert-manager-8484dc6898-flww9 🟢 Running 1/1 🟢 🟢 🔴
cp-tools postgres-contacts-787f8d6cd-pb5rg 🟢 Running 1/1 🟢 🔴 🔴
default nginx-error 🟡 Pending 0/1 🔴 🔴 🔴
istio-system istiod-74f575db47-k6j9r 🟢 Running 1/1 🟢 🟢 🟢
Pod Totalmente Saudável (argocd-server):
Pod com Problemas de Governança (cert-manager):
Pod com Múltiplos Problemas (postgres-contacts):
Pod em Estado Crítico (nginx-error):
Nomes de Variáveis Descritivos:
containers_ready = 0
containers_liveness_probe = 0
Ao invés de cr = 0 ou lp = 0, usamos nomes que documentam a intenção.
Snake_case para Variáveis e Funções:
containers_status_result
status_liveness_probe_view
O PEP-8 recomenda snake_case para variáveis e funções, melhorando a legibilidade.
Estruturas Condicionais Claras:
if status in emojis:
emoji = emojis.get(status)
status = f'{emoji} {status}'
Lógica simples e direta, fácil de entender e manter.
“Explicit is better than implicit”:
status_readiness_probe = False
if containers_readiness_probe == total_containers:
status_readiness_probe = True
Deixamos claro quando a validação passa, não assumimos valores implícitos.
“Readability counts”:
emojis = {
'Running': '🟢',
'Pending': '🟡'
}
Código que se lê como documentação, sem necessidade de comentários excessivos.
“Simple is better than complex”:
for container_status in containers_statuses:
ready = container_status.ready
if ready:
containers_ready += 1
Loop direto e compreensível, sem otimizações prematuras que sacrificam clareza.
“Flat is better than nested”: O código evita indentações excessivas, mantendo a lógica no mesmo nível sempre que possível.
from typing import Dict, List
def audit_pods() -> List[List[str]]:
result: List[List[str]] = []
# ... resto do código
return result
def count_ready_containers(containers_statuses) -> int:
return sum(1 for status in containers_statuses if status.ready)
def has_all_probes(containers, probe_type: str) -> bool:
return all(getattr(c, probe_type) for c in containers)
def audit_pods():
"""
Audita todos os Pods do cluster Kubernetes.
Verifica health checks, resource limits e estado dos containers.
Returns:
List[List[str]]: Dados formatados para exibição em tabela
"""
import json
with open('audit_result.json', 'w') as f:
json.dump(result, f, indent=2)
import sys
# Verifica se há problemas críticos
has_errors = any(row[4] == '🔴' or row[5] == '🔴' for row in result)
if has_errors:
print("❌ Problemas de configuração detectados!")
sys.exit(1) # Falha o pipeline
else:
print("✅ Todos os Pods estão configurados corretamente!")
sys.exit(0)
import sys
namespace_filter = sys.argv[1] if len(sys.argv) > 1 else None
if namespace_filter:
pods = v1.list_namespaced_pod(namespace_filter)
else:
pods = v1.list_pod_for_all_namespaces()
def send_alert(problems: List[str]) -> None:
import requests
webhook_url = "<https://hooks.slack.com/services/YOUR/WEBHOOK>"
message = f"⚠️ Problemas encontrados no cluster:\\n" + "\\n".join(problems)
requests.post(webhook_url, json={"text": message})
A união de Python para DevOps e a API do Kubernetes não é apenas uma tendência, mas o novo padrão para quem busca eficiência e controle total sobre a infraestrutura. O script que analisamos hoje demonstra como poucas linhas de código Python podem transformar tarefas complexas de auditoria em processos automatizados, confiáveis e visuais.
Você aprendeu a:
✅ Conectar-se automaticamente ao cluster Kubernetes usando suas credenciais existentes
✅ Consumir a API do Kubernetes de forma programática
✅ Auditar configurações críticas de health checks e resource limits
✅ Apresentar resultados de forma visual e profissional
✅ Seguir as melhores práticas do PEP-8 e PEP-20
O mais importante: você transformou uma operação reativa (descobrir problemas em produção) em uma operação proativa (identificar problemas antes que causem incidentes).
Este script é apenas o começo. Você pode expandi-lo para:
Python para DevOps é mais do que uma ferramenta, é uma mentalidade: automatize o máximo possível, valide continuamente, e deixe que o código trabalhe para você enquanto você foca em desafios mais estratégicos.
Agora é com você: qual será o próximo recurso do seu cluster que você automatizará com Python?