Módulo 9 · 9.1
Compreender os contentores
Módulo 9: Docker e docker compose · Tempo de leitura: 10 minutos
Objetivo de aprendizagem: Depois desta lição, saberá explicar o que é um contentor, em que difere de uma máquina virtual, onde ficam os dados de um contentor e quando faz sentido usar o Docker no seu servidor.
Conceitos-chave: imagem (image), contentor, camada, registry (Docker Hub), tag, digest, namespaces, cgroups, kernel partilhado, sistema de ficheiros volátil, volume, bind mount, publicar uma porta, imagem oficial
Porquê contentores?
Imagine que pretende executar no seu VPS uma página de estado que mostra se o seu site está a funcionar. O programa está escrito em Node.js, precisa de uma determinada versão dessa plataforma e de cerca de duzentas bibliotecas. Sem contentores, instala tudo isso no seu servidor, ao lado do servidor web e da base de dados. Um ano depois, quer um segundo programa que precisa de outra versão do Node.js. É aí que começam as complicações.
Um contentor resolve este problema. O autor do programa fornece o programa juntamente com tudo aquilo de que ele precisa, num único pacote: uma imagem (image). No seu servidor, inicia essa imagem como contentor. O programa vê os seus próprios ficheiros, o seu próprio Node.js e as suas próprias bibliotecas, e não entra em conflito com o resto do servidor. Já não precisa dele? Remove o contentor e a imagem, e nada fica para trás em /usr ou /etc.
O Docker é a ferramenta mais conhecida para descarregar imagens e executar contentores. Existem alternativas (Podman, o próprio containerd), mas os conceitos são os mesmos em todo o lado.
Imagem, contentor e registry
Três palavras que vai encontrar constantemente:
- Imagem: um modelo só de leitura com um sistema de ficheiros (programa, bibliotecas, definições) e o comando que deve ser iniciado. Uma imagem é composta por camadas: uma camada de base (por exemplo, um Debian mínimo), por cima uma camada com o Node.js e, por cima desta, o programa. Duas imagens com a mesma camada de base partilham essa camada no seu disco.
- Contentor: uma instância em execução (ou parada) de uma imagem. Por cima das camadas só de leitura, o contentor recebe uma fina camada de escrita própria. A partir de uma única imagem, pode iniciar dez contentores.
- Registry: o local onde as imagens estão guardadas, como o Docker Hub (
docker.io) ou o registry do GitHub (ghcr.io). O Docker descarrega uma imagem comdocker pull.
O nome de uma imagem tem este aspeto:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestA parte depois dos dois pontos é a tag: uma etiqueta para uma versão. Uma tag pode mudar: caddy:2 aponta hoje para uma build diferente da de daqui a três meses, assim que sair uma nova versão 2.x. Se quiser fixar exatamente que imagem está a executar, utilize o digest: uma impressão digital do conteúdo, como caddy@sha256:.... Este nunca muda. A tag latest é apenas um nome escolhido pelo autor; não significa automaticamente "a versão estável mais recente" e, por isso, é uma má escolha se quiser saber o que está em execução.
Não é uma máquina virtual
Um contentor parece uma pequena máquina virtual, mas não é. Esta diferença é importante para a segurança.
| Máquina virtual (como o seu VPS) | Contentor | |
|---|---|---|
| Kernel | Kernel próprio | Partilha o kernel do anfitrião |
| Arranque | De segundos a minutos, um sistema operativo completo | Normalmente num segundo, apenas o programa |
| Isolamento | Pelo hipervisor, ao nível do hardware | Pelo kernel: namespaces e cgroups |
| Tamanho | Gigabytes | Frequentemente dezenas a centenas de megabytes |
Na prática, um contentor é um processo normal no seu servidor, que o kernel coloca num ambiente isolado:
- os namespaces fazem com que o processo tenha a sua própria visão dos ficheiros, processos, rede e utilizadores. Dentro do contentor, o programa parece ser o processo número 1 e não vê o resto do seu servidor;
- os cgroups limitam a quantidade de processador e de memória que pode utilizar.
Como todos os contentores partilham o mesmo kernel, o isolamento é menos rigoroso do que entre dois VPS. Uma falha de segurança no kernel ou um contentor com demasiados privilégios pode afetar o anfitrião. Daí as regras deste módulo: execute apenas imagens em que confia, não dê aos contentores mais privilégios do que o necessário e nunca monte /var/run/docker.sock ou / num contentor (lições 9.3 e 10.2).
Onde ficam os seus dados?
Esta é a armadilha clássica para principiantes. A camada de escrita de um contentor é volátil: se remover o contentor (por exemplo, numa atualização, lição 9.4), tudo o que o programa lá escreveu desaparece. Os dados que devem ser mantidos pertencem, por isso, ao exterior do contentor:
- Volume: um espaço de armazenamento gerido pelo próprio Docker (em
/var/lib/docker/volumes/). Atribui-lhe um nome, por exemplouptime-kuma, e liga-o a uma pasta no contentor:-v uptime-kuma:/app/data. - Bind mount: uma pasta normal no seu servidor que monta no contentor:
-v /srv/vaultwarden:/data. É prático porque vê os ficheiros diretamente e os inclui facilmente na sua cópia de segurança (módulo 8).
Um contentor com bons volumes pode ser eliminado e recriado sem perder nada. É exatamente assim que funciona uma atualização: descarregar a nova imagem, remover o contentor antigo, criar um novo contentor com os mesmos volumes. Inclua, por isso, os volumes no seu plano de cópias de segurança (lição 8.1).
Publicar portas
Um contentor tem a sua própria rede. Um programa web que escuta na porta 3001 dentro do contentor não está acessível a partir do exterior do servidor até publicar essa porta: -p 3001:3001 (porta do anfitrião:porta do contentor). Atenção: sem endereço, o Docker publica a porta em todos os endereços do seu servidor, ou seja 0.0.0.0 e [::]. Isto significa: acessível a partir de toda a internet, e o Docker trata disso sem passar pelo ufw (lição 9.3). O hábito seguro é publicar no loopback, -p 127.0.0.1:3001:3001, e colocar à frente um proxy inverso com https (lição 9.4).
Quem cria a imagem?
Uma imagem é software de outra pessoa que pode ser executado como root no seu servidor. Verifique, por isso, quem é o autor:
- as Docker Official Images (como
caddy,nginx,postgres) são mantidas pelo Docker em conjunto com os autores; - imagens do próprio autor (como
louislam/uptime-kumaevaultwarden/server), reconhecíveis pelo nome indicado no site do projeto; - imagens de desconhecidos com nomes parecidos: não as utilize.
Utilize sempre o nome indicado no site oficial do projeto, e não o primeiro que uma pesquisa devolve.
Quando sim, quando não?
O Docker é útil para programas que o autor fornece como imagem, para serviços que pretende poder eliminar ou mudar de sítio rapidamente e para executar lado a lado vários programas com requisitos diferentes. Para a base do seu servidor (SSH, firewall, atualizações), não se utilizam contentores. E um único site com nginx e PHP a partir do repositório de pacotes (lição 7.2) funciona perfeitamente sem Docker. Um contentor acrescenta uma camada que tem de compreender e manter atualizada; utilize-o quando isso traz vantagens.
Resumo
- Uma imagem é um modelo só de leitura em camadas; um contentor é uma instância em execução com uma camada de escrita própria.
- Os contentores partilham o kernel do anfitrião e são isolados com namespaces e cgroups: mais leves do que uma VM, mas com um isolamento menos rigoroso.
- A camada de escrita é volátil: os dados permanentes pertencem a um volume ou bind mount, e estes pertencem à sua cópia de segurança.
- Uma tag pode mudar, um digest não;
latestdiz pouco. - Publique portas em 127.0.0.1 e utilize apenas imagens do autor ou imagens oficiais.
Questionário
Exercício
Exercício O9.1: Contentor ou não? Escolha dois programas que pretende executar no seu servidor (ou utilize como exemplo o Uptime Kuma e um site WordPress). Para cada programa, procure se o autor fornece uma imagem oficial e com que nome, que tag escolheria, que pasta contém os dados permanentes e em que porta escuta. Depois, explique se o executaria num contentor ou a partir do repositório de pacotes, e porquê.
Exercício O9.1: Contentor ou não?
Este exercício faz você mesmo; ninguém o verifica. Assinale o que já fez e marque o exercício como concluído.
Uptime Kuma: louislam/uptime-kuma com uma tag de versão, dados em /app/data, porta 3001, publicar em 127.0.0.1 atrás de um proxy inverso. Escolha uma imagem do autor ou uma Official Image, com uma tag de versão e uma pasta de dados com nome.
As suas marcações e notas ficam apenas neste navegador; não as enviamos para lado nenhum. Se tiver sessão iniciada, guardamos em Os meus cursos apenas que concluiu o exercício.
Para saber mais
- Documentação do Docker, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Documentação do Docker, Volumes: https://docs.docker.com/engine/storage/volumes/
- Documentação do Docker, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
