Dia 21: Docker no Linux — Contentores, Imagens, Volumes e Redes
O Docker transformou a forma como se empacota, distribui e executa software no Linux. Em vez de instalar dependências directamente no sistema, um contentor empacota a aplicação com tudo o que precisa — bibliotecas, runtime, configuração — numa unidade isolada e portável. Este guia cobre os quatro pilares do Docker: imagens, contentores, volumes e redes, além do Dockerfile para construir imagens personalizadas. Segue o guia oficial de instalação da documentação Docker.
Neste artigo
1. Introdução ao Docker
O Docker é uma plataforma de contentorização que permite correr aplicações em ambientes isolados chamados contentores. Cada contentor partilha o kernel do sistema anfitrião mas tem o seu próprio sistema de ficheiros, processos e rede — é mais leve que uma máquina virtual porque não precisa de um kernel separado.
ℹ Contentor vs Máquina Virtual
Uma máquina virtual inclui um sistema operativo completo com o seu próprio kernel. Um contentor partilha o kernel do anfitrião e só empacota a aplicação e as suas dependências. Por isso, os contentores arrancam em segundos e ocupam megabytes em vez de gigabytes.
Os quatro conceitos fundamentais do Docker são:
| Conceito | O que é | Analogia |
|---|---|---|
| Imagem | Template só de leitura com a aplicação e dependências | Receita ou molde |
| Contentor | Instância em execução de uma imagem | Bolo feito da receita |
| Volume | Armazenamento persistente para dados do contentor | Disco externo |
| Rede | Comunicação entre contentores e com o exterior | Switch virtual |
O Docker usa namespaces do kernel Linux para isolar processos, rede e sistema de ficheiros, e cgroups para limitar recursos (CPU, memória). Isto significa que qualquer distribuição Linux moderna pode correr Docker nativamente, sem virtualização adicional.
2. Instalar Docker
A forma recomendada é usar o repositório oficial do Docker. O exemplo abaixo aplica-se a Debian/Ubuntu. Para outras distribuições, consulta a documentação oficial.
Primeiro, instalar dependências e adicionar a chave GPG oficial:
# Instalar dependências
sudo apt update
sudo apt install -y ca-certificates curl gnupg
# Adicionar chave GPG oficial do Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Adicionar repositório
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Depois, instalar o Docker Engine e verificar:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Verificar instalação
docker --version
sudo docker run hello-world
Para evitar escrever sudo em cada comando, adicionar o utilizador ao grupo docker:
sudo usermod -aG docker $USER
newgrp docker
⚠ Atenção de segurança
Adicionar o utilizador ao grupo docker dá privilégios equivalentes a root. Num servidor de produção, considera usar sudo docker ou configurar rootless mode.
O serviço Docker deve estar activo. Verificar com systemctl:
sudo systemctl enable docker
sudo systemctl start docker
sudo systemctl status docker
3. Imagens e Contentores
Uma imagem é um template só de leitura. Um contentor é uma instância em execução dessa imagem. O Docker Hub é o repositório público oficial onde se encontram milhares de imagens — desde Ubuntu e Debian até PostgreSQL, Redis e Nginx.
Gerir imagens
# Procurar imagem no Docker Hub
docker search nginx
# Descarregar imagem
docker pull ubuntu:24.04
# Listar imagens locais
docker images
# Eliminar imagem
docker rmi ubuntu:24.04
As imagens usam um sistema de camadas (layers). Cada instrução num Dockerfile cria uma nova camada. Camadas idênticas entre imagens são partilhadas, poupando espaço.
Gerir contentores
# Criar e correr um contentor em primeiro plano
docker run --name meu-nginx -p 8080:80 nginx:latest
# Correr em segundo plano (-d) com reinício automático
docker run -d --name web-server --restart unless-stopped -p 8080:80 nginx
# Listar contentores ativos
docker ps
# Listar todos (incluindo parados)
docker ps -a
# Iniciar, parar, reiniciar
docker start meu-nginx
docker stop meu-nginx
docker restart meu-nginx
# Entrar num contentor em execução
docker exec -it meu-nginx bash
# Ver logs
docker logs -f meu-nginx
# Eliminar contentor
docker rm -f meu-nginx
A flag -it combina -i (interactivo) com -t (terminal), permitindo interagir com o contentor. A flag -p 8080:80 mapeia o porto 8080 do anfitrião para o porto 80 do contentor.
| Flag | Significado |
|---|---|
-d |
Correr em segundo plano (detached) |
-it |
Interactivo com terminal |
-p H:C |
Mapear porto do anfitrião para o contentor |
-v H:C |
Montar volume ou bind mount |
--name |
Atribuir nome ao contentor |
--restart |
Política de reinício (no, always, unless-stopped, on-failure) |
4. Volumes e Persistência
Por defeito, quando um contentor é removido, todos os dados que continha desaparecem. Os volumes e bind mounts resolvem este problema, permitindo que os dados persistam independentemente do ciclo de vida do contentor.
Volumes vs Bind Mounts
| Tipo | Localização | Quando usar |
|---|---|---|
| Volume | Gerido pelo Docker em /var/lib/docker/volumes/ |
Bases de dados, dados de aplicações — produção |
| Bind mount | Caminho absoluto no anfitrião | Desenvolvimento (código fonte partilhado) |
| tmpfs | Memória RAM do anfitrião | Dados temporários sensíveis (segredos) |
Comandos para gerir volumes:
# Criar volume nomeado
docker volume create dados-postgres
# Listar volumes
docker volume ls
# Correr contentor com volume
docker run -d --name postgres \
-v dados-postgres:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=minha-senha \
postgres:16
# Inspecionar volume
docker volume inspect dados-postgres
# Eliminar volume (contentor deve estar parado)
docker volume rm dados-postgres
Bind mounts para desenvolvimento — partilhar código fonte entre o anfitrião e o contentor:
# Montar directoria actual no contentor
docker run -d --name dev-web \
-v $(pwd)/src:/app/src \
-p 3000:3000 \
node:20
ℹ Boa prática
Em produção, usa sempre volumes nomeados em vez de bind mounts. Os volumes são geridos pelo Docker, são portáveis entre nós, e o backup é mais simples. Reserva bind mounts para ambiente de desenvolvimento.
5. Redes Docker
As redes Docker permitem que os contentores comuniquem entre si e com o exterior. O Docker cria três drivers de rede por defeito: bridge, host e none.
| Driver | Comportamento | Uso típico |
|---|---|---|
| bridge | Rede virtual isolada no anfitrião | Contentores que precisam de comunicar entre si |
| host | Partilha a rede do anfitrião (sem isolamento) | Máximo desempenho de rede |
| none | Sem rede | Contentores totalmente isolados |
Criar uma rede personalizada e ligar contentores por nome (DNS automático):
# Criar rede bridge personalizada
docker network create rede-app
# Correr PostgreSQL nessa rede
docker run -d --name postgres \
--network rede-app \
-e POSTGRES_PASSWORD=senha123 \
postgres:16
# Correr aplicação web na mesma rede
docker run -d --name webapp \
--network rede-app \
-p 8080:3000 \
minha-app:latest
# A aplicação web liga-se ao PostgreSQL
# usando o nome "postgres" como hostname
ℹ DNS automático
Nas redes bridge personalizadas, o Docker fornece resolução DNS automática. O contentor webapp consegue resolver postgres por nome — não precisa de saber o IP. Isto não funciona na rede bridge predefinida, por isso cria sempre redes personalizadas.
Comandos essenciais de rede:
# Listar redes
docker network ls
# Inspecionar rede
docker network inspect rede-app
# Ligar contentor a uma rede em execução
docker network connect rede-app outro-contentor
# Desligar contentor
docker network disconnect rede-app outro-contentor
# Eliminar rede
docker network rm rede-app
6. Dockerfile
O Dockerfile é um ficheiro de texto com instruções para construir uma imagem personalizada. Cada instrução cria uma camada na imagem. O exemplo abaixo cria uma imagem com uma aplicação Node.js simples.
# Imagem base — usar versão especificada, não "latest"
FROM node:20-slim
# Definir directoria de trabalho
WORKDIR /app
# Copiar package.json primeiro (aproveita cache de camadas)
COPY package*.json ./
# Instalar dependências
RUN npm ci --production
# Copiar resto do código
COPY . .
# Expor porto da aplicação
EXPOSE 3000
# Comando para iniciar a aplicação
CMD ["node", "server.js"]
Construir a imagem e correr o contentor:
# Construir imagem (-t define tag, . é o contexto)
docker build -t minha-app:1.0 .
# Correr contentor
docker run -d --name app-prod -p 3000:3000 minha-app:1.0
# Construir com ficheiro Dockerfile alternativo
docker build -f Dockerfile.prod -t minha-app:prod .
Instruções principais do Dockerfile:
| Instrução | Função |
|---|---|
FROM |
Define a imagem base |
WORKDIR |
Define a directoria de trabalho |
COPY |
Copia ficheiros do anfitrião para a imagem |
RUN |
Executa um comando durante a construção |
EXPOSE |
Documenta o porto que o contentor escuta |
CMD |
Comando por defeito ao iniciar o contentor |
ENTRYPOINT |
Comando fixo que não pode ser sobrescrito |
ENV |
Define variável de ambiente |
⚠ Erros comuns no Dockerfile
Não uses :latest como tag base — as imagens mudam e quebram a reprodutibilidade. Especifica sempre versões concretas como node:20-slim. Coloca COPY package*.json antes de COPY . . para aproveitar o cache de camadas — se o código muda mas as dependências não, o npm ci não precisa de repetir.
7. Erros Comuns e Checklist
Estes são os erros mais frequentes ao trabalhar com Docker e como os evitar.
| Erro | Causa | Solução |
|---|---|---|
permission denied |
Utilador fora do grupo docker | sudo usermod -aG docker $USER |
port is already allocated |
Outro processo usa o porto | Trocar porto ou parar o contentor conflituante |
no space left on device |
Imagens e contentores acumulados | docker system prune -a |
| Contentor para imediatamente | Processo principal terminou | Verificar docker logs e o CMD |
| Dados perdidos após reinício | Sem volume montado | Usar -v para persistir dados |
| Contentores não se vêem | Rede bridge predefinida | Criar rede bridge personalizada |
Comandos úteis de limpeza e diagnóstico:
# Remover todos os contentores parados
docker container prune
# Remover imagens não usadas
docker image prune -a
# Remover volumes não usados (cuidado com dados!)
docker volume prune
# Limpeza total — remove tudo não em uso
docker system prune -a --volumes
# Ver uso de espaço do Docker
docker system df
Checklist de boas práticas:
- Usar tags de versão específicas (
nginx:1.27) em vez de:latest - Usar volumes nomeados para dados persistentes em produção
- Criar redes bridge personalizadas para DNS automático entre contentores
- Definir
--restart unless-stoppedem contentores de produção - Limpar regularmente com
docker system prune - Usar
.dockerignorepara excluir ficheiros desnecessários do contexto de build - Combinar instruções
RUNcom&¶ reduzir camadas - Nunca guardar segredos no Dockerfile — usar variáveis de ambiente ou Docker Secrets
✓ Resumo
O Docker segue o fluxo: imagem (template) → contentor (execução) → volume (persistência) → rede (comunicação). O Dockerfile descreve como construir a imagem. Com estes cinco conceitos dominas 90% do uso diário do Docker no Linux.
Artigos Relacionados
- Dia 20: Gestão de Pacotes — APT, DPKG, Snap e Flatpak
- Dia 1: Introdução ao Linux e Instalação
- Dia 9: Firewalls — iptables, nftables e UFW
- Dia 10: Endurecimento de SSH
- Índice completo do curso Linux em 30 dias
- {‘raw’: ‘Dia 22: Docker Compose — Multi-Service Stacks e Orquestração Básica’, ‘rendered’: ‘Dia 22: Docker Compose — Multi-Service Stacks e Orquestração Básica’} — dia seguinte do curso