Projeto App com Docker

Neste laboratório você coloca no ar duas aplicações com Docker Compose: o Uptime Kuma, um painel que vigia se sites estão no ar, e um pequeno site servido pelo nginx. Tudo descrito num único arquivo, que liga, desliga, atualiza e recria as aplicações com um comando.

Ao terminar você terá
  • O Docker instalado e o seu usuário autorizado a usá-lo.
  • Um arquivo compose.yaml com dois serviços, portas e volumes.
  • Os dados do Uptime Kuma num volume, que sobrevive à recriação dos containers.
  • Um procedimento testado de atualização e de backup do volume.
ItemDetalhe
Tempo estimado1h
Pré-requisitosComo Usar os Projetos, Docker, Docker Compose, tar
Onde rodaVM lab (servidor) + navegador do notebook
Saídas ilustrativas

As versões das imagens e do Docker mudam com frequência. Os números nas saídas abaixo são exemplos; o formato é o que importa.


As etapas

  1. Preparar a VM

    $ multipass launch 26.04 --name lab --disk 15G --memory 2G
    Launched: lab
    $ multipass list
    Name                    State             IPv4             Image
    lab                     Running           10.85.140.27     Ubuntu 26.04 LTS
    $ multipass shell lab

    Usamos 15 GB de disco porque imagens de containers ocupam espaço.

  2. Instalar o Docker

    O que vamos fazer e por quê: o Ubuntu traz o Docker nos repositórios oficiais: docker.io é o motor e docker-compose-v2 adiciona o comando docker compose. Depois, colocamos o usuário no grupo docker, para não precisar de sudo em todo comando.

    $ sudo apt update && sudo apt install -y docker.io docker-compose-v2
    …
    $ sudo usermod -aG docker ubuntu
    $ exit

    Saia e entre de novo para o grupo novo valer:

    $ multipass shell lab
    $ docker run --rm hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    …
    Hello from Docker!                                « funcionou
    This message shows that your installation appears to be working correctly.
    …
    O grupo docker equivale a root

    Quem está no grupo docker consegue montar qualquer pasta do sistema dentro de um container e alterá-la. Só coloque nele quem já poderia ter sudo.

    Se deu errado: "permission denied while trying to connect to the Docker daemon socket"
    $ docker ps
    permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: …

    O que aconteceu: você não saiu e entrou de novo depois do usermod, então a sessão ainda não tem o grupo docker.

    Como confirmar: groups não mostra docker.

    Como resolver: exit e multipass shell lab.

  3. Escrever o compose.yaml

    O que vamos fazer e por quê: em vez de lembrar comandos docker run longos, descrevemos as aplicações num arquivo. Ele vira a "receita" do servidor: dá para versionar no Git e recriar tudo em outra máquina.

    $ mkdir -p ~/monitor/site && cd ~/monitor
    $ echo '<h1>Site no container</h1>' > site/index.html
    $ nano compose.yaml
    services:
      kuma:                                  # nome do serviço
        image: louislam/uptime-kuma:1        # imagem e versão (tag)
        container_name: kuma
        restart: unless-stopped              # volta sozinho após reboot ou falha
        ports:
          - "3001:3001"                      # porta da VM : porta do container
        volumes:
          - kuma-dados:/app/data             # volume nomeado: dados persistentes
    
      site:
        image: nginx:alpine
        container_name: site
        restart: unless-stopped
        ports:
          - "8080:80"
        volumes:
          - ./site:/usr/share/nginx/html:ro  # pasta da VM, só leitura (ro)
    
    volumes:
      kuma-dados:                            # declara o volume usado acima
    ConceitoNo arquivoSignificado
    Imagemimage: nginx:alpineO "molde" do container. O que vem depois do : é a versão (tag).
    Porta"8080:80"Quem acessar a VM na porta 8080 chega na porta 80 do container. Sempre fora:dentro.
    Volume nomeadokuma-dados:/app/dataUma área de dados gerenciada pelo Docker. Sobrevive quando o container é apagado.
    Bind mount./site:/usr/…/html:roUma pasta da VM aparece dentro do container. Você edita os arquivos direto na VM.
    restartunless-stoppedReinicia sempre, a não ser que você pare o container de propósito.

    Confira se deu certo: o próprio Compose valida o arquivo. Se houver erro de indentação, ele diz a linha:

    $ docker compose config --quiet && echo "arquivo válido"
    arquivo válido
  4. Subir as aplicações

    docker compose
    A ferramenta que lê o compose.yaml da pasta atual.
    up
    Cria e liga tudo o que está descrito.
    -d
    Detached: roda em segundo plano e devolve o terminal.
    $ docker compose up -d
    [+] Running 4/4
     ✔ Network monitor_default        Created
     ✔ Volume "monitor_kuma-dados"    Created           « o nome ganha o prefixo da pasta
     ✔ Container site                 Started
     ✔ Container kuma                 Started
    $ docker compose ps
    NAME   IMAGE                    COMMAND                  SERVICE   CREATED          STATUS                    PORTS
    kuma   louislam/uptime-kuma:1   "/usr/bin/dumb-init …"   kuma      40 seconds ago   Up 39 seconds (healthy)   0.0.0.0:3001->3001/tcp, [::]:3001->3001/tcp
    site   nginx:alpine             "/docker-entrypoint.…"   site      40 seconds ago   Up 39 seconds             0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

    Na primeira vez, antes dessas linhas, aparece o download (pull) das imagens. A coluna STATUS com Up significa rodando; (healthy) significa que o teste de saúde da própria imagem passou.

    Confira se deu certo: do notebook:

    $ curl http://10.85.140.27:8080
    <h1>Site no container</h1>

    E abra http://10.85.140.27:3001 no navegador: o Uptime Kuma pede para criar um usuário administrador.

    Se deu errado: "port is already allocated"

    O que aconteceu: outra coisa já usa a porta 8080 ou 3001 na VM.

    Como confirmar: sudo ss -tlnp | grep -E ':8080|:3001'.

    Como resolver: mude o número da esquerda, por exemplo "8081:80", e rode docker compose up -d de novo.

  5. Containers conversam pelo nome

    O que vamos fazer e por quê: o Compose cria uma rede própria (monitor_default), onde cada serviço é encontrado pelo nome. No Uptime Kuma, crie um monitor do tipo HTTP(s) com a URL http://site. Ele vai acessar o container do nginx pela rede interna, sem passar pela porta 8080.

    Confira pelo terminal:

    $ docker run --rm --network monitor_default alpine wget -qO- http://site
    <h1>Site no container</h1>                       « "site" virou um endereço dentro da rede

    Esse comando liga um container descartável (alpine) na mesma rede do projeto e pede a página ao endereço site.

  6. Ler os logs

    $ docker compose logs --tail 3 site
    site  | 10.85.140.1 - - [15/Oct/2026:15:02:11 +0000] "GET / HTTP/1.1" 200 30 "-" "curl/8.14.1" "-"
    site  | 172.18.0.3 - - [15/Oct/2026:15:04:40 +0000] "GET / HTTP/1.1" 200 30 "-" "Uptime-Kuma/1.23.16" "-"
    site  | 172.18.0.3 - - [15/Oct/2026:15:05:40 +0000] "GET / HTTP/1.1" 200 30 "-" "Uptime-Kuma/1.23.16" "-"

    A primeira linha veio do notebook; as outras, do Kuma vigiando o site a cada 60 segundos, pelo IP interno 172.18.0.3. Use docker compose logs -f para acompanhar ao vivo (Ctrl+C para sair).

  7. Provar que os dados persistem

    O que vamos fazer e por quê: containers são descartáveis; dados não podem ser. Vamos apagar os containers e recriá-los. O usuário e o monitor que você criou no Kuma precisam continuar lá.

    $ docker compose down
    [+] Running 3/3
     ✔ Container kuma                 Removed
     ✔ Container site                 Removed
     ✔ Network monitor_default        Removed
    $ docker volume ls
    DRIVER    VOLUME NAME
    local     monitor_kuma-dados                        « o volume NÃO foi apagado
    $ docker compose up -d
    …

    Confira se deu certo: abra o Kuma no navegador: o login e o monitor continuam lá.

    down -v apaga os volumes

    docker compose down -v remove também os volumes, ou seja, os dados. Só use quando quiser zerar tudo de propósito.

  8. Atualizar a aplicação

    O que vamos fazer e por quê: atualizar um container é trocar a imagem por uma mais nova e recriá-lo. Como os dados estão no volume, nada se perde.

    $ docker compose pull
    [+] Pulling 2/2
     ✔ kuma Pulled
     ✔ site Pulled
    $ docker compose up -d
    [+] Running 2/2
     ✔ Container site  Running                         « imagem igual: nada muda
     ✔ Container kuma  Started                         « imagem nova: container recriado
    $ docker image prune -f
    Total reclaimed space: 0B

    O image prune apaga imagens antigas que nenhum container usa mais, liberando disco. A tag :1 no compose.yaml garante que você recebe atualizações da versão 1, sem pular sozinho para uma versão nova que poderia ser incompatível.

  9. Backup e restauração do volume

    O que vamos fazer e por quê: um volume é uma pasta gerenciada pelo Docker. Para fazer backup, ligamos um container descartável (alpine) com o volume e uma pasta da VM, e usamos o tar para empacotar.

    $ docker compose stop kuma
    « parar evita copiar o banco no meio de uma escrita
    $ docker run --rm -v monitor_kuma-dados:/dados:ro -v "$PWD":/backup alpine \
        tar czf /backup/kuma-$(date +%F).tar.gz -C /dados .
    $ docker compose start kuma
    $ ls -lh kuma-*.tar.gz
    -rw-r--r-- 1 root root 1.2M Oct 15 15:20 kuma-2026-10-15.tar.gz
    docker run --rm
    Roda um container e apaga-o ao terminar.
    -v monitor_kuma-dados:/dados:ro
    O volume aparece em /dados, só leitura.
    -v "$PWD":/backup
    A pasta atual da VM aparece em /backup.
    alpine
    Uma imagem Linux minúscula, só para ter o tar.
    tar czf … -C /dados .
    Compacta o conteúdo de /dados num .tar.gz.

    Teste a restauração num volume novo, sem tocar no original:

    $ docker volume create kuma-teste
    kuma-teste
    $ docker run --rm -v kuma-teste:/dados -v "$PWD":/backup alpine \
        tar xzf /backup/kuma-2026-10-15.tar.gz -C /dados
    $ docker run --rm -v kuma-teste:/dados alpine ls /dados
    docker
    kuma.db                                           « o banco de dados do Kuma está lá
    screenshots
    upload
    $ docker volume rm kuma-teste

    Para restaurar de verdade: docker compose down, apague e recrie o volume monitor_kuma-dados, extraia o backup nele e rode docker compose up -d. A lista exata de arquivos dentro do volume pode variar com a versão do Kuma.

  10. Cuidado: o Docker passa por cima do ufw

    O que vamos fazer e por quê: o Docker cria regras de firewall próprias para as portas publicadas, que valem antes das regras do ufw. Vamos ver isso acontecer.

    $ sudo ufw allow OpenSSH && sudo ufw --force enable
    …
    Firewall is active and enabled on system startup
    $ sudo ufw status
    Status: active
    
    To                         Action      From
    --                         ------      ----
    OpenSSH                    ALLOW       Anywhere
    OpenSSH (v6)               ALLOW       Anywhere (v6)
    $ curl http://10.85.140.27:8080
    <h1>Site no container</h1>                       « continua acessível, mesmo sem regra no ufw!

    Como proteger: publique a porta só no próprio servidor, trocando "8080:80" por "127.0.0.1:8080:80". Assim, só o próprio servidor acessa, e você expõe a aplicação por um nginx na frente (proxy reverso, com HTTPS). Veja Servidor Web (nginx).


Quando não funciona

O container fica reiniciando
$ docker compose ps
NAME   IMAGE                    …   STATUS
kuma   louislam/uptime-kuma:1   …   Restarting (1) 5 seconds ago

O que aconteceu: o programa dentro do container está terminando com erro.

Como confirmar: docker compose logs --tail 30 kuma mostra o motivo, por exemplo uma permissão ou um volume errado.

"no configuration file provided: not found"

O que aconteceu: você rodou docker compose fora da pasta do projeto.

Como resolver: cd ~/monitor, ou use docker compose -f ~/monitor/compose.yaml ….

O disco encheu depois de várias atualizações

Como confirmar: docker system df mostra quanto ocupam imagens, containers e volumes.

Como resolver: docker image prune -a apaga as imagens que nenhum container usa. Volumes nunca são apagados por esse comando.


O que você aprendeu

  • Instalar o Docker pelos repositórios do Ubuntu e os riscos do grupo docker.
  • Descrever aplicações em compose.yaml: imagem, portas, volumes e restart.
  • up -d, ps, logs, exec, down, pull.
  • A diferença entre volume nomeado e bind mount, e que down -v apaga dados.
  • Fazer e testar o backup de um volume com um container descartável.
  • Que portas publicadas pelo Docker ignoram o ufw.

Desafios extras

  1. Coloque um nginx na frente do Kuma como proxy reverso em http://kuma.lab, e publique a porta 3001 só em 127.0.0.1.
  2. Automatize o backup do volume com o script e o timer do Backup Automático.
  3. Guarde a pasta ~/monitor num repositório Git e recrie tudo numa VM nova só com git clone e docker compose up -d.

Desfazer e limpar

$ docker compose down -v
« aqui sim: apaga containers E volumes
$ exit
$ multipass delete --purge lab

Exercícios

1. Subir em segundo plano

Complete o comando que cria e liga tudo, devolvendo o terminal:

docker compose up

2. Porta

Complete para que a porta 9000 da VM leve à porta 80 do container:

ports: - ""

3. Você rodou docker compose down. O que aconteceu com o volume monitor_kuma-dados?

4. O ufw só libera SSH, mas a porta 8080 de um container continua acessível. Por quê?