Windows nodes no Kubernetes: rodando containers Windows

1. Introdução ao Kubernetes com Windows Nodes

O Kubernetes foi projetado originalmente para ambientes Linux, mas a necessidade de executar cargas de trabalho Windows em clusters Kubernetes cresceu significativamente. Muitas organizações possuem aplicações .NET Framework legadas, SQL Server, ou serviços que dependem de bibliotecas nativas Windows e não podem ser containerizadas em Linux.

A motivação principal para adotar Windows nodes no Kubernetes é a possibilidade de unificar a orquestração de containers, mantendo aplicações Windows e Linux no mesmo cluster, simplificando a infraestrutura e reduzindo custos operacionais.

Diferenças fundamentais entre Linux e Windows nodes:

  • Kernel: Containers Windows compartilham o kernel do Windows Server, enquanto containers Linux usam o kernel Linux. Isso impacta diretamente a compatibilidade de aplicações.
  • Runtime: O Docker e o containerd suportam Windows, mas exigem configurações específicas. O containerd com suporte a Windows é o runtime recomendado para clusters modernos.
  • Arquitetura: O control plane (plano de controle) deve rodar em Linux, enquanto os worker nodes podem ser Windows. Não é possível ter um control plane puramente Windows.

2. Pré-requisitos e Configuração do Ambiente

Para adicionar um Windows node ao cluster, os seguintes requisitos devem ser atendidos:

Hardware e Sistema Operacional:
- Windows Server 2019 (build 1809) ou Windows Server 2022 (build 20348)
- Licenciamento adequado (Windows Server Datacenter ou Standard com licenças por core)
- Atualizações do sistema operacional aplicadas (KB5005039 ou superior para Windows Server 2019)

Instalação do Runtime:
O containerd com suporte a Windows é o runtime mais utilizado. A instalação pode ser feita via script PowerShell:

# Instalar containerd no Windows Server
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/containerd/containerd/releases/download/v1.7.0/containerd-1.7.0-windows-amd64.tar.gz" -OutFile "containerd.tar.gz"
tar -xzf containerd.tar.gz
.\bin\containerd.exe --register-service
Start-Service containerd

Configuração de Rede:
Os CNI plugins compatíveis com Windows incluem:
- Flannel com VXLAN: Configuração mais simples, mas com desempenho inferior
- Calico para Windows: Suporte a políticas de rede avançadas e melhor desempenho

Preparação do Cluster:
O control plane Linux deve estar rodando Kubernetes 1.24 ou superior. Para garantir que apenas workloads Windows sejam agendadas nos nodes Windows, use taints:

kubectl taint nodes <windows-node> os=windows:NoSchedule

3. Adicionando um Windows Node ao Cluster

O processo de join para Windows nodes difere do Linux. Utilize o script kubeadm join.ps1 gerado pelo control plane:

# No Windows node, execute como Administrador
kubeadm join <control-plane-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> --cri-socket npipe://./pipe/containerd-containerd

Configuração do kubelet no Windows:
O kubelet requer parâmetros especiais para identificar o node como Windows:

kubelet.exe --windows-service --node-labels="kubernetes.io/os=windows" --register-with-taints="os=windows:NoSchedule" --cri-socket npipe://./pipe/containerd-containerd

Verificação da saúde do node:

kubectl get nodes
kubectl describe node <windows-node>

No Windows, verifique os logs do kubelet em C:\var\log\kubelet e o status do serviço com Get-Service kubelet.

4. Construindo e Gerenciando Containers Windows

Imagens de base Windows:
- Windows Server Core: ~3.4 GB, compatível com a maioria das aplicações .NET Framework e IIS
- Nano Server: ~300 MB, ideal para aplicações leves e .NET Core
- Windows: ~4.5 GB, imagem completa para cenários específicos

Dockerfile para containers Windows:

FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]
RUN Add-WindowsFeature Web-Server, Web-ASP-Net45
WORKDIR C:\inetpub\wwwroot
COPY app\ .
EXPOSE 80
CMD ["powershell", "-Command", "Start-Service W3SVC; while ($true) { Start-Sleep -Seconds 3600 }"]

Limitações importantes:
- Sem suporte a privileged: true
- hostNetwork não funciona em containers Windows
- hostPID e hostIPC não são suportados
- SecurityContext tem funcionalidade reduzida

5. Scheduling e Tolerations para Workloads Windows

Para garantir que pods Windows sejam agendados corretamente, use nodeSelector:

apiVersion: v1
kind: Pod
metadata:
  name: windows-app
spec:
  nodeSelector:
    kubernetes.io/os: windows
  tolerations:
  - key: "os"
    operator: "Equal"
    value: "windows"
    effect: "NoSchedule"
  containers:
  - name: windows-container
    image: mcr.microsoft.com/windows/servercore:ltsc2022

Labels adicionais úteis:
- beta.kubernetes.io/os: windows (deprecated, mas ainda usado)
- node.kubernetes.io/windows-build: 10.0.20348 (para identificar a build específica)

Evitando conflitos:
Sempre adicione taints nos nodes Windows e tolerations nos pods Windows. Para pods Linux, use nodeSelector: kubernetes.io/os: linux para evitar que sejam agendados em nodes Windows.

6. Exemplo Prático: Deploy de uma Aplicação Windows

Deployment de um servidor ASP.NET:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aspnet-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: aspnet
  template:
    metadata:
      labels:
        app: aspnet
    spec:
      nodeSelector:
        kubernetes.io/os: windows
      tolerations:
      - key: "os"
        operator: "Equal"
        value: "windows"
        effect: "NoSchedule"
      containers:
      - name: aspnet
        image: mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2022
        ports:
        - containerPort: 80
        volumeMounts:
        - name: app-data
          mountPath: C:\data
      volumes:
      - name: app-data
        emptyDir: {}

Service para expor a aplicação:

apiVersion: v1
kind: Service
metadata:
  name: aspnet-service
spec:
  selector:
    app: aspnet
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer

Monitoramento:
Para logs, use kubectl logs <pod> normalmente. No Windows, você também pode acessar o Event Viewer diretamente no node. Para métricas, configure o Prometheus com o Windows Exporter.

7. Limitações e Boas Práticas

Funcionalidades não suportadas:
- DaemonSets com hostPID ou hostNetwork
- SecurityContext com runAsUser, runAsGroup, capabilities
- readinessProbe e livenessProbe com comandos executados no host
- Volumes hostPath com tipos específicos

Gerenciamento de atualizações:
Planeje janelas de manutenção para aplicar patches do Windows Server. Use kubectl drain para drenar o node antes de reiniciar:

kubectl drain <windows-node> --ignore-daemonsets --delete-emptydir-data

Estratégias de backup:
- Faça backup do etcd regularmente
- Para volumes persistentes, utilize StorageClass compatível com Windows (Azure Disk/File, SMB)
- Documente a build específica do Windows Server para facilitar a recriação de nodes

Considerações de desempenho:
Imagens Windows são significativamente maiores que as Linux, impactando o tempo de pull e o armazenamento. Considere usar Nano Server sempre que possível e mantenha um registry local para acelerar deploys.

8. Troubleshooting e Depuração

Problemas comuns:

  1. Falha ao puxar imagem: Verifique se a imagem é compatível com a build do Windows Server. Use kubectl describe pod para ver o erro exato.

  2. Erro de runtime: Confirme se o containerd está configurado corretamente com suporte a Windows.

  3. Incompatibilidade de versão: A build do Windows Server no node deve corresponder à build da imagem de base.

Comandos de diagnóstico:

kubectl describe node <windows-node>
kubectl logs <pod>
kubectl exec -it <pod> -- powershell

Logs do sistema no Windows:
- Event Viewer: Event Viewer -> Windows Logs -> System
- Logs do kubelet: C:\var\log\kubelet
- Logs do containerd: C:\ProgramData\containerd\logs

Resolução de problemas de rede:
Verifique a conectividade entre pods Windows e Linux com kubectl exec. Teste o CNI plugin com:

kubectl exec -it <pod> -- powershell Test-NetConnection <ip-do-outro-pod> -Port 80

Referências