ARM support: Kubernetes em Raspberry Pi e dispositivos embarcados

1. Introdução ao Kubernetes em Arquitetura ARM

O ecossistema de dispositivos ARM experimentou crescimento exponencial nos últimos anos. Raspberry Pi, NVIDIA Jetson, Rockchip e outras plataformas baseadas em ARM tornaram-se protagonistas no cenário de edge computing, IoT e clusters de baixo custo. Para profissionais de DevOps, a capacidade de orquestrar containers nesses dispositivos representa uma fronteira estratégica.

Os desafios são significativos: diferenças entre ARMv7 (32 bits) e ARM64 (64 bits), recursos limitados de CPU e memória, e a necessidade de imagens de container compatíveis. No entanto, os benefícios justificam o esforço — orquestração leve, resiliência em borda de rede, automação de deploys e redução de custos operacionais.

Kubernetes em dispositivos embarcados permite criar clusters heterogêneos, onde nós ARM e x86 coexistem, processando dados localmente antes de enviá-los para a nuvem. É a base para arquiteturas híbridas e soluções de IoT em escala.

2. Preparação do Ambiente: Hardware e Sistema Operacional

Para um cluster ARM funcional, recomenda-se:

  • Hardware mínimo: Raspberry Pi 4 (4 GB RAM) ou superior, SSD via USB para armazenamento, fonte estável (5V/3A).
  • Sistema operacional: Raspberry Pi OS 64-bit (base Debian), Ubuntu Server ARM, ou Alpine Linux (extremamente leve).

Configuração inicial:

# Atualizar sistema e instalar dependências
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ufw

# Configurar hostname e rede estática
sudo hostnamectl set-hostname k8s-master
echo "192.168.1.100 k8s-master" | sudo tee -a /etc/hosts

# Habilitar cgroups no boot (essencial para Kubernetes)
echo " cgroup_memory=1 cgroup_enable=memory" | sudo tee -a /boot/cmdline.txt

Para armazenamento persistente, prefira SSDs via USB 3.0. Cartões SD são propensos a falhas em clusters com alta taxa de escrita.

3. Instalação do Kubernetes em Clusters ARM

k3s é a distribuição Kubernetes mais adequada para ARM — leve, otimizada e com binários nativos.

Cluster single-node (master + worker):

# No nó master
curl -sfL https://get.k3s.io | sh -
sudo k3s kubectl get nodes

Cluster multi-node:

# No master, obter token
sudo cat /var/lib/rancher/k3s/server/node-token
# Exemplo: K10...token...ab12

# Em cada worker
curl -sfL https://get.k3s.io | K3S_URL=https://192.168.1.100:6443 \
  K3S_TOKEN=K10...token...ab12 sh -

Verificar nós com labels de arquitetura:

kubectl get nodes -o wide
kubectl describe node k8s-worker1 | grep architecture
# Saída: kubernetes.io/arch=arm64

Para clusters heterogêneos, use nodeSelector ou taints para direcionar workloads específicas.

4. Docker e Container Images para ARM

Construir imagens multi-arquitetura com docker buildx é essencial.

Criar e usar builder multi-arch:

# Criar builder
docker buildx create --name armbuilder --use
docker buildx inspect --bootstrap

# Construir e push para Docker Hub
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 \
  -t seuuser/app-arm:latest --push .

Estratégias de pull:

  • Imagens nativas ARM: Prefira imagens oficiais com suporte ARM (nginx:alpine, postgres:13-arm64).
  • Emulação via QEMU: Último recurso. Configure binfmt_misc no host:
docker run --privileged --rm tonistiigi/binfmt --install all

Verificar compatibilidade de imagem:

docker manifest inspect nginx:alpine | grep architecture

5. Gerenciamento de Recursos e Limitações

Dispositivos embarcados exigem gestão rigorosa de recursos.

Definir limites em deployments:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-edge
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: app
        image: seuuser/app-arm:latest
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

Storage leve: Para clusters ARM, hostPath ou NFS são práticos. Para soluções mais robustas, Longhorn oferece suporte ARM64.

# PVC com hostPath (apenas para testes)
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-local
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  hostPath:
    path: /data/k8s

Networking: Flannel (modo VXLAN) funciona bem. Calico em modo host-gw reduz overhead. Para eBPF, Cilium tem suporte experimental em ARM64.

6. Observabilidade e Monitoramento em Clusters ARM

Monitoramento leve é crucial.

Prometheus + Node Exporter (versões ARM):

# Node Exporter via DaemonSet
kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/nodeExporter-daemonset.yaml

Ferramentas de dashboard:

  • K9s (terminal): Leve, ideal para SSH em dispositivos ARM.
  • Grafana: Suporte ARM64 nativo, use painéis pré-configurados.

Health checks para pods em hardware limitado:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3
readinessProbe:
  exec:
    command:
    - cat
    - /tmp/ready
  initialDelaySeconds: 5

7. Casos de Uso e Aplicações Práticas

Edge computing com processamento de sensores:

# Deployment de gateway IoT
apiVersion: apps/v1
kind: Deployment
metadata:
  name: iot-gateway
spec:
  replicas: 1
  selector:
    matchLabels:
      app: iot-gateway
  template:
    metadata:
      labels:
        app: iot-gateway
    spec:
      nodeSelector:
        kubernetes.io/arch: arm64
      containers:
      - name: mqtt-broker
        image: eclipse-mosquitto:arm64
        ports:
        - containerPort: 1883

Banco de dados leve (SQLite em cluster single-node):

kubectl run sqlite-pod --image=alpine:arm64 -- sh -c "apk add sqlite && sqlite3 /data/db.sqlite"

CI/CD com GitHub Actions em runner ARM:

# workflow.yml
jobs:
  build:
    runs-on: [self-hosted, arm64]
    steps:
    - uses: actions/checkout@v4
    - name: Build Docker image
      run: docker build -t app-arm .

8. Troubleshooting e Boas Práticas

Problemas comuns e soluções:

Problema Causa provável Solução
Pod CrashLoopBackOff Imagem x86 em nó ARM Use nodeSelector ou imagem multi-arch
OOMKilled Limite de memória baixo Ajuste resources.limits.memory
Network timeout MTU incompatível Configure Flannel com MTU 1200

Segurança e otimizações:

  • Atualize firmware: sudo rpi-eeprom-update
  • Verifique cgroups v2: grep cgroup /proc/filesystems
  • Desabilite serviços desnecessários: sudo systemctl disable bluetooth hciuart
  • Use containerd em vez de Docker para redução de overhead:
# k3s já usa containerd por padrão
k3s ctr images ls

Boas práticas finais:

  • Sempre especifique nodeSelector com kubernetes.io/arch: arm64
  • Prefira imagens oficiais com tag explícita de arquitetura
  • Monitore uso de swap: desabilite em produção (sudo dphys-swapfile swapoff)
  • Teste workloads em staging ARM antes de produzir

Referências