Rode seus primeiros containers Docker
Baixe uma imagem oficial do Docker Hub e rode, inspecione e destrua containers reais pela linha de comando. Aprenda o modelo mental imagem-vs-container na prática — a base sobre a qual toda outra habilidade de Docker é construída.
Problema
"Funciona na minha máquina" é o bug mais antigo do software. Seu app roda localmente e quebra em staging porque a versão do Python, uma biblioteca de sistema ou uma variável de ambiente é diferente. O Docker mata essa classe de problema empacotando uma aplicação junto com tudo que ela precisa numa **imagem**, e rodando-a num **container** isolado que se comporta igual em qualquer lugar. Mas antes de conseguir containerizar seus próprios apps, você precisa de fluência no ciclo básico: achar uma imagem confiável, baixá-la, rodá-la como container, olhar dentro de um container em execução, ler seus logs e limpar tudo. Pule isso e todo tópico seguinte (Dockerfiles, Compose, redes, volumes) vira uma mágica que você não sabe depurar. Neste lab você vai rodar containers reais a partir de imagens oficiais, expor um servidor web ao seu navegador, entrar (exec) num container vivo e gerenciar o ciclo de vida completo — para que o vocabulário vire memória muscular.
Objetivos
- Explicar a diferença entre uma imagem (o blueprint) e um container (uma instância em execução)
- Achar e avaliar uma imagem confiável no Docker Hub, preferindo imagens oficiais e tags fixas em vez de
latest - Baixar uma imagem com
docker pulle listar o que você tem comdocker images - Rodar um container em segundo plano com
docker run, publicando uma porta para o navegador alcançá-lo - Inspecionar containers em execução com
docker ps, ler a saída comdocker logse obter um shell dentro comdocker exec - Gerenciar o ciclo de vida completo: parar, iniciar, remover containers e remover imagens, deixando o host limpo
Pré-requisitos
- Docker instalado e rodando (Docker Desktop no Windows/macOS, ou Docker Engine no Linux). Rode
docker version— se imprimir uma seção Client e uma Server, você está pronto. - Um terminal (PowerShell, bash ou zsh) e um navegador
- Acesso à internet para alcançar o Docker Hub nos downloads de imagem
- Git instalado, para entregar seu deliverable no fim
- Nenhum conhecimento prévio de Docker é exigido — este é o ponto de entrada da trilha de Docker
O que você vai construir
Você não vai escrever nenhum código de aplicação neste lab. Em vez disso, vai rodar um servidor
web real (nginx) dentro de um container, alcançá-lo pelo navegador, olhar dentro do container
em execução e depois limpar tudo — usando só a CLI do Docker. No fim, os comandos centrais
(pull, run, ps, logs, exec, stop, rm) vão parecer rotina.
O modelo mental essencial: imagem vs container
Quase toda confusão com Docker vem de embaralhar essas duas palavras. Mantenha-as afiadas:
| Conceito | O que é | Analogia |
|---|---|---|
| Imagem | Um pacote imutável e somente-leitura: app + runtime + bibliotecas + config, construído em camadas | Uma receita, ou uma classe no código |
| Container | Uma instância em execução de uma imagem, com sua própria camada gravável, isolada do host | O bolo feito a partir da receita, ou um objeto instanciado de uma classe |
Uma imagem pode gerar muitos containers, do mesmo jeito que uma classe cria muitos objetos.
A imagem nunca muda quando um container roda — o container ganha sua própria camada gravável
fina por cima. É por isso que containers são baratos de criar e descartar, e por que a mesma
imagem se comporta identicamente no seu laptop e em produção.
De onde vêm as imagens
Imagens ficam em registries. O registry público padrão é o Docker Hub
(hub.docker.com). Quando você faz docker pull nginx, o Docker busca no Docker Hub a menos que
você diga o contrário. Existem outros registries (Amazon ECR, Google GCR, Azure ACR) para
imagens privadas ou integradas à nuvem, mas o Docker Hub é onde você começa.
Como trabalhar neste lab
Faça os passos em ordem — cada comando se apoia no anterior. Rode cada comando você mesmo e leia
a saída real; não só passe o olho. No caminho você vai coletar as saídas que precisa para a
entrega do Passo 6.
Passos
-
Confirme que o Docker está rodando e entenda a divisão
Antes de baixar qualquer coisa, confirme que seu engine está vivo e fixe a ideia de imagem-vs-container.
Verifique a instalação
Rode:
docker versionVocê deve ver dois blocos:
Client(a CLI onde você digita) eServer/Engine
(o daemon que de fato roda os containers). Se o bloco Server estiver faltando ou você receber
um erro "cannot connect to the Docker daemon", inicie o Docker Desktop (Windows/macOS) ou
rodesudo systemctl start docker(Linux) e tente de novo.Agora rode:
docker infoRepare na linha que informa quantas imagens e containers você tem no momento — provavelmente
zero de cada numa instalação nova. Você vai ver esses números mudarem ao longo do lab.A arquitetura em uma frase
Você digita comandos no cliente Docker; ele os envia ao daemon Docker, que baixa
imagens de um registry e as roda como containers.Checkpoint
Responda antes de continuar:
- Se você rodar a mesma imagem três vezes, quantas imagens e quantos containers existem? (Uma imagem, três containers.)
- Rodar um container muda a imagem de onde ele veio? (Não — a imagem é imutável; o container ganha sua própria camada gravável.)
- De onde
docker pull nginxbaixa por padrão? (Do Docker Hub, o registry padrão.)
Se alguma resposta pareceu insegura, releia "O modelo mental essencial" na visão geral. Tudo
abaixo assume que você distingue uma imagem de um container. -
Baixe uma imagem oficial e fixe uma tag
Agora busque uma imagem real. Você vai usar o nginx, um servidor web popular, porque é
pequeno, oficial e te dá algo para abrir no navegador.Escolha uma imagem confiável
No Docker Hub, prefira imagens marcadas como Official ou Verified Publisher. Imagens
oficiais (comonginx,postgres,python) são mantidas e revisadas em segurança pelo Docker
ou pelo projeto upstream. Imagens da comunidade podem ser ótimas, mas não são verificadas —
cheque a data de última atualização, o número de downloads e se o Dockerfile de origem está
publicado antes de confiar numa em algo sério.Baixe
docker pull nginx:1.27-alpineObserve a saída: o Docker baixa várias camadas (layers) e reporta
Pull completepara cada.
Essas camadas são os blocos de construção da imagem — compartilhadas e cacheadas, então o
próximo pull de uma imagem relacionada as reaproveita em vez de rebaixar.Por que
1.27-alpinee não sónginxUma tag identifica uma versão da imagem.
docker pull nginxsignifica implicitamente
nginx:latest, que é um alvo móvel — muda sempre que os mantenedores publicam uma nova
versão. Em projetos reais essa imprevisibilidade te morde: um rebuild silenciosamente pega uma
versão diferente.-
nginx:latest→ o que for mais novo neste momento (evite em qualquer coisa que queira reproduzir) -
nginx:1.27-alpine→ fixado na linha 1.27, sobre a base pequena Alpine Linux (previsível)
Fixar uma tag específica é o hábito mais importante para containers reproduzíveis. A variante
-alpinetambém é bem menor, o que significa pulls mais rápidos e uma superfície de ataque menor.Verifique o que você tem
docker imagesVocê deve ver uma linha para
nginxcom a tag1.27-alpine, um ID de imagem e um tamanho
(o Alpine mantém em torno de ~50 MB). Seu host foi de zero imagens para uma.Entregável deste passo: a saída de
docker imagesmostrando a imagem nginx presente. -
-
Rode um container e alcance-o no navegador
Uma imagem parada ali não faz nada. Transforme-a num container em execução.
Inicie o nginx
docker run -d -p 8080:80 --name web nginx:1.27-alpineLeia cada flag — elas importam:
-
-d(detached) → roda em segundo plano e devolve seu prompt, em vez de sequestrar o terminal. -
-p 8080:80(publish) → mapeia a porta8080do seu host para a porta80dentro do container. O formato é sempreHOST:CONTAINER. O nginx escuta na 80 por dentro; você o alcança na 8080 por fora. -
--name web→ dá ao container um nome amigável para você não ter que usar o ID aleatório. -
nginx:1.27-alpine→ a imagem a instanciar.
O Docker imprime uma longa string hexadecimal — o ID do container. Seu container está rodando.
Veja no navegador
Abra http://localhost:8080 — você deve ver a página "Welcome to nginx!". O tráfego bateu na
porta 8080 da sua máquina, o Docker o encaminhou para a porta 80 no container, o nginx respondeu.
Esse mapeamento de porta é todo o truque de expor serviços containerizados.Prove o isolamento
Rode um segundo container a partir da mesma imagem numa porta de host diferente:
docker run -d -p 8081:80 --name web2 nginx:1.27-alpineAbra http://localhost:8081 — um segundo nginx, independente, da mesma única imagem. Dois
containers, uma imagem: exatamente o modelo da visão geral. Se você tentasse reusar a porta de
host 8080 receberia um erro "port is already allocated", porque só um processo pode dono de uma
porta de host.Entregável deste passo: anote a URL que funcionou (http://localhost:8080) e o fato de que
dois containers rodaram de uma imagem. -
-
Inspecione um container em execução: ps, logs, exec
Um container em execução não é uma caixa-preta. Estes três comandos são como você observa e
depura um.Liste o que está rodando
docker psVocê verá
webeweb2, cada um com sua imagem, status (Up ...) e o mapeamento de porta
(0.0.0.0:8080->80/tcp). Adicione-apara ver também containers parados:docker ps -aLeia os logs
Os logs de todo container são o que seu processo principal escreveu em stdout/stderr. Atualize
http://localhost:8080 algumas vezes no navegador e então:docker logs webVocê verá as linhas de log de acesso do nginx para as requisições que acabou de fazer. Para
acompanhar os logs ao vivo (comotail -f), adicione-f:docker logs -f webAperte
Ctrl+Cpara parar de acompanhar — isso para de acompanhar os logs, não o container.Obtenha um shell dentro
docker execroda um comando dentro de um container já em execução. Abra um shell interativo:docker exec -it web sh-
-imantém a entrada aberta,-tte dá um terminal — juntos-it= uma sessão interativa. -
shé o shell (a imagem Alpine não inclui bash, mas temsh).
Agora você está dentro do container. Experimente:
ls /usr/share/nginx/html # a raiz web do nginx cat /etc/os-release # repare que diz Alpine Linux, não o SO do seu host exit # saia do shell do containerO
cat /etc/os-releaseé o "aha": o container roda Alpine Linux independentemente do que seu
host é. Esse é o isolamento que o Docker te dá — um ambiente autocontido empacotado na imagem.Entregável deste passo: a saída de
docker pse uma cópia de algumas linhas dedocker logs web. -
-
Gerencie o ciclo de vida: parar, iniciar, remover, limpar
Containers foram feitos para serem descartáveis. Pratique pará-los e removê-los para seu host ficar limpo.
Pare e inicie
Um container parado ainda existe — mantém sua camada gravável e pode ser reiniciado:
docker stop web docker ps # 'web' sumiu da lista de rodando docker ps -a # mas ainda listado, com status 'Exited' docker start web # traga de voltastoppede ao processo para desligar graciosamente; após um timeout o Docker o mata à força.
Reiniciar reusa o mesmo container (e sua camada gravável), o que é diferente dedocker run, que
sempre cria um novo.Remova containers
Para deletar um container você precisa pará-lo antes (ou forçar):
docker stop web web2 docker rm web web2docker rmdeleta o container e sua camada gravável permanentemente. A imagem fica intacta —
confirme:docker ps -a # web e web2 sumiram docker images # nginx:1.27-alpine ainda está aquiEsse é o ganho da divisão imagem/container: você jogou fora dois containers, mas a imagem (o
blueprint reusável) permanece, pronta para gerar novos containers instantaneamente.Remova a imagem
Quando você realmente não precisar mais da imagem:
docker rmi nginx:1.27-alpine docker images # de volta ao vazioDica de limpeza
Para recuperar espaço de todos os containers parados, redes não usadas e imagens órfãs de uma vez:
docker system pruneEle pede confirmação e só toca em recursos não usados — seguro para limpeza, mas leia o que ele
lista antes de digitary.Entregável deste passo: confirme com
docker ps -aedocker imagesque seu host está limpo
(sem containersweb/web2sobrando). -
Entregue: documente sua execução de container
Prove que você rodou o ciclo completo capturando a evidência num pequeno repositório.
Monte sua entrega
Crie uma pasta, inicialize o git e escreva um arquivo chamado
SUBMISSION.mddocumentando o que
você fez. Cole as saídas reais que coletou — não texto inventado.# Docker Lab 1 — Rode seus primeiros containers ## 1. docker images (após o pull) <cole sua saída de `docker images` mostrando nginx:1.27-alpine> ## 2. docker ps (com web e web2 rodando) <cole sua saída de `docker ps`> ## 3. Verificação no navegador Abri http://localhost:8080 e vi a página "Welcome to nginx!". (sim / não) Rodei um segundo container na 8081 a partir da mesma imagem. (sim / não) ## 4. docker logs web (algumas linhas) <cole algumas linhas do log de acesso> ## 5. Dentro do container Saída de `cat /etc/os-release` dentro do `web`: <cole — deve mencionar Alpine Linux> ## 6. Host limpo <cole `docker ps -a` e `docker images` mostrando que web/web2 sumiram> ## Reflexão (2-3 frases) Nas minhas palavras: a diferença entre uma imagem e um container, e por que eu fixo uma tag em vez de usar `latest`.Entregue
git init git add SUBMISSION.md git commit -m "Docker lab 1 — primeiros containers" # faça push para um repo público ou crie um gist, depois entregue essa URLEntregue a URL do repositório ou gist como seu deliverable do lab.
Critério de submissão (autoverificação)
- A saída de
docker imagesmostra a imagem nginx fixada (nãolatest) - A saída de
docker psmostra ao menos um container rodando com um mapeamento de portaHOST:80 - Você confirmou que a página de boas-vindas do nginx carregou no navegador
- A saída de
docker logsestá incluída, mostrando linhas reais de requisição - A saída de
cat /etc/os-releasemostra o SO do container (Alpine), provando que você entrou (exec) dentro - Um
docker ps -a/docker imagesfinal mostra um host limpo - Sua reflexão diz corretamente, nas suas palavras, imagem vs container e por que fixar a tag ganha do
latest
O que vem a seguir
Você já sabe rodar e gerenciar containers a partir de imagens existentes. No próximo lab de
Docker você vai no sentido oposto: escrever um Dockerfile e construir sua própria imagem,
transformando seu código num container portátil que você controla de ponta a ponta. - A saída de