Comando docker: imagens, contentores e compose no Linux

Terminal com o comando docker run -d em destaque, ilustração do guia HJFR sobre contentores Docker no Linux

Instalar uma aplicação num servidor costumava ser um exercício de paciência: a versão certa da linguagem, as bibliotecas certas, a configuração certa — e o eterno «na minha máquina funciona». O docker resolveu isto: empacota a aplicação com tudo o que ela precisa numa imagem e corre-a num contentor isolado, que se comporta da mesma maneira no portátil, no servidor de testes e em produção.

Este guia acompanha o vídeo da série e percorre o fluxo completo no terminal: imagens, o docker run e as suas opções, o ciclo de vida, o diagnóstico, os volumes e as redes, o docker compose e a limpeza. No fim, olhamos para o Docker com olhos de cibersegurança — porque quem controla o Docker controla a máquina.

Veja o guia em vídeo

Prefere ver antes de experimentar? No canal HJFR-IT no YouTube mostramos o docker opção a opção, com o resultado de cada comando no ecrã — narrado em português e com legendas.

docker — Guia Completo: containers a partir do terminal — canal HJFR-IT no YouTube. Se o áudio não arrancar em português, abra as definições do vídeo (ícone da roda dentada) → Faixa de áudio → Português.

O que faz o docker

O docker é o cliente de linha de comandos que fala com o dockerd, o serviço que constrói imagens e corre contentores. Um contentor não é uma máquina virtual: partilha o núcleo do anfitrião e isola apenas os processos, a rede e o sistema de ficheiros, com namespaces e cgroups do próprio Linux. Por isso arranca em segundos.

A imagem é o molde, imutável e reutilizável: um sistema de ficheiros pré-construído com a aplicação e as dependências. O contentor é uma instância a correr a partir desse molde — da mesma imagem nascem muitos contentores idênticos.

docker [OPÇÕES] COMANDO [ARGUMENTOS]
docker image ls       # o mesmo que docker images

Imagens: pull, images e build

Descarregar e listar

O docker pull descarrega uma imagem de um registo — por omissão, o Docker Hub. Depois dos dois pontos vem a tag, que indica a versão. Sem ela, o Docker assume latest, que muda sem aviso: fixe sempre a versão. O docker images lista as imagens locais.

docker pull nginx:1.27
docker images

Construir a sua imagem com o Dockerfile

Para empacotar uma aplicação própria, escreve-se um Dockerfile — a receita, passo a passo — e corre-se o docker build. O -t dá nome e tag à imagem; o ponto final é o contexto, a pasta atual.

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER 1000
CMD ["python", "app.py"]

docker build -t hjfr/app:1.0 .

Cada instrução gera uma camada em cache: num segundo build, só se refaz o que mudou. E o USER 1000 faz a aplicação deixar de correr como root dentro do contentor.

tag, push e rmi

  • docker tag ORIGEM DESTINO — dá um segundo nome à mesma imagem (o IMAGE ID não muda), por exemplo com o endereço de um registo privado.
  • docker push NOME:TAG — envia a imagem para esse registo, depois de um docker login.
  • docker rmi IMAGEM — remove imagens que já não são precisas; acumulam-se depressa.
docker tag hjfr/app:1.0 registry.example.com/hjfr/app:1.0
docker push registry.example.com/hjfr/app:1.0
docker rmi mysql:5.7

docker run: as opções que moldam o contentor

O docker run é o comando central: cria e arranca um contentor a partir de uma imagem (descarregando-a, se for preciso). São as opções que lhe dão forma:

  • -d — corre em segundo plano (detached), o normal para serviços.
  • --name — um nome legível, em vez de um aleatório como vibrant_lamport.
  • -p 8080:80 — publica uma porta: a 8080 do anfitrião chega à 80 do contentor.
  • -it e --rm — terminal interativo dentro do contentor, apagado automaticamente à saída.
  • -e — define variáveis de ambiente, a forma habitual de configurar a aplicação.
  • -v — monta um volume; sem ele, os dados desaparecem quando o contentor é removido.
docker run -d --name web -p 8080:80 nginx:1.27
docker run -it --rm alpine:3.20 sh
docker run -d --name db -e POSTGRES_PASSWORD=mudar-isto \
  -v dados-db:/var/lib/postgresql/data postgres:16

O ciclo de vida do contentor

O docker ps lista os contentores em execução, com imagem, estado, portas e nome. Por omissão só mostra os que estão a correr; o docker ps -a mostra também os parados.

  • docker stop — para de forma graciosa: SIGTERM e, se o processo não sair em 10 segundos, SIGKILL.
  • docker start / docker restart — volta a arrancar o mesmo contentor / faz stop e start de uma vez.
  • docker rm — remove um contentor parado; um que esteja a correr só sai com docker rm -f.

Parar não é remover. Um contentor parado mantém o sistema de ficheiros e a configuração e pode voltar a arrancar; um removido desaparece.

Inspecionar e interagir

  • docker logs — o que o contentor escreveu na saída; com -f segue em direto, como o tail -f.
  • docker exec -it NOME bash — abre uma shell num contentor a correr, sem o parar.
  • docker inspect — a configuração completa em JSON (rede, volumes, variáveis, comando): a fonte da verdade.
  • docker stats — CPU, memória, rede e disco de cada contentor, ao vivo: o top dos contentores.
  • docker top lista os processos de um contentor; docker cp copia ficheiros de e para ele, mesmo parado.
docker logs -f --tail 20 web
docker exec -it web bash
docker inspect -f '{{.HostConfig.Privileged}}' web
docker stats --no-stream
docker cp web:/etc/nginx/nginx.conf ./nginx.conf

Volumes e redes

Volumes: dados que sobrevivem

Os contentores são efémeros: quando um é removido, tudo o que estava lá dentro desaparece. Os volumes são armazenamento persistente, gerido pelo Docker, que sobrevive aos contentores. Cria-se um com docker volume create e monta-se com -v: a base de dados fica intacta mesmo que se recrie o contentor.

Redes: contentores que se encontram pelo nome

Por omissão, os contentores ficam na rede bridge partilhada, sem resolução de nomes. Com uma rede própria (docker network create), cada contentor chega aos outros pelo nome: a aplicação liga-se à base de dados chamando-a simplesmente db.

docker volume create uploads
docker network create app-net
docker run -d --name app --network app-net -e DB_HOST=db \
  -v uploads:/app/uploads hjfr/app:1.0
docker exec app getent hosts db

docker compose: vários contentores num só ficheiro

Uma aplicação real tem várias peças — aplicação, base de dados, cache — e coordená-las à mão é penoso. O docker compose descreve tudo num ficheiro YAML, tipicamente compose.yaml, de forma declarativa:

services:
  app:
    image: hjfr/app:1.0
    ports:
      - "127.0.0.1:8000:8000"
    environment:
      DB_HOST: db
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_pw
    secrets:
      - db_pw
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
secrets:
  db_pw:
    file: ./db_pw.txt
  • docker compose up -d — levanta tudo de uma vez, com redes e volumes.
  • docker compose ps e docker compose logs — estado do conjunto e registos de todos os serviços.
  • docker compose down — para e remove contentores e redes; os volumes só saem com -v.

A configuração fica num ficheiro versionável no git: qualquer pessoa levanta a mesma aplicação com um comando. Para vários servidores há o Kubernetes; numa só máquina, basta o compose.

Limpeza: system df e prune

Imagens antigas, contentores parados e cache de build enchem o disco. O docker system df mostra o espaço usado, por tipo. O docker system prune remove o que não está em uso; com -a apaga também todas as imagens sem contentor — incluindo as que talvez quisesse manter. Leia a lista antes de confirmar.

docker system df
docker system prune
docker system prune -a

docker em cibersegurança

Quem controla o Docker é root. O dockerd corre como root e escuta em /var/run/docker.sock. Um utilizador do grupo docker pode correr docker run -v /:/host e alterar todo o anfitrião: pertencer ao grupo equivale a ter root. Montar o socket num contentor, ou usar --privileged, entrega a máquina a quem o comprometer. Reserve o grupo a administradores e endureça os contentores com --cap-drop ALL, --read-only e um utilizador sem privilégios.

Imagens de origem duvidosa e segredos à vista. Uma imagem de autor desconhecido é código de terceiros a correr no seu servidor — algumas trazem mineradores de criptomoedas. Prefira imagens oficiais, fixe a versão e analise-as com um scanner de vulnerabilidades. E tudo o que passa por -e aparece no docker inspect: palavras-passe pertencem a secrets ou a ficheiros montados.

Investigar sem destruir provas. O docker stats denuncia o contentor que devora a CPU; o docker top mostra os seus processos com os PIDs do anfitrião; o docker inspect revela imagem, privilégios e volumes. E o -p publica em 0.0.0.0, com regras de firewall próprias que podem contornar as do anfitrião. Para conter, docker stop, não rm: o contentor parado guarda o sistema de ficheiros, e o docker cp e o docker logs recolhem a evidência. Um prune precipitado apaga as provas.

Experimente no simulador interativo

O simulador recria um servidor de testes com imagens antigas, um contentor parado e um monitor que ninguém se lembra de ter lançado. À esquerda, as imagens (a tracejado), os contentores, os volumes e as redes; à direita, a saída de cada comando. Demonstrar tudo percorre os 41 passos, do pull à investigação do monitor; Anterior e Seguinte navegam passo a passo e Repor estado recomeça.

Erros comuns e boas práticas

  • Usar latest em produção: a mesma tag pode trazer amanhã outra versão. Fixe-a.
  • Guardar dados dentro do contentor: sem -v, a base de dados desaparece no primeiro docker rm.
  • Confundir parar com remover: o docker ps esconde os parados; confirme com docker ps -a.
  • Publicar portas para toda a rede: -p 5432:5432 expõe a base de dados em todas as interfaces; prefira 127.0.0.1:.
  • Pôr segredos em -e: ficam à vista no inspect. Use secrets.
  • Correr prune -a por reflexo: apaga imagens úteis e, num incidente, a evidência. Primeiro system df, depois decidir.

Conclusão

Imagens com pull e build, contentores com run, o ciclo de vida com ps, stop e rm, o diagnóstico com logs, exec e inspect, e ainda volumes, redes, compose e prune: eis o essencial do docker. A regra que fica: trate o acesso ao Docker como acesso root. Os processos dos contentores são processos da máquina — o guia de ps e top ajuda a encontrá-los — e as portas publicadas aparecem no comando ss.

Workshop — Linha de Comandos Linux

Quer passar da leitura à prática, com exercícios reais e acompanhamento? No workshop Linha de Comandos Linux da HJFR trabalha estes e outros comandos da série — da administração do dia a dia à resposta a incidentes.

Este artigo faz parte da série «Comandos Linux, um a um» do blog HJFR — fique atento aos próximos comandos.