Kured: Reboots Automáticos Seguros em Clusters Kubernetes

Manter um cluster Kubernetes actualizado é essencial para a segurança, mas reiniciar nodes manualmente causa tempo de inactividade e riscos operacionais. O Kured (KUbernetes REboot Daemon) resolve este problema ao coordenar reboots de forma automática e segura — drena workloads, aguarda a sua conclusão e reinicia um node de cada vez. Para PME que aplicam actualizações de segurança do kernel automaticamente via unattended-upgrades, o Kured é a peça que falta para fechar o ciclo sem intervenção manual.

O problema dos reboots em clusters Kubernetes

Em clusters Kubernetes, cada node é uma máquina (física ou virtual) que corre um sistema operativo Linux. Quando o kernel é actualizado — seja por unattended-upgrades no Debian/Ubuntu, dnf-automatic no Fedora/RHEL, ou manualmente — é necessário reiniciar o node para carregar o novo kernel. O problema é que um reboot abrupto mata todos os pods a correr nesse node.

Num cluster com 5 nodes e dezenas de workloads, reiniciar manualmente significa:

  • Marcar cada node como unschedulable (cordon)
  • Drenar workloads com kubectl drain, aguardando terminação graciosa
  • Reiniciar e verificar se o node volta a ficar Ready
  • Repetir para cada node, garantindo que não se reiniciam dois ao mesmo tempo

Este processo é moroso, repetitivo e propenso a erros. Em PME sem equipa dedicada de SRE, os reboots são frequentemente adiados — deixando nodes vulneráveis durante semanas ou meses.

⚠ Risco real: Um kernel não actualizado tem vulnerabilidades conhecidas (CVEs). Se um atacante explora uma dessas vulnerabilidades para obter acesso ao node, compromete não apenas esse node mas potencialmente todo o cluster — os pods a correr nesse node têm acesso ao daemon do Kubernetes.

O que é o Kured

O Kured é um daemonset de código aberto (licença Apache 2.0), mantido pela organização kubereboot no GitHub e aceite como projecto Sandbox da CNCF (Cloud Native Computing Foundation). Corre em cada node do cluster e coordena reboots de forma segura.

O fluxo de funcionamento do Kured é o seguinte:

  • 1. Detecção: Verifica periodicamente (a cada hora por defeito) a existência do ficheiro sentinel /var/run/reboot-required, criado pelo gestor de pacotes quando uma actualização exige reboot
  • 2. Bloqueio: Obtém um lock distribuído via anotação no daemonset — garante que só um node reinicia de cada vez
  • 3. Cordon e Drain: Marca o node como unschedulable e drena os pods graciosamente, respeitando PodDisruptionBudgets
  • 4. Reboot: Executa systemctl reboot no node
  • 5. Uncordon: Após o node voltar a ficar Ready, remove o cordon e liberta o lock

ℹ Ficheiro sentinel: O /var/run/reboot-required é criado automaticamente pelo unattended-upgrades no Debian/Ubuntu e por ferramentas equivalentes noutras distribuições quando uma actualização do kernel ou de bibliotecas críticas exige reinício. O Kured pode também usar um comando sentinel alternativo (ex.: needs-restarting --reboothint no RHEL).

Instalação e Configuração

Instalação com manifestos YAML

A forma mais simples de instalar o Kured é aplicar o manifesto combinado directamente do repositório oficial:

# Obter a versão mais recente
latest=$(curl -s https://api.github.com/repos/kubereboot/kured/releases | jq -r '.[0].tag_name')

# Aplicar o manifesto no cluster
kubectl apply -f "https://github.com/kubereboot/kured/releases/download/$latest/kured-$latest-combined.yaml"

Isto cria um daemonset no namespace kube-system que corre um pod do Kured em cada node.

Instalação com Helm

Para PME que usam Helm para gerir implantações, o Kured tem um chart oficial que simplifica a configuração:

# Adicionar o repositório Helm do Kured
helm repo add kubereboot https://kubereboot.github.io/charts
helm repo update

# Instalar com configuração por defeito
helm install kured kubereboot/kured -n kube-system

# Instalar com parâmetros personalizados
helm install kured kubereboot/kured -n kube-system \
  --set configuration.period=15m \
  --set configuration.startTime=2am \
  --set configuration.endTime=5am \
  --set configuration.timeZone=Europe/Lisbon

Parâmetros principais

A tabela seguinte resume os parâmetros mais importantes para configurar o Kured numa PME:

Parâmetro Defeito Descrição
–reboot-sentinel /var/run/reboot-required Caminho do ficheiro que indica necessidade de reboot
–period 1h Intervalo entre verificações do sentinel
–reboot-days todos os dias Dias da semana em que reboots são permitidos
–start-time / –end-time 0:00 / 23:59:59 Janela horária para reboots
–time-zone UTC Fuso horário para o agendamento
–drain-timeout 0 (infinito) Tempo máximo para drenar pods
–lock-ttl 0 (desactivado) Expira o lock após este tempo (segurança contra locks presos)
–concurrency 1 Número de nodes a reiniciar simultaneamente

Agendamento de reboots numa janela de manutenção

Para uma PME em Portugal, reboots automáticos devem ocorrer fora do horário comercial. O exemplo seguinte configura o Kured para reiniciar apenas de segunda a sexta, entre as 2h e as 5h, no fuso de Lisboa:

helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.rebootDays='mon,tue,wed,thu,fri' \
  --set configuration.startTime=2am \
  --set configuration.endTime=5am \
  --set configuration.timeZone=Europe/Lisbon \
  --set configuration.period=15m

ℹ Período de verificação: Ao usar uma janela horária restrita, convém reduzir o --period (ex.: 15m em vez de 1h) para que o Kured detecte o sentinel a tempo dentro da janela. Cada réplica usa um deslocamento aleatório derivado do período, evitando que todos os nodes disputem o lock ao mesmo tempo.

Integração com Prometheus e Alertmanager

O Kured expõe uma métrica Prometheus em :8080/metrics que indica se um node necessita de reboot:

# HELP kured_reboot_required OS requires reboot due to software updates.
# TYPE kured_reboot_required gauge
kured_reboot_required{node="worker-01"} 0
kured_reboot_required{node="worker-02"} 1

Um valor de 1 significa que o node precisa de reinício. Esta métrica permite criar um alerta no Alertmanager que funciona como rede de segurança — se o Kured não conseguir reiniciar um node durante 24 horas, alguém é notificado:

# Alerta Prometheus — reboot pendente há mais de 24h
ALERT RebootRequired
IF max(kured_reboot_required) != 0
FOR 24h
LABELS { severity = "warning" }
ANNOTATIONS {
  summary = "Node(s) precisam de reboot há mais de 24h",
  impact = "Nodes mais vulneráveis a exploits de segurança",
  description = "O Kured não conseguiu reiniciar um node automaticamente",
}

Para bloquear reboots quando existem alertas activos no Prometheus, basta fornecer o URL do servidor:

helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.prometheusUrl=http://prometheus.monitoring.svc.cluster.local \
  --set configuration.alertFilterRegexp=^RebootRequired$

⚠ Evitar deadlock: Se criar o alerta RebootRequired e configurar o Kured para bloquear reboots na presença de alertas activos, tem de usar --alert-filter-regexp=^RebootRequired$ para ignorar esse alerta específico. Sem este filtro, o Kured bloqueia o reboot porque o alerta está activo, e o alerta fica activo porque o Kured não reinicia — deadlock.

Outras opções úteis para integração com Prometheus:

  • --alert-firing-only=true — bloqueia apenas quando os alertas estão a disparar (firing), ignorando os pendentes
  • --alert-filter-match-only=true — inverte a lógica: apenas alertas que correspondem ao regexp bloqueiam o reboot
  • --metrics-port — altera a porta do endpoint de métricas (defeito: 8080)

Integração com Slack/Teams

O Kured pode enviar notificações para Slack, Microsoft Teams, RocketChat e e-mail via SMTP. A configuração usa o parâmetro --notify-url com o formato apropriado para cada plataforma.

Notificações para Slack

# Slack App Bot Token (formato actual)
helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.notifyUrl="slack://xoxb:123456789012-1234567890123-4mt0t4l1YL3g1T5L4cK70k3N@C0123ALERTAS?botname=kured-bot"

# Slack Incoming Webhook (formato legacy)
helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.notifyUrl="slack://tokenA/tokenB/tokenC"

Notificações para Microsoft Teams

# Microsoft Teams webhook
helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.notifyUrl="teams://group@tenant/altId/groupOwner?host=organization.webhook.office.com"

Personalização de mensagens

Os modelos de mensagem podem ser personalizados para incluir o nome do cluster ou região:

helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.messageTemplateDrain="A drenar node %s do cluster-produção" \
  --set configuration.messageTemplateReboot="A reiniciar node %s do cluster-produção" \
  --set configuration.messageTemplateUncordon="Node %s reiniciado com sucesso no cluster-produção"

Os modelos usam %s como marcador para o nome do node. O Kured envia três notificações por node: ao iniciar o drain, ao reiniciar e ao concluir o uncordon.

Boas Práticas para PME

1. Configurar unattended-upgrades antes do Kured

O Kured só funciona se o sistema operativo criar o ficheiro sentinel. No Debian/Ubuntu, confirme que o unattended-upgrades está activo e configurado para actualizar o kernel:

# Verificar que o unattended-upgrades está activo
sudo systemctl status unattended-upgrades.service

# Confirmar que o kernel é actualizado automaticamente
cat /etc/apt/apt.conf.d/50unattended-upgrades | grep -A5 Allowed-Origins

# Testar criação do sentinel manualmente
sudo touch /var/run/reboot-required

# Verificar que o Kured detecta e processa o reboot
kubectl -n kube-system logs -l app=kured --tail=20

2. Definir PodDisruptionBudgets

O drain do Kured respeita PodDisruptionBudgets (PDBs). Sem PDBs, o Kubernetes pode permitir que todos os pods de um serviço sejam terminados em simultâneo. Para workloads críticos, defina um PDB que garanta um mínimo de réplicas disponíveis:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-critical-pdb
  namespace: produção
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api-critical

3. Usar lock-ttl como rede de segurança

Se um node falha permanentemente enquanto detém o lock, o Kured fica bloqueado indefinidamente. Configurar --lock-ttl=30m permite que outros nodes assumam o lock após 30 minutos:

helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.lockTtl=30m

4. Bloquear reboots com pods sensíveis

Use --blocking-pod-selector para impedir o reboot de um node quando pods críticos estão a correr nele:

helm upgrade kured kubereboot/kured -n kube-system \
  --set configuration.blockingPodSelector={runtime=long,cost=expensive,name=critical-job}

5. Testar antes de confiar

Para verificar que o Kured está a funcionar correctamente, provoque um reboot manualmente num node de teste:

# Criar o ficheiro sentinel num node
sudo touch /var/run/reboot-required

# Acompanhar o processo no Kured
kubectl -n kube-system logs -l app=kured -f

# Verificar estado do node
kubectl get nodes -w

# Desactivar reboots temporariamente (se necessário)
kubectl -n kube-system annotate ds kured weave.works/kured-node-lock='{"nodeID":"manual"}'

# Libertar o lock manual
kubectl -n kube-system annotate ds kured weave.works/kured-node-lock-

ℹ Comando de teste: O kubectl annotate ds kured weave.works/kured-node-lock- (com o travessão no fim) remove a anotação completamente. O travessão é obrigatório — sem ele, o kubectl interpreta a string vazia como um valor e não remove a anotação.

Conclusão

O Kured preenche uma lacuna crítica na gestão de clusters Kubernetes: a automatização segura de reboots de nodes. Para PME que não têm equipas SRE dedicadas, é a forma mais simples de garantir que as actualizações de segurança do kernel são aplicadas atempadamente sem tempo de inactividade desnecessário.

A combinação de unattended-upgrades no sistema operativo com o Kured no Kubernetes cria um ciclo completo: o SO instala actualizações, cria o ficheiro sentinel, o Kured detecta-o e coordena o reboot — tudo sem intervenção humana. A integração com Prometheus e Alertmanager adiciona uma camada de visibilidade e a integração com Slack/Teams mantém a equipa informada.

Comece pela instalação sem defeitos, teste num node de desenvolvimento, defina uma janela de manutenção e adicione integração com Prometheus e notificações à medida que a confiança no sistema cresce.