CRI-O no RHEL 10: como instalar, corrigir o erro do sandbox e testar com Nginx

Instale o CRI-O no RHEL 10 com CNI, crictl e o fix do systemd eBPF, depois valide com um Pod Nginx via JSON.

Escrito por
Emanuel Negromonte
Emanuel Negromonte é Jornalista, Mestre em Tecnologia da Informação e atualmente cursa a segunda graduação em Engenharia de Software. Com 14 anos de experiência escrevendo sobre...
Destaques
  • Instalação completa do CRI-O no RHEL 10, incluindo configuração do repositório upstream em /etc/yum.repos.d/cri-o.repo e ativação do serviço com systemctl.
  • Compatibilidade de versões sem erro: o tutorial reforça como alinhar CRIO_VERSION (ex.: v1.34) com a versão minor do Kubernetes para evitar incompatibilidades.
  • Rede de Pods funcionando de verdade: passo obrigatório de CNI Plugins com instalação em /opt/cni/bin e ativação do bridge em /etc/cni/net.d/.
  • Fix crítico do RHEL 10 (systemd eBPF): correção do problema de sandbox ajustando enable_devices = false em /etc/crio/crio.conf.d/ e restart do crio.
  • Validação prática com crictl: criação de Pod Sandbox e container Nginx via JSON, checagem de status, logs e teste de acesso via IP do Pod com curl.

O Docker deixou de ser o runtime padrão no Kubernetes, e isso acelerou a adoção de runtimes nativos de CRI. No RHEL 10, o CRI-O se encaixa muito bem nesse cenário por ser leve, OCI-compliant e focado exclusivamente no que o Kubernetes precisa.

A seguir você vai instalar o CRI-O no RHEL 10, adicionar os plugins CNI, aplicar o fix crítico de systemd eBPF, e validar tudo criando manualmente um Pod Sandbox e um container Nginx via crictl.

Arquitetura e conceitos (entenda em 90 segundos)

CRI (Container Runtime Interface) é a interface que o Kubernetes usa para falar com o runtime de containers. O CRI-O implementa essa interface e entrega apenas o necessário para o Kubernetes, por isso costuma ser mais enxuto que soluções genéricas.

OCI (Open Container Initiative) define padrões para imagens e runtime. O CRI-O é OCI-compliant, significa que ele segue esses padrões, facilitando interoperabilidade.

Um Pod Sandbox é a “casca” do Pod, onde entram namespace de rede e outras bases do isolamento. Para rede, o CRI-O usa plugins CNI, normalmente com binários em /opt/cni/bin e definições em /etc/cni/net.d/.

Pré-requisitos

  • Um sistema RHEL 10 em execução.
  • Usuário local com acesso sudo.
  • Assinatura Red Hat ativa (ou assinatura de desenvolvedor válida).
  • Conectividade com a internet.
  • Atenção: as versões do CRI-O devem corresponder à versão minor do Kubernetes.

Passo 1: Preparação do repositório e sistema

1.1 Defina a versão do CRI-O

Vamos usar a variável CRIO_VERSION para apontar o repo correto. Ajuste conforme a versão minor do Kubernetes do seu cluster.

CRIO_VERSION=v1.34

1.2 Crie o arquivo de repositório do CRI-O

Este passo grava o repo em /etc/yum.repos.d/cri-o.repo usando o repositório upstream da OpenSUSE.

cat <<EOF | sudo tee /etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/rpm/
enabled=1
gpgcheck=1
gpgkey=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/rpm/repodata/repomd.xml.key
EOF

1.3 SELinux em modo permissive (somente para validação inicial)

SELinux em permissive. Recomendado apenas para validação inicial; em produção, configure as políticas corretas.

sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

Passo 2: Instalação do CRI-O e plugins CNI

2.1 Instale o CRI-O

Com o repo configurado, instale o pacote e habilite o serviço no boot.

sudo dnf install cri-o -y
sudo systemctl start crio && sudo systemctl enable crio

Verifique se o serviço está ativo.

sudo systemctl status crio

2.2 Instale os plugins CNI

Sem CNI Plugins, o CRI-O não consegue criar e gerenciar redes de Pods. Agora vamos baixar o bundle de plugins e extrair em /opt/cni/bin.

Defina a versão e arquitetura usadas no exemplo.

CNI_VERSION="v1.6.0"
ARCH="amd64"
curl -LO "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-${ARCH}-${CNI_VERSION}.tgz"

Crie o diretório e extraia os binários.

sudo mkdir -p /opt/cni/bin
sudo tar -C /opt/cni/bin -xzf cni-plugins-linux-${ARCH}-${CNI_VERSION}.tgz

Ative o arquivo bridge do CRI-O (mova o arquivo .disabled).

sudo mv /etc/cni/net.d/10-crio-bridge.conflist.disabled /etc/cni/net.d/10-crio-bridge.conflist

Reinicie o serviço para aplicar as mudanças.

sudo systemctl restart crio

Passo 3: O fix crítico do RHEL 10 (eBPF)

Há um problema específico do RHEL 10: a criação do sandbox pode falhar por systemd eBPF device filtering. O ajuste recomendado é desabilitar enable_devices via um arquivo drop-in em /etc/crio/crio.conf.d/.

Crie o arquivo 99-disable-ebpf.conf:

sudo vi /etc/crio/crio.conf.d/99-disable-ebpf.conf

Conteúdo:

[crio.runtime]
enable_devices = false

Reinicie o CRI-O:

sudo systemctl restart crio

Passo 4: Ferramentas e validação (crictl)

4.1 Instale o cri-tools (crictl)

Recomendamos que a versão do crictl acompanhe a do CRI-O para evitar incompatibilidades. No exemplo, v1.34.0.

export VERSION="v1.34.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz

Extraia em /usr/local/bin e copie para /usr/bin.

sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
sudo cp /usr/local/bin/crictl /usr/bin/

Valide a versão e o endpoint do CRI-O:

sudo crictl --runtime-endpoint unix:///var/run/crio/crio.sock version
crictl --version

Verifique se Runtime e Network aparecem como Ready no crictl info (vamos inspecionar o final da saída):

sudo crictl info | tail -20

4.2 Teste prático: criando um Pod Sandbox e um container Nginx via JSON

Este teste valida o fluxo completo: criação do Pod Sandbox, pull de imagem e start de container. Ele também ajuda a isolar problemas de rede (CNI), permissões e runtime.

Crie o arquivo nginx-pod.json:

vi nginx-pod.json

Conteúdo:

{
  "metadata": {
    "name": "nginx-pod",
    "namespace": "default",
    "attempt": 1,
    "uid": "nginx-pod-uid"
  },
  "linux": {}
}

Crie o sandbox do Pod e capture o ID:

POD_ID=$(sudo crictl runp nginx-pod.json)

Liste os Pods:

sudo crictl pods

Crie o arquivo nginx-container.json:

vi nginx-container.json

Conteúdo:

{
  "metadata": {
    "name": "nginx"
  },
  "image": {
    "image": "docker.io/library/nginx:latest"
  },
  "log_path": "nginx.log",
  "linux": {
    "security_context": {
      "privileged": false
    }
  },
  "port_mappings": [
    {
      "container_port": 80,
      "protocol": "TCP"
    }
  ]
}

Crie o container dentro do Pod, com pull de imagem, e capture o ID:

CONTAINER_ID=$(sudo crictl create --with-pull $POD_ID nginx-container.json nginx-pod.json)

Inicie o container:

sudo crictl start $CONTAINER_ID

Confirme o estado:

sudo crictl ps

Veja logs do Nginx:

sudo crictl logs $CONTAINER_ID

Inspecione o Pod para obter o IP (no exemplo, vamos usar --output table e filtra o topo). Substitua o identificador pelo ID real que você tem.

sudo crictl inspectp --output table $POD_ID | head

Teste com curl contra o IP do Pod:

curl -I <IP_DO_POD>

Se o retorno HTTP aparecer, você validou que o sandbox, a rede CNI e o container estão operacionais.

4.3 Limpeza do ambiente de teste

Finalize o container e o Pod Sandbox:

sudo crictl stop $CONTAINER_ID
sudo crictl rm $CONTAINER_ID
sudo crictl stopp $POD_ID
sudo crictl rmp $POD_ID
Compartilhe este artigo