Executar um cluster Kubernetes em produção é uma coisa. Executar um sistema que possa absorver picos de tráfego imprevisíveis, sobreviver a falhas no plano de controle, impor o isolamento dos locatários e dar à sua equipe de operações visibilidade clara de cada camada do sistema — esse é um desafio totalmente diferente. RKE2, a distribuição Kubernetes de próxima geração da Rancher, foi desenvolvida especificamente para ambientes onde esses requisitos não são negociáveis.
Este artigo aborda todo o ciclo de vida de uma implantação RKE2 de nível de produção: arquitetura de cluster inicial, escalonamento automático no nível do pod e do nó, planos de controle de alta disponibilidade, governança de recursos e observabilidade com Prometheus e Grafana.
Por que RKE2?
ORKE2 se distingue do upstream Kubernetes e de seu antecessor RKE1 em três áreas principais. Primeiro, ele vem com uma configuração CIS Kubernetes Benchmark pronta para uso: controladores de admissão, registro de auditoria, segurança de pod e configurações TLS são pré-configurados para passar em uma varredura CIS Nível 1 sem intervenção manual. Em segundo lugar, é compatível com FIPS 140-2, o que o torna adequado para implantações governamentais e em indústrias regulamentadas. Terceiro, ele incorpora o containerd diretamente e vem com seu próprio CNI (Canal ou Cilium dependendo da sua escolha de configuração), reduzindo a área de superfície de dependências externas que você precisa gerenciar.
ORKE2 também é compatível com air gap. O pacote de instalação inclui todas as imagens de contêiner necessárias, o que é extremamente importante em implantações locais e de borda, onde o acesso à Internet a partir de nós do cluster é restrito ou impossível.
Arquitetura de clusterUm cluster RKE2 de produção é dividido em nós de servidor (que executam o plano de controle e etcd) e nós de agente (que executam cargas de trabalho). A topologia recomendada para alta disponibilidade é de três ou cinco nós de servidor e um número variável de nós de agente organizados em pools de nós por classe de carga de trabalho.
# /etc/rancher/rke2/config.yaml (server node)
token: <shared-cluster-token>
tls-san:
- 10.0.0.10 # VIP or load balancer address
- k8s.internal.example.com
cni: cilium
cluster-cidr: 10.42.0.0/16
service-cidr: 10.43.0.0/16
etcd-expose-metrics: true
kube-apiserver-arg:
- "audit-log-path=/var/log/kubernetes/audit.log"
- "audit-log-maxage=30"
- "audit-log-maxsize=100"# /etc/rancher/rke2/config.yaml (agent node)
server: https://10.0.0.10:9345
token: <shared-cluster-token>
node-label:
- "workload-class=general"
- "topology.kubernetes.io/zone=eu-west-1a"Instale o servidor em seu primeiro nó do plano de controle e, em seguida, junte os nós restantes do servidor e todos os nós do agente usando o mesmo token e o endereço VIP. O RKE2 elege automaticamente os líderes do etcd e gerencia o quorum.
# Install and start RKE2 server
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE=server sh -
systemctl enable --now rke2-server.service
# Retrieve the node token for joining additional nodes
cat /var/lib/rancher/rke2/server/node-token
# Install and start RKE2 agent (on worker nodes)
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE=agent sh -
systemctl enable --now rke2-agent.servicePools de nóse posicionamento de carga de trabalho
Nem todas as cargas de trabalho possuem o mesmo perfil de recursos. Os serviços web sem estado têm requisitos diferentes dos trabalhos de inferência GPU, cargas de trabalho de análise com uso intensivo de memória ou bancos de dados sensíveis à latência. A organização de nós de agente em pools com rótulos e taints distintos permite que o Kubernetes agende cada classe de carga de trabalho em hardware de tamanho apropriado.
# Label a node pool for memory-intensive workloads
kubectl label nodes worker-mem-{1..4} workload-class=memory-optimised
kubectl taint nodes worker-mem-{1..4} workload-class=memory-optimised:NoSchedule
# Label a separate pool for general compute
kubectl label nodes worker-gen-{1..8} workload-class=general# Deployment targeting the memory-optimised pool
apiVersion: apps/v1
kind: Deployment
metadata:
name: analytics-engine
spec:
template:
spec:
nodeSelector:
workload-class: memory-optimised
tolerations:
- key: workload-class
operator: Equal
value: memory-optimised
effect: NoSchedule
containers:
- name: analytics
image: registry.internal/analytics:v2.3.1
resources:
requests:
memory: "8Gi"
cpu: "2"
limits:
memory: "16Gi"
cpu: "4"Escalonador automático de pod horizontalO Horizontal Pod Autoscaler (HPA) ajusta a contagem de réplicas de uma implantação ou StatefulSet com base nas métricas observadas. A utilização do CPU é o gatilho clássico, mas as configurações modernas do HPA também podem ser dimensionadas com base em métricas personalizadas expostas pelo seu aplicativo ou em métricas externas de fontes, como a profundidade da fila de mensagens.
Primeiro, certifique-se de que o Metrics Server esteja em execução — o RKE2 não o empacota por padrão.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlapiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-server-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # wait 5 minutes before scaling down
policies:
- type: Percent
value: 25
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 30O blocobehavioré fundamental para a estabilidade. Sem uma janela de estabilização reduzida, uma breve queda no tráfego removerá os pods prematuramente, deixando você subprovisionado quando a carga retornar. A política assimétrica — aumento agressivo, redução conservadora — é o padrão certo para a maioria das cargas de trabalho de produção.
O Vertical Pod Autoscaler (VPA) dimensiona corretamente o CPU e as solicitações de memória em pods individuais com base no uso observado. Ele resolve um problema comum: os desenvolvedores definem solicitações iniciais de recursos com base em suposições, e esses valores nunca são atualizados, levando a um provisionamento excessivo desnecessário ou a pods OOMKilled sob carga.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: worker-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: background-worker
updatePolicy:
updateMode: "Auto" # or "Off" to only view recommendations
resourcePolicy:
containerPolicies:
- containerName: worker
minAllowed:
cpu: 100m
memory: 256Mi
maxAllowed:
cpu: 4
memory: 8Gi
controlledResources: ["cpu", "memory"]Observe que o VPA no modoAutoremoverá e reiniciará os pods para aplicar novos valores de recursos. Para serviços em que as solicitações em andamento não podem ser interrompidas, execute o VPA no modoOffpara gerar recomendações que você aplica manualmente ou por meio de um fluxo de trabalho GitOps durante as janelas de manutenção.
Importante:HPA e VPA não devem gerenciar o mesmo recurso (CPU ou memória) na mesma implantação simultaneamente. Use HPA para dimensionamento horizontal orientado por CPU e VPA no modoOffpara dimensionamento correto da memória ou useKEDApara dimensionamento orientado a eventos onde o controle refinado é necessário.
funcionam dentro da capacidade existente do nó. Quando essa capacidade se esgota – os pods ficam presos noPendingporque nenhum nó tem recursos suficientes – você precisa do Cluster Autoscaler para provisionar novos nós. Por outro lado, quando os nós são significativamente subutilizados, o Cluster Autoscaler pode esvaziá-los e desativá-los para reduzir os custos de infraestrutura.
Em implantações bare-metal ou locais, o Cluster Autoscaler integra-se à sua camada de provisionamento de infraestrutura. Para implantações em nuvem, provedores como AWS, GCP e Azure oferecem integrações de grupos de nós nativos. O exemplo a seguir mostra a configuração principal de um grupo de Auto Scaling AWS.
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
template:
spec:
containers:
- name: cluster-autoscaler
image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.29.0
command:
- ./cluster-autoscaler
- --cloud-provider=aws
- --nodes=2:10:k8s-general-worker-asg
- --nodes=1:4:k8s-memory-worker-asg
- --scale-down-delay-after-add=10m
- --scale-down-unneeded-time=10m
- --scale-down-utilization-threshold=0.5
- --skip-nodes-with-local-storage=false
- --expander=least-waste
env:
- name: AWS_REGION
value: eu-west-1A opção--expander=least-wasteinforma ao escalonador automático para preferir o grupo de nós que teria a menor quantidade de recursos não utilizados após acomodar o pod pendente, o que minimiza o custo. Expansores alternativos incluemrandom,most-podsepriority.
Um plano de controle de três nós com etcd integrado é a topologia de HA mínima viável. etcd requer quorum – a maioria dos membros deve estar íntegra para que o cluster aceite gravações. Com três membros você pode tolerar um fracasso; com cinco membros você pode tolerar dois.
Os nós do plano de controle devem ficar atrás de um balanceador de carga. Para implantações em nuvem, um balanceador de carga TCP direcionado às portas 6443 (kube-apiserver) e 9345 (registro RKE2) funciona bem. As implantações locais geralmente usam keepalived com um endereço IP virtual.
# keepalived.conf on control-plane nodes
vrrp_instance VI_1 {
state MASTER # BACKUP on the other two nodes
interface eth0
virtual_router_id 51
priority 100 # 90 and 80 on the other two nodes
advert_int 1
authentication {
auth_type PASS
auth_pass securepassword
}
virtual_ipaddress {
10.0.0.10/24 # VIP used in tls-san and agent server address
}
}Valide se o etcd está íntegro após qualquer operação do plano de controle. RKE2 agrupaetcdctlem/var/lib/rancher/rke2/bin/etcdctl.
ETCDCTL_API=3 /var/lib/rancher/rke2/bin/etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
--cert=/var/lib/rancher/rke2/server/tls/etcd/client.crt \
--key=/var/lib/rancher/rke2/server/tls/etcd/client.key \
endpoint health --clusterCotas de recursos e intervalos de limitesEm clusters multilocatários — onde diferentes equipes ou aplicativos compartilham a mesma infraestrutura física — ResourceQuotas e LimitRanges são proteções essenciais. ResourceQuotas define limites rígidos para o consumo total de recursos em um namespace. LimitRanges definem valores padrão e máximos para contêineres individuais, evitando que uma implantação mal configurada solicite recursos ilimitados.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
count/deployments.apps: "20"
count/services: "15"
persistentvolumeclaims: "10"
requests.storage: 500GiapiVersion: v1
kind: LimitRange
metadata:
name: team-alpha-limits
namespace: team-alpha
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "8"
memory: 16Gi
- type: PersistentVolumeClaim
max:
storage: 100GiAplicar LimitRanges garante que os desenvolvedores que se esquecem de especificar solicitações de recursos ainda obtenham padrões sensatos em vez de solicitar zero CPU, o que faria com que o agendador colocasse o pod em qualquer lugar e potencialmente privasse outras cargas de trabalho no mesmo nó.
Monitoramentocom Prometheus e Grafana
A observabilidade doem um cluster Kubernetes tem três pilares: métricas, logs e rastreamentos. Prometheus lida com coleta de métricas; A Grafana cuida da visualização. O gráficokube-prometheus-stackHelm implanta toda a pilha — Operador Prometheus, Alert Manager, Grafana, exportadores de nós e um conjunto abrangente de painéis pré-construídos — em um único comando.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set prometheus.prometheusSpec.retention=30d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=longhorn \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=100Gi \
--set grafana.adminPassword=<secure-password> \
--set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.resources.requests.storage=10GiRKE2 expõe métricas etcd quandoetcd-expose-metrics: trueé definido na configuração do servidor. Adicione um ServiceMonitor para que o Prometheus os raspe.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: rke2-etcd
namespace: monitoring
labels:
release: kube-prometheus-stack
spec:
namespaceSelector:
matchNames: [kube-system]
selector:
matchLabels:
app.kubernetes.io/name: rke2-etcd
endpoints:
- port: metrics
scheme: https
tlsConfig:
caFile: /etc/prometheus/secrets/etcd-client-cert/ca.crt
certFile: /etc/prometheus/secrets/etcd-client-cert/client.crt
keyFile: /etc/prometheus/secrets/etcd-client-cert/client.keyRegras de alerta essenciaisPainéis pré-construídossão um ponto de partida, mas regras de alerta personalizadas ajustadas ao seu ambiente são o que permitem que os engenheiros de plantão ajam antes que os usuários percebam um problema.
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: workload-alerts
namespace: monitoring
labels:
release: kube-prometheus-stack
spec:
groups:
- name: pod-health
rules:
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[10m]) > 0.5
for: 5m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash-looping"
- alert: NodeMemoryPressure
expr: |
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.1
for: 2m
labels:
severity: warning
annotations:
summary: "Node {{ $labels.node }} memory below 10%"
- alert: HPAMaxedOut
expr: |
kube_horizontalpodautoscaler_status_current_replicas
== kube_horizontalpodautoscaler_spec_max_replicas
for: 15m
labels:
severity: warning
annotations:
summary: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} at maximum replicas"O alertaHPAMaxedOuté particularmente valioso na prática. Quando um HPA é fixado no máximo por um longo período, significa que o tráfego ultrapassou o limite atual. Você precisa aumentar o máximo ou adicionar capacidade ao pool de nós – e deseja saber sobre isso antes do próximo pico, não durante ele.
Um PodDisruptionBudget (PDB) restringe quantos pods em uma implantação podem estar simultaneamente indisponíveis durante interrupções voluntárias, como drenagem de nós. Sem PDBs, drenar um nó para manutenção pode deixar toda uma implantação off-line.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-server-pdb
namespace: production
spec:
minAvailable: 2 # or use maxUnavailable: 1
selector:
matchLabels:
app: api-serverRestrições de propagação da topologiaPor padrão, o agendador espalha réplicas entre nós usando um algoritmo de melhor esforço. As restrições de distribuição de topologia oferecem garantias concretas de que as réplicas serão distribuídas entre zonas de disponibilidade ou racks.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: api-serverEstratégia de atualizaçãoORKE2 suporta atualizações contínuas por meio do Controlador de atualização do sistema. Você define um Plano direcionado a nós de servidor ou agente e especifica a versão de destino; o controlador drena, atualiza e desconecta os nós sequencialmente.
apiVersion: upgrade.cattle.io/v1
kind: Plan
metadata:
name: rke2-server-upgrade
namespace: system-upgrade
spec:
concurrency: 1
cordon: true
nodeSelector:
matchExpressions:
- { key: node-role.kubernetes.io/control-plane, operator: In, values: ["true"] }
serviceAccountName: system-upgrade
upgrade:
image: rancher/rke2-upgrade
version: v1.29.4+rke2r1etcd Backup e restauração
ORKE2 pode tirar instantâneos agendados do etcd automaticamente. Certifique-se de que eles sejam gravados em armazenamento durável fora do cluster (um bucket S3 ou uma montagem NFS remota) em vez de um disco local nos nós do plano de controle.
# /etc/rancher/rke2/config.yaml additions for automated snapshots
etcd-snapshot-schedule-cron: "0 */6 * * *" # every 6 hours
etcd-snapshot-retention: 10
etcd-snapshot-dir: /mnt/nfs/etcd-snapshots
# Manual snapshot
rke2 etcd-snapshot save --name pre-upgrade-$(date +%Y%m%d)
# Restore from snapshot (run on a single server node with cluster stopped)
rke2 server --cluster-reset --cluster-reset-restore-path=/path/to/snapshot.dbConclusãoO dimensionamento da infraestrutura com RKE2 não é uma única mudança de configuração – é um sistema de recursos interligados que deve ser projetado e operado em conjunto. O escalonamento automático horizontal de pods lida com intermitências de tráfego de curta duração no nível da carga de trabalho. O escalonamento automático vertical de pods mantém as solicitações de recursos honestas ao longo do tempo. O Cluster Autoscaler garante que a capacidade do nó subjacente rastreie a demanda agregada dos seus pod autoscalers. Os pools de nós e as restrições de topologia garantem que as cargas de trabalho cheguem ao hardware certo. As cotas de recursos e os intervalos de limites protegem os locatários uns dos outros. PodDisruptionBudgets e restrições de distribuição de topologia aumentam a disponibilidade. E o Prometheus com Grafana dá à sua equipe a visibilidade para detectar a degradação antes que ela se transforme em uma interrupção.
ORKE2 ganha seu lugar na produção precisamente porque envia uma parte substancial dessa pilha pré-endurecida e pré-integrada. Sua responsabilidade é entender os botões, ajustá-los às características da sua carga de trabalho e criar a disciplina operacional — runbooks, roteamento de alertas, cadência de atualização, validação de backup — que transforma um cluster bem configurado em uma plataforma genuinamente confiável.