Fluentd DaemonSet no OKE ARM64: 8 erros em sequência até os logs chegarem no OCI Logging
Publicado em 17 de abril de 2026

O objetivo: pods Next.js → OCI Logging Service
Um cluster OKE (Oracle Kubernetes Engine) com nodes ARM64 (A1.Flex Ampere) precisava enviar os logs de erro dos pods de aplicação para o OCI Logging Service. A aplicação já emitia logs estruturados via stdout/stderr — o trabalho era capturar esses logs com Fluentd, filtrar pelos pods corretos e ingerir no OCI Logging via HTTPS autenticado por instance principal.
A arquitetura planejada era direta:
Pod (console.error → stdout/stderr)
→ CRI-O (grava em /var/log/containers/*.log)
→ Fluentd DaemonSet (tail + filter + match)
→ OCI Logging Service (via HTTPS, auth: instance principal)O que não estava no plano eram os 8 erros entre o kubectl apply e o primeiro log confirmado no OCI Logging.
Erro 1: imagem do OCI Container Registry exige autenticação
A documentação oficial do OCI Logging sugeria usar a imagem do próprio Oracle Container Registry:
container-registry.oracle.com/oci_logging/fluentbitAo tentar fazer pull desta imagem nos nodes OKE, o kubelet retornava erro de autenticação. O Oracle Container Registry requer login mesmo para imagens públicas — e configurar ImagePullSecrets para um registry externo em todos os nodes do cluster não era o caminho.
Fix: usar a imagem oficial do Fluent Bit no Docker Hub público, que não requer autenticação:
docker.io/fluent/fluent-bit:3.2Erro 2: CRI-O rejeita nomes de imagem curtos
Mesmo com a imagem trocada para fluent/fluent-bit:3.2, o kubelet rejeitava com:
short name mode is enforcing, but image name "fluent/fluent-bit:3.2"
returns ambiguous list of candidatesO Oracle Linux 8.10 que roda nos nodes OKE tem o CRI-O configurado em modo short name enforcing — todos os nomes de imagem precisam ser fully qualified com o registry explícito.
Fix: prefixar com docker.io/ em todos os nomes de imagem do manifest:
image: docker.io/fluent/fluent-bit:3.2Erro 3: Fluent Bit 3.2 não tem plugin oci_logging
Com o pod subindo, os logs mostravam que o Fluent Bit não conseguia carregar o output plugin necessário para enviar ao OCI Logging Service. O plugin oci_logging não existe no Fluent Bit — ele existe apenas na gem Ruby do Fluentd.
Fix: migrar de Fluent Bit para Fluentd com a gem fluent-plugin-oci-logging. Isso exigiu construir uma imagem customizada baseada no Fluentd oficial:
FROM docker.io/fluent/fluentd:v1.17-debian-1
# gems instaladas nas próximas etapas...Erro 4: build falhou — sem toolchain na imagem base
A imagem base do Fluentd (debian) não inclui compilador C. A instalação da gem fluent-plugin-oci-logging falhou na etapa de compilação de extensões nativas:
make: g++: No such file or directory
make[1]: *** [Makefile:234: <target>.o] Error 127Fix: adicionar build-essential no Dockerfile antes da instalação das gems:
FROM docker.io/fluent/fluentd:v1.17-debian-1
USER root
RUN apt-get update && apt-get install -y build-essential && rm -rf /var/lib/apt/lists/*
RUN gem install fluent-plugin-oci-logging fluent-plugin-kubernetes_metadata_filter fluent-plugin-parser-criErro 5: File.exists? removido no Ruby 3.2
Com as gems instaladas, o pod iniciava mas quebrava imediatamente com:
NoMethodError: undefined method 'exists?' for File:Class
/usr/local/bundle/gems/fluent-plugin-oci-logging-1.0.12/lib/fluent/plugin/os.rbO método File.exists? foi removido no Ruby 3.2 (deprecated desde Ruby 2.1). A gem fluent-plugin-oci-logging versão 1.0.12 ainda usava o método antigo e não havia sido atualizada.
Fix: patch inline no Dockerfile via sed:
RUN sed -i 's/File\.exists?/File.exist?/g' /usr/local/bundle/gems/fluent-plugin-oci-logging-*/lib/fluent/plugin/os.rbVerificar em versões futuras da gem se File.exists? já foi corrigido upstream. O patch é necessário enquanto a gem não for atualizada.
Erro 6: Permission denied ao criar diretório de buffer
Pod subindo, gems funcionando — mas o Fluentd travava na inicialização com:
Permission denied @ dir_s_mkdir - /var/log/fluentd-buffersO DaemonSet estava configurado para rodar com o usuário padrão do Fluentd (não-root). O diretório /var/log no host pertence ao root e o usuário fluent não tinha permissão de escrita.
Fix: adicionar securityContext: runAsUser: 0 no DaemonSet e mover o buffer para /tmp/fluentd-buffers/:
spec:
template:
spec:
securityContext:
runAsUser: 0
containers:
- name: fluentd
# ...
# no fluent.conf:
# <buffer>
# path /tmp/fluentd-buffers/
# </buffer>Nota: DaemonSets de coleta de logs que precisam ler /var/log/containers/ no host tipicamente precisam rodar como root. Isso é esperado e documentado para coletores de log como Fluentd e Fluentbit.
Erro 7: 404 na ingestão — Dynamic Group com OCID errado
Com o pod rodando e sem erros de permissão, as tentativas de ingestão no OCI Logging falhavam com:
NOT_AUTHORIZED_OR_NOT_FOUND (404) - Authorization failed or resource not foundO Fluentd usava autenticação por instance principal — os nodes OKE precisam estar em um Dynamic Group com política de acesso ao OCI Logging. O Dynamic Group havia sido criado com a seguinte regra:
# Rule incorreta — usa tag que não existe nos nodes OKE
All {tag.Oracle-Tags.CreatedBy.value = '<ocid-do-cluster>'}O problema: a tag Oracle-Tags.CreatedBy nos nodes OKE contém o OCID do nodepool, não do cluster. Nodes de clusters diferentes no mesmo compartment compartilham o mesmo OCID de cluster — mas os OCIDs de nodepool são únicos. Usar o OCID errado fazia o Dynamic Group não reconhecer os nodes.
Fix — opção mais simples e robusta: usar instance.compartment.id em vez de tags:
# Rule correta — todos os nodes do compartment
All {instance.compartment.id = '<ocid-do-compartment>'}Usar instance.compartment.id é mais simples e mais robusto que depender de tags de nodepool. Se o cluster for recriado ou o nodepool substituído, a regra continua válida. A desvantagem é a granularidade: todos os nodes do compartment entram no grupo — avaliar se isso é aceitável no ambiente.
Erro 8: bloco <auth> no config quebra a autenticação
Após corrigir o Dynamic Group, os logs de ingestão mostravam warnings sobre o bloco de autenticação no fluent.conf:
[warn]: #0 unknown parameter 'auth' in <match>O plugin fluent-plugin-oci-logging usa auto-detection do tipo de autenticação — ele detecta automaticamente se está rodando em uma instância OCI e usa instance principal. Adicionar um bloco <auth> explícito não só é desnecessário como interfere na autenticação automática.
Fix: remover completamente o bloco <auth> do fluent.conf. O plugin cuida da autenticação automaticamente via instance principal.
<match kubernetes.**>
@type oci_logging
log_object_id <ocid-do-log>
# <auth> — NÃO adicionar. O plugin usa auto-detection.
</match>Resultado: DaemonSet Running, primeiro log em 11 segundos
Após resolver os 8 erros em sequência, o DaemonSet subiu nos 2 nodes ARM64 do cluster sem restart:
kubectl get pods -n logging
# fluentd-a1b2c 1/1 Running 0 5m
# fluentd-d3e4f 1/1 Running 0 5mO primeiro log confirmado no OCI Logging chegou 11 segundos após o pod ficar Running — exatamente o flush_interval de 10 segundos configurado no fluent.conf mais a latência de rede.
# Primeiro log ingerido:
{
"timestamp": "2026-04-16T18:21:23Z",
"message": "Error: Loading chunk failed.",
"stream": "stderr"
}
# Ingerido em: 2026-04-16T18:21:34Z (+11s)Resumo dos 8 erros e fixes
1. Registry requer auth → usar docker.io/fluent/fluentd:v1.17-debian-1 (Docker Hub público)
2. CRI-O rejeita short names → prefixar todos os nomes de imagem com docker.io/
3. Fluent Bit não tem oci_logging → migrar para Fluentd + gem fluent-plugin-oci-logging
4. Build sem toolchain → adicionar build-essential no Dockerfile
5. File.exists? removido no Ruby 3.2 → patch sed no Dockerfile
6. Permission denied no buffer → runAsUser: 0 + buffer em /tmp/fluentd-buffers/
7. Dynamic Group com OCID errado → usar instance.compartment.id em vez de tag de cluster/nodepool
8. Bloco <auth> interfere na autenticação → remover — plugin usa auto-detection de instance principal


