Por que Precisamos de Pods

Por que Precisamos de Pods

Sobre Pods

Pods são a menor unidade de API no Kubernetes. Em termos mais técnicos, Pods são a unidade atômica de agendamento no Kubernetes. Mas por que precisamos de Pods? Para responder a essa pergunta, precisamos primeiro entender a essência de um contêiner: um contêiner é essencialmente um processo. Isso mesmo. Contêineres são processos em um sistema de computação em nuvem, e imagens de contêiner são essencialmente pacotes de instalação “.exe” para esse sistema. Kubernetes, nessa analogia, atua como o sistema operacional.

Processos e Grupos de Processos

Vamos fazer login em uma máquina Linux e executar o seguinte comando:

$ pstree -g

Esse comando exibe a estrutura em árvore dos processos atualmente em execução no sistema. A saída pode ser algo como:

systemd(1)-+-accounts-daemon(1984)-+-{gdbus}(1984)
           | `-{gmain}(1984)
           |-acpid(2044)
          ...      
           |-lxcfs(1936)-+-{lxcfs}(1936)
           | `-{lxcfs}(1936)
           |-mdadm(2135)
           |-ntpd(2358)
           |-polkitd(2128)-+-{gdbus}(2128)
           | `-{gmain}(2128)
           |-rsyslogd(1632)-+-{in:imklog}(1632)
           |  |-{in:imuxsock) S 1(1632)
           | `-{rs:main Q:Reg}(1632)
           |-snapd(1942)-+-{snapd}(1942)
           |  |-{snapd}(1942)
           |  |-{snapd}(1942)
           |  |-{snapd}(1942)
           |  |-{snapd}(1942)

Como você pode ver, em um sistema operacional real, os processos não são executados isoladamente. Em vez disso, eles são organizados em grupos de processos. Por exemplo, o programa “rsyslogd” é responsável pelo processamento de logs no Linux. O programa principal do rsyslogd, “main”, e o módulo de log do kernel “imklog” que ele usa pertencem ao grupo de processos 1632. Esses processos colaboram para cumprir as responsabilidades do programa rsyslogd. O Kubernetes essencialmente mapeia esse conceito de “grupos de processos” para a tecnologia de contêineres e o torna um “cidadão de primeira classe” nesse “sistema operacional” de computação em nuvem. O Kubernetes adota essa abordagem porque os engenheiros do Google perceberam que os aplicativos que implantavam frequentemente exibiam relações semelhantes a “processos e grupos de processos”. Especificamente, esses aplicativos exigiam colaboração próxima, necessitando sua implantação na mesma máquina. Gerenciar tais relações operacionais sem o conceito de “grupos” seria incrivelmente desafiador. Tomemos o rsyslogd como exemplo. Ele consiste em três processos: um módulo imklog, um módulo imuxsock e a função principal do próprio rsyslogd. Esses três processos devem ser executados na mesma máquina; caso contrário, sua comunicação via sockets e troca de arquivos encontraria problemas.

Comunicação entre Contêineres

Como mostrado no diagrama acima, este Pod contém dois contêineres de usuário, A e B, e um contêiner Infra. No Kubernetes, o contêiner Infra é projetado para consumir recursos mínimos e utiliza uma imagem especial chamada “k8s.gcr.io/pause”. Essa imagem representa um contêiner, escrito em linguagem assembly, que permanece perpetuamente em um estado “pausado”, com tamanho não compactado de apenas 100–200 KB. Uma vez que o contêiner Infra “segura” o Namespace de Rede, os contêineres de usuário podem se juntar a esse namespace. Portanto, se você examinar os arquivos de Namespace desses contêineres na máquina host (o caminho para esse arquivo foi mencionado anteriormente), eles apontarão para o mesmo valor. Isso significa que, para os contêineres A e B dentro do Pod, eles podem se comunicar diretamente usando “localhost”. Eles percebem os mesmos dispositivos de rede que o contêiner Infra. Um Pod tem apenas um endereço IP, que é o endereço IP associado ao Namespace de Rede do Pod. Naturalmente, todos os outros recursos de rede são alocados por Pod e compartilhados por todos os contêineres dentro desse Pod. O ciclo de vida de um Pod está exclusivamente vinculado ao contêiner Infra e é independente dos contêineres A e B.

Além disso, para todos os contêineres de usuário dentro do mesmo Pod, seu tráfego de entrada e saída pode ser considerado como passando pelo contêiner Infra. Esse aspecto é crucial porque, se você for desenvolver um plugin de rede para o Kubernetes no futuro, seu foco principal deve ser configurar o Namespace de Rede do Pod, não como cada contêiner de usuário utiliza sua configuração de rede. Isso último é irrelevante. Isso implica que, se seu plugin de rede depende da instalação de pacotes ou configurações dentro do contêiner, não é uma solução viável. O sistema de arquivos raiz da imagem do contêiner Infra é praticamente vazio, não deixando espaço para personalização. Por outro lado, isso também significa que seu plugin de rede não precisa se preocupar com o status de inicialização dos contêineres de usuário, mas apenas com a configuração do Pod, ou seja, o Namespace de Rede do contêiner Infra.

Com esse design, o compartilhamento de volumes se torna muito mais simples. O Kubernetes pode definir todas as configurações de volume no nível do Pod. Consequentemente, o diretório host correspondente a um volume é exclusivo do Pod, e qualquer contêiner dentro do Pod precisa apenas declarar a montagem desse diretório. Essa filosofia de design por trás dos Pods, que promove um “relacionamento super próximo” entre os contêineres, visa incentivar os usuários a considerar se aplicativos com múltiplos componentes funcionalmente não relacionados executando em um único contêiner poderiam ser melhor representados como múltiplos contêineres dentro de um Pod.

Para entender essa mentalidade, tente aplicá-la a cenários que são difíceis de resolver com um único contêiner. Por exemplo, imagine um aplicativo que continuamente gera arquivos de log no diretório “/var/log” dentro do contêiner. Nesse caso, você pode montar um volume dentro do Pod no diretório “/var/log” do contêiner do aplicativo. Então, dentro do mesmo Pod, execute um contêiner sidecar que também declare a montagem do mesmo volume em seu diretório “/var/log”. A partir daí, a única tarefa do contêiner sidecar é ler continuamente os arquivos de log de seu diretório “/var/log” e encaminhá-los para soluções de armazenamento como MongoDB ou Elasticsearch. Essa configuração estabelece um mecanismo básico de coleta de logs.

Semelhante ao primeiro exemplo, a função principal do sidecar neste cenário também gira em torno do uso do volume compartilhado para operações de arquivo. No entanto, não negligencie a outra característica crucial dos Pods: todos os contêineres dentro de um Pod compartilham o mesmo Namespace de Rede. Isso permite que muitas configurações e tarefas de gerenciamento relacionadas à rede do Pod sejam delegadas ao sidecar, evitando completamente a necessidade de interferir nos contêineres de usuário. Um exemplo primordial disso é o projeto de malha de serviço Istio.

Resumo

Nesta discussão, nos aprofundamos nas razões por trás da necessidade de Pods. Em essência, um Pod serve como a unidade fundamental em um cluster Kubernetes, encapsulando um ou mais contêineres (tipicamente contêineres Docker). Esses contêineres compartilham recursos de rede e armazenamento. Da perspectiva de processos e grupos de processos, um Pod pode ser visto como um grupo de processos leve. Ele permite implantar, escalar e gerenciar múltiplos processos que colaboram de perto (contêineres) como uma unidade coesa, simplificando a implantação e operação de aplicativos complexos. No próximo artigo, forneceremos uma explicação mais aprofundada sobre Pods.

Novita AI é a plataforma completa em nuvem que impulsiona suas ambições de IA. Com APIs perfeitamente integradas, computação serverless e aceleração por GPU, fornecemos as ferramentas econômicas que você precisa para construir e escalar rapidamente seu negócio orientado por IA. Elimine dores de cabeça com infraestrutura e comece gratuitamente – a Novita AI torna seus sonhos de IA realidade.

Leitura Recomendada:

  1. How to write Dockerfile for beginners
  2. Docker for Beginners: Say Goodbye to Deployment Nightmares!