Conteúdo

Tutorial de Docker Compose: gerencie vários contêineres com um único arquivo

Um aplicativo real costuma ter mais de um contêiner: site, banco de dados, cache... Para cada um, você precisa lembrar uma longa lista de parâmetros de docker run, criar uma rede e um Volume antes e prestar atenção à ordem de inicialização.

Docker Compose permite colocar essas configurações em um arquivo YAML e iniciar tudo com um único comando:

docker compose up -d

Instalação e versão

  • Docker Desktop (Windows e macOS) já inclui o Compose.
  • Linux: siga as etapas de instalação do Docker e instale docker-compose-plugin.
$ docker compose version
Docker Compose version v5.6.0

O antigo programa independente se chama docker-compose (com hífen, v1) e não recebe mais manutenção; agora, use docker compose (com espaço). O número da versão do Compose saltou diretamente da v2 para a v5, mas o uso não mudou. Tutoriais antigos na internet misturam os dois; os comandos e parâmetros são praticamente os mesmos.

Projeto de exemplo: site + banco de dados + interface de administração

Crie a pasta compose-demo com a seguinte estrutura:

compose-demo/
├── compose.yaml
└── site/
    └── index.html

Coloque uma página simples em site/index.html (o conteúdo fica a seu critério). compose.yaml:

services:
  web:
    image: nginx:1.30-alpine
    ports:
      - "8080:80"
    volumes:
      - ./site:/usr/share/nginx/html:ro

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - pgdata:/var/lib/postgresql

  adminer:
    image: adminer
    ports:
      - "8081:8080"
    depends_on:
      - db

volumes:
  pgdata:

Os três serviços:

ServiçoFunção
webnginx, que usa a pasta ./site como site, na porta 8080 do host
dbPostgreSQL 18; os dados ficam no Volume chamado pgdata (atenção: a montagem da versão 18 é em /var/lib/postgresql; consulte Volume)
adminerFerramenta web de administração de banco de dados, na porta 8081 do host

Para escrever a mesma configuração com docker run, você precisaria primeiro executar docker network create e docker volume create e, em seguida, executar três comandos docker run bem longos.

Inicialização: docker compose up

Execute na pasta compose-demo:

$ docker compose up -d
[+] up 34/34
 ✔ Image nginx:1.30-alpine          Pulled                                                      7.8s
 ✔ Image adminer                    Pulled                                                      8.7s
 ✔ Network compose-demo_default     Created                                                     0.1s
 ✔ Volume compose-demo_pgdata       Created                                                     0.0s
 ✔ Container compose-demo-web-1     Started                                                     1.7s
 ✔ Container compose-demo-db-1      Started                                                     0.8s
 ✔ Container compose-demo-adminer-1 Started                                                     1.0s

Um único comando fez tudo: baixou as imagens (Pulled, algo que só acontece na primeira vez), criou a rede e o Volume e iniciou os três contêineres.

$ docker compose ps
NAME                     IMAGE               COMMAND                  SERVICE   CREATED          STATUS          PORTS
compose-demo-adminer-1   adminer             "entrypoint.sh docke…"   adminer   10 seconds ago   Up 9 seconds    0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp
compose-demo-db-1        postgres:18         "docker-entrypoint.s…"   db        10 seconds ago   Up 10 seconds   5432/tcp
compose-demo-web-1       nginx:1.30-alpine   "/docker-entrypoint.…"   web       10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

$ docker network ls --filter name=compose-demo
NETWORK ID     NAME                   DRIVER    SCOPE
a722da926fbd   compose-demo_default   bridge    local

$ docker volume ls --filter name=compose-demo
DRIVER    VOLUME NAME
local     compose-demo_pgdata
  • O nome do contêiner segue o formato nome-do-projeto-nome-do-serviço-número. Por padrão, o nome do projeto é o da pasta (compose-demo), então projetos em pastas diferentes não interferem uns nos outros.
  • O Compose criou automaticamente a rede compose-demo_default. Os três serviços estão nela e podem se conectar entre si usando o nome do serviço.
  • O nome real do Volume pgdata é compose-demo_pgdata.
  • db não tem ports configurado, então o campo PORTS mostra apenas 5432/tcp; não é possível acessá-lo de fora.

Abra http://localhost:8080:

nginx iniciado pelo Compose exibindo site/index.html
O serviço web exibe o conteúdo de site/index.html

Gerencie o banco de dados com o Adminer

Ao abrir http://localhost:8081, você verá a tela de login do Adminer. Observe que System é MySQL por padrão:

Tela de login do Adminer com System definido como MySQL por padrão
Padrão do Adminer: System é MySQL / MariaDB, e Server já vem preenchido com db

Faça login com as configurações abaixo:

CampoPreencha com
SystemPostgreSQL (é obrigatório alterar, caso contrário, a conexão será feita como MySQL e falhará)
Serverdb (nome do serviço, resolvido pela rede do Compose)
Usernamepostgres
Passwordexample (POSTGRES_PASSWORD em compose.yaml)
Tela de login do Adminer com PostgreSQL selecionado em System
Altere System para PostgreSQL e clique em Login

Após fazer login, a tela exibirá a versão do PostgreSQL e a lista de bancos de dados:

Versão do PostgreSQL e lista de bancos de dados exibidas após o login no Adminer
O Adminer se conecta ao PostgreSQL do serviço db pela rede do Compose

Clique em SQL command à esquerda e insira o SQL:

CREATE TABLE guestbook (id serial PRIMARY KEY, name text, message text);
INSERT INTO guestbook (name, message) VALUES ('Docker', 'Hello from Compose!');
SELECT * FROM guestbook;
Tela de entrada de SQL em SQL command no Adminer
Insira o SQL em SQL command e clique em Execute

Clique em Execute para executar os três comandos em sequência. O SELECT final lista os dados que você acabou de adicionar:

Resultado da execução de SQL no Adminer
Criação da tabela, adição de um registro e resultado da consulta

Consulte os logs

$ docker compose logs --tail 2
web-1  | 2026/10/13 00:14:23 [notice] 1#1: start worker processes
web-1  | 2026/10/13 00:14:23 [notice] 1#1: start worker process 30
db-1   | 2026-10-13 00:14:24.205 UTC [71] LOG:  database system was shut down at 2026-10-13 00:14:24 UTC
db-1   | 2026-10-13 00:14:24.210 UTC [1] LOG:  database system is ready to accept connections
adminer-1  | [Tue Oct 13 00:14:22 2026] PHP 8.4.26 Development Server (http://[::]:8080) started

docker compose logs combina e exibe os logs de todos os serviços, com o nome do serviço no início de cada linha. --tail 2 exibe apenas as 2 últimas linhas de cada serviço, -f acompanha os logs continuamente, e docker compose logs db exibe somente os logs de db.

Pare e inicie

$ docker compose stop
[+] stop 3/3
 ✔ Container compose-demo-adminer-1 Stopped                                                     0.4s
 ✔ Container compose-demo-web-1     Stopped                                                     0.4s
 ✔ Container compose-demo-db-1      Stopped                                                     0.3s

$ docker compose ps -a
NAME                     IMAGE               COMMAND                  SERVICE   CREATED          STATUS                              PORTS
compose-demo-adminer-1   adminer             "entrypoint.sh docke…"   adminer   53 seconds ago   Exited (0) Less than a second ago
compose-demo-db-1        postgres:18         "docker-entrypoint.s…"   db        53 seconds ago   Exited (0) Less than a second ago
compose-demo-web-1       nginx:1.30-alpine   "/docker-entrypoint.…"   web       53 seconds ago   Exited (0) Less than a second ago

$ docker compose start
[+] start 3/3
 ✔ Container compose-demo-db-1      Started                                                     0.3s
 ✔ Container compose-demo-web-1     Started                                                     1.0s
 ✔ Container compose-demo-adminer-1 Started                                                     0.4s

stop apenas para os contêineres (Exited (0)); os contêineres, a rede e o Volume continuam lá. start os inicia novamente.

down: remova os contêineres, mas mantenha os dados

$ docker compose down
[+] down 4/4
 ✔ Container compose-demo-adminer-1 Removed                                                     0.7s
 ✔ Container compose-demo-web-1     Removed                                                     0.7s
 ✔ Container compose-demo-db-1      Removed                                                     0.3s
 ✔ Network compose-demo_default     Removed                                                     0.1s

down removeu os contêineres e a rede, mas não removeu o Volume. Execute up novamente, e os dados continuarão lá:

$ docker compose up -d
[+] up 4/4
 ✔ Network compose-demo_default     Created                                                     0.1s
 ✔ Container compose-demo-web-1     Started                                                     0.7s
 ✔ Container compose-demo-db-1      Started                                                     1.1s
 ✔ Container compose-demo-adminer-1 Started                                                     1.6s

$ docker compose exec db psql -U postgres -c "SELECT * FROM guestbook;"
 id |  name  |       message
----+--------+---------------------
  1 | Docker | Hello from Compose!
(1 row)

down -v: remova também os dados

$ docker compose down -v
[+] down 5/5
 ✔ Container compose-demo-adminer-1 Removed                                                     0.7s
 ✔ Container compose-demo-web-1     Removed                                                     0.7s
 ✔ Container compose-demo-db-1      Removed                                                     0.2s
 ✔ Volume compose-demo_pgdata       Removed                                                     0.1s
 ✔ Network compose-demo_default     Removed                                                     0.1s

A opção -v também remove o Volume compose-demo_pgdata, apagando os dados do banco de dados. Tenha cuidado ao usar down -v em produção.

Resumo das operações básicas

docker compose up -d        # Cria e inicia todos os serviços em segundo plano
docker compose ps           # Verifica o status dos serviços
docker compose logs -f      # Acompanha os logs de todos os serviços
docker compose logs -f db   # Mostra apenas db
docker compose stop         # Para (os contêineres são mantidos)
docker compose start        # Inicia novamente
docker compose down         # Para e remove os contêineres e a rede (o Volume é mantido)
docker compose down -v      # Remove também o Volume (os dados serão perdidos!)

Depois de modificar compose.yaml, execute docker compose up -d novamente. O Compose recria apenas os serviços que foram alterados (veja o exemplo em Comandos do docker compose).

Nome do projeto e nome do arquivo

  • Por padrão, o nome do projeto é o nome da pasta. Você também pode especificar name: myproject no início de compose.yaml ou usar docker compose -p myproject.
  • Por padrão, o Compose procura, nesta ordem, por compose.yaml, compose.yml, docker-compose.yaml e docker-compose.yml. Para projetos novos, recomendamos usar compose.yaml.
  • version: "3.8" no início do arquivo é uma sintaxe antiga. Atualmente, não é mais necessário e, se você incluí-lo, apenas receberá um aviso.

Próximos passos

Recapitulação

  • compose.yaml descreve vários serviços, redes e Volumes, que podem ser iniciados todos com um único comando.
  • O Compose cria automaticamente uma rede para o projeto, e os serviços se conectam uns aos outros usando os nomes dos serviços.
  • docker compose down mantém o Volume; down -v exclui os dados.
  • O Docker Desktop exibe os projetos do Compose agrupados.

Exercícios

Exercício 1: No projeto deste capítulo, use um único comando para ver apenas as 5 últimas linhas de log do serviço db.

Resposta
docker compose logs --tail 5 db

Exercício 2: Depois de executar docker compose down e, em seguida, up -d, as tabelas criadas no Adminer ainda estarão lá? E se você usar down -v?

Resposta

Depois de down, os dados continuam lá porque o Volume pgdata é mantido; down -v exclui o Volume, o banco de dados é inicializado novamente e as tabelas desaparecem.

Perguntas frequentes

Qual é a diferença entre docker-compose e docker compose?

docker-compose (com hífen) é o programa independente v1, que não recebe mais manutenção; hoje, use o plugin docker compose da Docker CLI (com espaço). Este tutorial usa a v5.

Tanto compose.yaml quanto docker-compose.yml funcionam?

Sim. O Compose procura os arquivos nessa ordem. Para novos projetos, recomendamos compose.yaml.

Como o nome do projeto é definido?

Por padrão, é o nome da pasta onde está o compose.yaml. Os nomes dos contêineres, da rede e do Volume recebem esse nome como prefixo. Você pode defini-lo com name: ou -p.

Atualizado 14 de outubro de 2026