Ubuntu Docker

O Docker roda programas dentro de containers: caixas isoladas que já trazem tudo o que o programa precisa. Com ele você sobe um servidor web, um banco de dados ou um app inteiro com um comando, sem bagunçar o seu sistema, e apaga tudo com outro comando.

Você vai aprender
  • A diferença entre container, imagem e máquina virtual.
  • As duas formas de instalar o Docker no Ubuntu, e qual escolher.
  • O que cada parte de docker run -d -p 8080:80 --name web nginx faz.
  • Como guardar dados fora do container com volumes.
  • Como criar a sua própria imagem com um Dockerfile.
  • O que fazer com "permission denied", "port is already allocated" e container que morre na hora.

Os exemplos acontecem na máquina fictícia notebook, usuária ana. As saídas do Docker mudam um pouco entre versões (IDs, tamanhos, números de versão): trate-as como ilustrativas.


Conceito: imagem, container e VM

Três palavras aparecem o tempo todo. Pense numa receita de bolo:

PalavraAnalogiaO que é de verdade
ImagemA receitaUm pacote somente-leitura com o programa e tudo de que ele precisa (bibliotecas, configurações). Ex.: nginx, postgres, ubuntu.
ContainerO bolo feitoUma imagem rodando. Da mesma imagem saem quantos containers você quiser.
RegistroO livro de receitasOnde as imagens ficam guardadas. O padrão é o Docker Hub.

E qual a diferença para uma máquina virtual (veja KVM)?

Container (Docker)Máquina virtual (KVM, VirtualBox)
KernelUsa o kernel do próprio UbuntuTem kernel próprio
Sobe emMenos de 1 segundoDezenas de segundos
Tamanho típicoDezenas a centenas de MBVários GB
Roda outro sistema?Só Linux (outra distribuição, sim)Qualquer um, até Windows
IsolamentoBom, mas compartilha o kernelMais forte
Melhor paraRodar apps e serviçosRodar um sistema inteiro

Instalar: duas formas

Existem dois pacotes diferentes, de fontes diferentes. Os dois funcionam; não instale os dois juntos.

docker.io (do Ubuntu)docker-ce (oficial da Docker Inc.)
De onde vemRepositório do próprio UbuntuRepositório da Docker (download.docker.com)
InstalaçãoUm apt installAdicionar chave e repositório antes
VersãoUm pouco mais antiga, testada pelo UbuntuSempre a mais nova
Atualizações de segurançaPelo Ubuntu, junto com o sistemaPela Docker
ComposePacote docker-compose-v2Pacote docker-compose-plugin
Para quemQuem está aprendendo e a maioria dos servidoresQuem precisa de um recurso recente

Forma 1: pacote do Ubuntu (recomendada para começar)

sudo
Instalar programas exige administrador.
apt install
Instala pacotes (veja apt).
docker.io
O motor do Docker (o daemon) e o comando docker.
docker-compose-v2
O comando docker compose, para vários containers (veja Docker Compose).
$ sudo apt update
$ sudo apt install docker.io docker-compose-v2
[sudo: authenticate] Senha:
…
Configurando docker.io …
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
$ systemctl is-active docker
active                                         « o serviço já está rodando
$ docker --version
Docker version 28.2.2, build 28.2.2-0ubuntu1   « número ilustrativo

Forma 2: repositório oficial da Docker

Siga sempre o passo a passo atual em docs.docker.com/engine/install/ubuntu. Em resumo: remova pacotes antigos, adicione a chave em /etc/apt/keyrings, adicione o repositório (veja Repositórios e PPAs) e instale:

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Usar sem sudo: o grupo docker

O comando docker conversa com o serviço por um arquivo especial, o socket /var/run/docker.sock. Só o root e quem está no grupo docker podem usá-lo. Sem isso, você vê:

$ docker ps
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/containers/json": dial unix /var/run/docker.sock: connect: permission denied
sudo usermod
Altera uma conta de usuário (veja Usuários e Grupos).
-aG docker
-a = acrescentar, -G docker = ao grupo docker. Sem o -a, você sairia dos outros grupos (inclusive do sudo).
$USER
Variável com o seu nome de usuário (ana).
$ sudo usermod -aG docker $USER
$ groups
ana adm cdrom sudo dip plugdev users lpadmin   « docker ainda não aparece
$ newgrp docker
$ groups
docker adm cdrom sudo dip plugdev users lpadmin ana
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES   « funcionou (lista vazia)

O grupo novo só vale em sessões novas. O newgrp docker resolve no terminal atual; para valer em tudo, saia da sessão e entre de novo.

Atenção: grupo docker = poder de root

Quem está no grupo docker pode montar o disco inteiro dentro de um container e mexer em qualquer arquivo do sistema. Em servidores com várias pessoas, coloque no grupo só quem já teria sudo. Uma alternativa mais segura é o modo rootless do Docker.


O primeiro container: hello-world

docker
O programa cliente: ele só pede coisas ao serviço (daemon).
run
Subcomando: criar um container a partir de uma imagem e rodá-lo.
hello-world
O nome da imagem. Sem :versão, o Docker usa :latest.
$ docker run hello-world
Unable to find image 'hello-world:latest' locally         « não tinha a imagem aqui…
latest: Pulling from library/hello-world                  « …então baixou do Docker Hub
e6590344b1a5: Pull complete
Digest: sha256:ec153840d1e635ac434fab5e377081f17e0e15afab27beb3f726c3265039cfff
Status: Downloaded newer image for hello-world:latest

Hello from Docker!                                         « daqui para baixo é o programa rodando
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
…

Leia a saída em duas partes. As 5 primeiras linhas são o Docker baixando a imagem, o que só acontece na primeira vez. O resto é o programa de dentro do container, que imprime a mensagem e termina. Quando o programa termina, o container para.

O que o comando devolve

docker run devolve o código de saída do programa de dentro do container. Isso permite usar containers em scripts:

$ docker run --rm ubuntu true
$ echo $?
0
$ docker run --rm ubuntu false
$ echo $?
1                              « o "false" de dentro do container falhou
$ docker run --rm ubuntu comando-que-nao-existe
docker: Error response from daemon: failed to create task for container: … exec: "comando-que-nao-existe": executable file not found in $PATH: unknown
$ echo $?
127

Um servidor de verdade: nginx

Agora um container que fica rodando: o servidor web nginx. É aqui que entram as opções mais usadas.

docker run
Cria e roda um container.
-d
detached, "desacoplado": roda em segundo plano e devolve o terminal.
-p 8080:80
publish: a porta 8080 do Ubuntu leva à porta 80 do container. Formato host:container.
--name web
Um nome fácil. Sem ele, o Docker inventa um (ex.: quirky_lovelace).
nginx
A imagem.
$ docker run -d -p 8080:80 --name web nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
…
Status: Downloaded newer image for nginx:latest
9b1f2c7a0d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a   « o ID completo do container novo
$ curl -s localhost:8080 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>           « o nginx respondeu pela porta 8080

Abra http://localhost:8080 no navegador e você verá a página "Welcome to nginx!".

Ver os containers: docker ps

$ docker ps
CONTAINER ID   IMAGE   COMMAND                  CREATED          STATUS          PORTS                                     NAMES
9b1f2c7a0d3e   nginx   "/docker-entrypoint.…"   12 seconds ago   Up 11 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   web
ColunaSignificado
CONTAINER IDOs 12 primeiros caracteres do ID. Você pode usá-lo no lugar do nome.
IMAGEDe qual imagem o container nasceu.
COMMANDO programa que roda dentro (cortado com "…").
CREATED / STATUSQuando foi criado e se está Up (rodando) ou Exited (parado).
PORTS0.0.0.0:8080->80/tcp = porta 8080 de todas as interfaces do Ubuntu → porta 80 do container.
NAMESO nome que você deu com --name.

docker ps mostra só os que estão rodando. docker ps -a (de all) mostra também os parados.

Logs, entrar no container, parar e apagar

$ docker logs --tail 2 web
172.17.0.1 - - [15/Oct/2026:13:30:02 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.14.1" "-"
172.17.0.1 - - [15/Oct/2026:13:30:09 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "-" "Mozilla/5.0 …" "-"
$ docker exec -it web bash
docker exec
Roda um comando dentro de um container que já está rodando.
-it
-i mantém a entrada aberta e -t cria um terminal: juntos, deixam você digitar lá dentro.
web
O container.
bash
O programa a rodar: um shell.

Agora o prompt muda: você está dentro do container, como root dele (não do Ubuntu).

#> cat /etc/os-release | head -1
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"     « a imagem do nginx é baseada em Debian
#> ls /usr/share/nginx/html
50x.html  index.html
#> exit
exit
$ docker stop web
web
$ docker ps -a
CONTAINER ID   IMAGE   COMMAND                  CREATED         STATUS                     PORTS   NAMES
9b1f2c7a0d3e   nginx   "/docker-entrypoint.…"   5 minutes ago   Exited (0) 3 seconds ago           web
$ docker start web
web
$ docker rm -f web
web                                        « -f para e apaga de uma vez
Container descartável: --rm

Com docker run --rm, o container é apagado sozinho quando termina. Use para testes rápidos, como docker run --rm -it ubuntu:26.04 bash, que abre um Ubuntu limpo para brincar.


Imagens

$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
nginx         latest    a830707172e8   2 weeks ago   192MB
ubuntu        26.04     4b1d0c4a2c3f   3 weeks ago   78.1MB
hello-world   latest    74cc54e27dc4   9 months ago  10.1kB
$ docker pull postgres:17
$ docker rmi hello-world
Untagged: hello-world:latest
Deleted: sha256:74cc54e27dc4…
$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

A tag é a versão: postgres:17, ubuntu:26.04. Em servidores, fixe a tag. Com latest, a versão muda sozinha quando você baixa de novo, e isso pode quebrar o app.


Guardar dados: volumes

Tudo o que um programa grava dentro do container some quando o container é apagado. Para guardar dados, ligue uma pasta de fora a uma pasta de dentro. Há duas formas:

Forma 1: pasta do Ubuntu (bind mount)

-v ~/site:/usr/share/nginx/html
pasta-do-ubuntu:pasta-do-container. O que você muda em ~/site aparece na hora no container.
:ro
Opcional: read-only, o container só pode ler.
$ mkdir ~/site
$ echo "<h1>Site da Ana</h1>" > ~/site/index.html
$ docker run -d -p 8080:80 --name web -v ~/site:/usr/share/nginx/html:ro nginx
$ curl localhost:8080
<h1>Site da Ana</h1>                         « o nginx serve o arquivo do seu Ubuntu

Forma 2: volume gerenciado pelo Docker

$ docker volume create dados-db
dados-db
$ docker run -d --name db -e POSTGRES_PASSWORD=segredo -v dados-db:/var/lib/postgresql/data postgres:17
$ docker volume ls
DRIVER    VOLUME NAME
local     dados-db
FormaExemploMelhor quando…
Pasta do Ubuntu-v ~/site:/dadosVocê quer editar os arquivos (código, site, configurações).
Volume nomeado-v dados-db:/dadosOs dados são do programa (banco de dados) e você não mexe à mão.
Sem volume(nada)Os dados podem sumir (testes).

Sua própria imagem: Dockerfile

Um Dockerfile é a receita da imagem: um arquivo de texto com uma instrução por linha. Exemplo: um site estático servido pelo nginx.

# Parte de uma imagem pronta (a "base")
FROM nginx:1.29-alpine

# Copia os arquivos do projeto para dentro da imagem
COPY site/ /usr/share/nginx/html/

# Documenta a porta que o programa usa
EXPOSE 80

# (o nginx já define o comando de partida; não é preciso CMD aqui)
InstruçãoO que faz
FROMImagem base. Toda receita começa daqui.
RUNRoda um comando durante a construção (ex.: RUN apt-get update && apt-get install -y curl).
COPYCopia arquivos do projeto para dentro da imagem.
WORKDIRDefine a pasta de trabalho dentro da imagem.
ENVDefine variáveis de ambiente.
EXPOSEDocumenta a porta. Não publica nada: isso é o -p.
CMDO comando que roda quando o container sobe.
docker build
Constrói uma imagem a partir de um Dockerfile.
-t meusite:1.0
tag: o nome e a versão da imagem nova.
.
O "contexto": a pasta atual, onde estão o Dockerfile e a pasta site/.
$ ls
Dockerfile  site
$ docker build -t meusite:1.0 .
[+] Building 3.2s (7/7) FINISHED
 => [internal] load build definition from Dockerfile
 => [1/2] FROM docker.io/library/nginx:1.29-alpine
 => [2/2] COPY site/ /usr/share/nginx/html/
 => exporting to image
 => => naming to docker.io/library/meusite:1.0
$ docker run -d -p 8081:80 --name meusite meusite:1.0

Formas de manter um app rodando

FormaExemploMelhor quando…
docker run à mãodocker run -d …Testes e um container só.
Política de reiníciodocker run -d --restart unless-stopped …Um container que deve voltar sozinho depois de um reboot.
Docker Composedocker compose up -dVários containers que trabalham juntos (site + banco). Veja Docker Compose.
Sem Dockerapt install nginx + systemctlUm serviço simples que o Ubuntu já empacota.

Quando não funciona

"permission denied while trying to connect to the Docker daemon socket"

O que aconteceu: seu usuário não está no grupo docker, ou entrou nele e ainda não abriu uma sessão nova.

Como confirmar: groups não mostra docker.

Como resolver: sudo usermod -aG docker $USER e depois saia e entre na sessão (ou use newgrp docker).

"Cannot connect to the Docker daemon … Is the docker daemon running?"
$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
$ systemctl is-active docker
inactive

Como resolver: sudo systemctl enable --now docker. Se não subir, veja o motivo em journalctl -u docker -n 30 (veja Logs).

"port is already allocated"
$ docker run -d -p 8080:80 --name web2 nginx
docker: Error response from daemon: driver failed programming external connectivity on endpoint web2 (3c1e…): Bind for 0.0.0.0:8080 failed: port is already allocated.

O que aconteceu: outro container (ou outro programa) já usa a porta 8080 do Ubuntu.

Como confirmar: docker ps e sudo ss -tulpn | grep 8080 (veja ss).

Como resolver: escolha outra porta do lado do Ubuntu (-p 8081:80) ou pare o outro container. O container web2 foi criado mesmo assim, parado: apague com docker rm web2.

O container morre na hora
$ docker run -d --name teste ubuntu
5d2a…
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES     « vazio!
$ docker ps -a
CONTAINER ID   IMAGE    COMMAND       CREATED          STATUS                      PORTS   NAMES
5d2a8f1e7c33   ubuntu   "/bin/bash"   10 seconds ago   Exited (0) 9 seconds ago            teste

O que aconteceu: um container vive enquanto o programa principal dele vive. A imagem ubuntu roda bash, que sem terminal termina na hora.

Como resolver: para usar interativamente, rode com -it: docker run -it ubuntu. Se for um app seu que morre, leia o motivo com docker logs teste.

"pull access denied" ou "not found"
$ docker run nginxx
Unable to find image 'nginxx:latest' locally
docker: Error response from daemon: pull access denied for nginxx, repository does not exist or may require 'docker login'.

O que aconteceu: erro de digitação no nome da imagem, ou uma tag que não existe. Confira o nome no Docker Hub.


Referência

Comandos

ComandoO que faz
docker run IMAGEMCria e roda um container
docker ps / ps -aLista containers rodando / todos
docker logs [-f] NOMEMostra a saída do container (-f acompanha)
docker exec -it NOME bashAbre um shell dentro do container
docker stop / start / restart NOMEPara, inicia, reinicia
docker rm [-f] NOMEApaga o container
docker imagesLista imagens baixadas
docker pull IMAGEM:TAGBaixa uma imagem
docker rmi IMAGEMApaga uma imagem
docker build -t NOME .Constrói uma imagem do Dockerfile
docker volume ls / create / rmGerencia volumes
docker system dfQuanto espaço o Docker ocupa
docker system pruneApaga containers parados, redes e imagens soltas

Opções do docker run

OpçãoDescriçãoExemplo
-dSegundo planodocker run -d nginx
-itTerminal interativodocker run -it ubuntu bash
-p H:CPublica a porta C do container na porta H do Ubuntu-p 8080:80
-v ORIGEM:DESTINOLiga pasta ou volume-v ~/site:/dados
-e VAR=valorVariável de ambiente-e TZ=America/Sao_Paulo
--nameDá um nome--name web
--rmApaga ao terminardocker run --rm …
--restartno, always, unless-stopped, on-failure--restart unless-stopped
Atenção: o Docker e o firewall

Portas publicadas com -p passam por regras próprias do Docker e podem ficar acessíveis mesmo com o ufw bloqueando. Para publicar só para a própria máquina, use -p 127.0.0.1:8080:80.


Exercícios

1. Porta

Complete para que http://localhost:9000 mostre o nginx (que escuta na porta 80 do container):

docker run -d -p nginx

2. Entrar no container

Complete para abrir um shell dentro do container web:

docker web bash

3. Ver os parados

Complete para listar também os containers parados:

docker ps

4. Você apagou o container do banco com docker rm -f db. Em qual caso os dados continuam existindo?

5. Por que estar no grupo docker é delicado?


Resumo

  • Imagem é a receita, container é a imagem rodando.
  • Instale com sudo apt install docker.io docker-compose-v2 e entre no grupo docker, sabendo que ele equivale a root.
  • docker run -d -p HOST:CONTAINER --name NOME IMAGEM é a forma mais usada.
  • ps, logs, exec -it, stop, rm são o dia a dia.
  • Dados importantes vão em volumes (-v); sem isso, somem com o container.
  • Um Dockerfile descreve a sua própria imagem, e docker build -t a constrói.