Skip to main content

Container Network Interface

Até o momento, exploramos como os network namespaces funcionam, como conectar vários desses namespaces em uma rede de bridge, como criar pares (cabos virtuais) com interfaces virtuais, como anexar cada extremidade ao namespace e à bridge, como atribuir IP e trazê-los à tona, e como habilitar o NAT ou IP mascarado para comunicação externa.

Observamos também como o Docker segue um processo semelhante, mas usando padrões de nomenclatura diferentes. Outras soluções de contêineres resolvem seus desafios de rede de maneira semelhante, incluindo o Kubernetes.

Todas essas soluções tentam resolver os mesmos problemas de forma diferente, mas acabam seguindo os mesmos passos. Por que não criar uma abordagem padrão única?

Foi nesse cenário que surgiu o programa Bridge, que encapsula todos os passos necessários para conectar um contêiner a uma rede de bridge.

Usando um simples comando como:

bridge add 2353245 /var/run/netns/2353245

O container runtime fica liberado da responsabilidade de implementar essa tarefa. Por exemplo, se um runtime de contêiner invocar o bridge passando os seguintes parâmetros bridge add <container_id> <namespace>, isso seria suficiente.

Se você quisesse criar um programa desse tipo para si mesmo, talvez para um novo tipo de rede, quais argumentos e comandos deveria passar? Como garantiria que o programa funcionasse corretamente com os runtimes existentes? Como ter certeza de que runtimes de contêineres como Kubernetes ou rkt invocariam seu programa corretamente? É aqui que a definição de padrões se torna crucial.

A CNI é um conjunto de padrões que define como os programas devem ser desenvolvidos para resolver os desafios de rede em um ambiente de runtime de contêiner.

Os programas são chamados de plugins. Neste caso, o programa Bridge ao qual nos referimos é um plugin para a CNI. A CNI define como o plugin deve ser desenvolvido e como os runtimes de contêineres devem invocá-los.

A CNI atribui um conjunto de responsabilidades tanto aos runtimes de contêineres quanto aos plugins. Para os runtimes de contêineres, a CNI especifica que eles são responsáveis por criar um namespace de rede para cada contêiner. Em seguida, os runtimes devem identificar as redes às quais os contêineres devem se conectar e invocar os plugins durante a criação (add) e exclusão (del) dos contêineres. Além disso, a CNI estipula a configuração dos plugins no ambiente do runtime de contêineres usando um arquivo JSON.

Por sua vez, os plugins devem suportar argumentos de linha de comando como add, del e check, aceitando parâmetros como o namespace de rede. Eles também são responsáveis pela atribuição de endereços IP aos contêineres, pela configuração de rotas necessárias para a comunicação entre contêineres na rede e pela especificação dos resultados em um formato particular. Desde que tanto os runtimes de contêineres quanto os plugins cumpram essas diretrizes, eles podem coexistir harmonicamente.

A CNI inclui um conjunto de plugins suportados, como Bridge, VLAN, IP VLAN, MAC VLAN, WINDOWS, Host Local e DHCP. Além disso, há outros plugins disponíveis de terceiros, como Weave, Flannel, Cilium, VMware NXC, Calico, entre outros. Todos esses implementam as normas da CNI, permitindo que qualquer runtime de contêiner trabalhe com qualquer um desses plugins.

No entanto, o Docker não implementa a CNI, mas sim o CNM (Container Network Model), que representa o modelo de rede de contêineres. O CNM é outro padrão que visa resolver desafios de rede de contêineres semelhantes à CNI, mas com algumas diferenças. Devido a essas diferenças, os plugins CNI não se integram nativamente ao Docker. Isso significa que você não pode executar um contêiner Docker e especificar o plugin de rede para usar um CNI e especificar um desses plugins. Mas isso não significa que você não possa usar o Docker com CNI de forma alguma. Basta trabalhar em torno disso, como criando um contêiner Docker sem nenhuma configuração de rede e depois invocando manualmente o plugin da bridge. Isso é praticamente o que o Kubernetes faz quando cria contêineres Docker: ele os cria sem rede e então invoca os plugins CNI configurados que cuidam do resto da configuração.