Olá! Na nossa última lição, mergulhamos nos fundamentos que tornam os contêineres possíveis: os namespaces do kernel do Linux para isolamento e os cgroups para limitação de recursos. Vimos que um contêiner, em sua essência, é um processo Linux padrão com "visão" e "uso" de recursos controlados.
Nesta lição, vamos subir um nível de abstração para entender as ferramentas que orquestram esses recursos do kernel. O objetivo é que você consiga descrever a arquitetura do Docker—incluindo o Docker Engine, containerd e runc—e como esses componentes colaboram para gerenciar o ciclo de vida de um contêiner. Isso preencherá a lacuna entre os recursos de baixo nível do kernel e os comandos docker que usamos no dia a dia.
A Arquitetura Docker: De Monolítica a Modular
Inicialmente, o Docker era uma aplicação monolítica, onde um único daemon era responsável por tudo. Com o tempo, para promover a padronização e a interoperabilidade (especialmente com o surgimento de orquestradores como o Kubernetes), o Docker adotou uma arquitetura modular.
Hoje, a interação com o Docker segue um modelo cliente-servidor, que evolui para uma cadeia de componentes especializados.

Vamos dissecar essa cadeia, começando pela interface com o usuário até chegar ao processo que efetivamente roda no kernel.
A Cadeia de Comando do Docker
Para entender como um simples comando docker run se transforma em um contêiner em execução, vamos examinar cada peça do quebra-cabeça.
O artigo a seguir, de Srinivasaraju Tangella, oferece uma excelente visão geral dessa arquitetura, da interface de linha de comando (CLI) até o kernel.
Inside Docker: The Complete Architecture Explained from CLI to Kernel
Este artigo explica de forma clara e sequencial cada componente da arquitetura Docker. Ele servirá como nosso guia principal para esta lição.
Leia as seções 1 a 7 e 10. Preste atenção especial na função de cada componente (Docker CLI, dockerd, containerd, containerd-shim, runc) e como eles se comunicam entre si. A seção 10 ('The Full Execution Flow') resume o processo de forma excelente.
Com base no que você leu, vamos detalhar as responsabilidades de cada componente.
1. Docker Client e Docker Daemon (dockerd)
- Docker CLI (
docker): Esta é a sua interface. Quando você digita um comando comodocker run, você está interagindo com o cliente Docker. Ele não faz o trabalho pesado; em vez disso, ele traduz seu comando em uma chamada de API REST e a envia para o Docker Daemon. - Docker Daemon (
dockerd): Este é o "cérebro" do Docker. É um processo de longa duração (um daemon) que escuta as chamadas da API do cliente.dockerdgerencia os objetos de alto nível do Docker, como imagens, redes e volumes. No entanto, quando se trata de executar um contêiner, ele não faz o trabalho sozinho. Ele delega essa responsabilidade a um componente mais especializado.
Essa separação é fundamental. Você pode, por exemplo, ter o Docker CLI em sua máquina local se comunicando com um dockerd rodando em um servidor remoto.
2. containerd: O Gerente de Ciclo de Vida do Contêiner
Como o artigo mencionou, dockerd passa a solicitação de execução de um contêiner para o containerd.
containerdé um runtime de contêiner de alto nível. Sua única preocupação é gerenciar o ciclo de vida completo do contêiner no sistema:- Baixar imagens de um registry (como o Docker Hub).
- Gerenciar o armazenamento de imagens e os sistemas de arquivos em camadas (snapshots).
- Iniciar, parar e supervisionar contêineres.
- Configurar a rede para o contêiner.
containerd foi doado pelo Docker para a Cloud Native Computing Foundation (CNCF). Isso o tornou um padrão da indústria, usado não apenas pelo Docker, mas também pelo Kubernetes e outras ferramentas, o que é relevante para seus objetivos de aprendizado mais amplos.
O vídeo a seguir fornece uma excelente explicação visual sobre a hierarquia entre dockerd, containerd e os componentes subsequentes.
Docker Architecture | Docker components : daemon, containerd, containerd-shim, runc
Para complementar a leitura, este vídeo do canal InvolveInInnovation detalha as responsabilidades de cada componente da arquitetura de forma clara e visual.
Assista dos 02:16 aos 05:39. O vídeo abordará containerd, containerd-shim e runc. Foque em entender como containerd gerencia o ciclo de vida e como o shim permite a existência de 'daemonless containers'.
3. runc: O Executor do Contêiner
containerd não cria o contêiner diretamente. Para essa tarefa, ele chama um runtime de baixo nível: runc.
runcé a implementação de referência da especificação OCI (Open Container Initiative). Sua única função é receber uma configuração padrão (um arquivoconfig.jsone um sistema de arquivos raiz) e usar os recursos do kernel do Linux (namespaces, cgroups, que vimos na lição anterior) para criar um contêiner.
Depois que runc cria o processo do contêiner, ele encerra. Ele não fica em execução para monitorar o contêiner. Essa tarefa é deixada para o próximo componente.
4. containerd-shim: O Elo Perdido
Então, se runc sai de cena, quem fica como pai do processo do contêiner? E como containerd (ou dockerd) se mantém funcional se eles precisarem ser reiniciados? A resposta é o containerd-shim.
Para cada contêiner em execução, um pequeno processo shim é criado. Suas responsabilidades são:
- Atuar como o pai direto do processo do contêiner, evitando que ele se torne um processo "órfão".
- Manter os pipes de entrada/saída padrão (
STDIN,STDOUT,STDERR) abertos para o contêiner, mesmo quedockerdoucontainerdsejam reiniciados. - Reportar o status de saída do contêiner de volta para o
containerdquando ele terminar.
Essa camada de shim é o que permite a funcionalidade "Live Restore" do Docker, garantindo que seus contêineres continuem rodando mesmo se você atualizar ou reiniciar o daemon do Docker.
Teste seu entendimento!
Você precisa depurar um problema onde um contêiner está sendo criado, mas falha imediatamente. Você suspeita que o problema está na forma como os namespaces e cgroups estão sendo aplicados. Qual componente da arquitetura Docker é o principal responsável por interagir diretamente com o kernel para aplicar essas configurações e, portanto, seria o foco principal de sua investigação em nível de sistema?
Show answer
O componente a ser investigado seria o runc.
Enquanto dockerd orquestra a operação e containerd gerencia o ciclo de vida e prepara o "pacote" do contêiner (imagem e configuração), é o runc que efetivamente executa as chamadas de sistema (syscalls) para o kernel do Linux para criar os namespaces, aplicar os limites dos cgroups e iniciar o processo isolado. Uma falha nesse nível aponta diretamente para a interação do runc com o kernel.
Uma Exploração Prática (Opcional)
Sua preferência por entender "como as coisas funcionam" me leva a sugerir um recurso mais aprofundado. O artigo a seguir não apenas explica a arquitetura, mas também mostra como usar as ferramentas de linha de comando de cada camada (ctr para containerd e o próprio runc) para executar contêineres, contornando o dockerd.
Dado seu background com Linux e desenvolvimento, seguir esses experimentos pode ser extremamente revelador.
Para uma experiência prática que solidifica o entendimento da arquitetura modular, este artigo do desenvolvedor 'kt' é excepcional. Ele demonstra como inspecionar a árvore de processos e interagir diretamente com containerd e runc.
Recomendo fortemente que você leia as seções 1, 2 e 3. A seção 1 ('Grasping the Big Picture') mostra como usar pstree para visualizar a hierarquia dockerd -> containerd -> containerd-shim -> container_process. As seções 2 e 3 guiam você na execução de um contêiner usando apenas containerd e, em seguida, apenas runc. Tentar esses passos em seu ambiente Docker fornecerá uma compreensão concreta e de baixo nível.
Conclusão
Nesta lição, desvendamos a arquitetura moderna do Docker. Vimos como o que parece ser um único comando docker run é, na verdade, uma cadeia de responsabilidades delegadas entre componentes especializados.
Principais pontos a reter:
- Arquitetura em Camadas: A arquitetura do Docker é uma pilha:
Docker CLI->dockerd->containerd->containerd-shim->runc->Kernel Linux. dockerd(Orquestrador): A interface de alto nível que gerencia imagens, volumes e redes e traduz os comandos do usuário em chamadas para ocontainerd.containerd(Gerente de Ciclo de Vida): Um runtime padrão da indústria focado em baixar imagens e gerenciar o ciclo de vida do contêiner (iniciar, parar).runc(Executor): Um runtime de baixo nível, compatível com OCI, que pega uma configuração e um sistema de arquivos e cria o contêiner usando os recursos do kernel (namespaces e cgroups).containerd-shim(Supervisor): Um processo intermediário que permite quedockerdecontainerdsejam reiniciados sem parar os contêineres, garantindo robustez.
Agora que entendemos a arquitetura que inicia um contêiner, a próxima lição focará nos comandos que você usará para interagir com eles. Vamos explorar em detalhes o comando docker run, incluindo como executar contêineres em primeiro plano (interactive) e em segundo plano (detached), e como gerenciar seu estado com docker start, stop, restart e remove.