Docker
O Docker é uma plataforma que permite empacotar, distribuir e executar aplicações de forma isolada usando containers. Os containers são como "mini-máquinas virtuais", mas muito mais leves.
Imagem, conteiner e volume:
| Conceito | Analogia com Programação | Explicação rápida |
|---|---|---|
| Imagem | Uma classe | Um modelo imutável com o código e dependências para rodar algo. Ex: nginx, mysql, etc. |
| Container | Uma instância da classe | Uma "imagem em execução", com configurações, variáveis, rede, etc. |
| Volume | Um banco de dados externo ou um disco persistente | Um local externo ao container onde dados são armazenados de forma persistente, mesmo se o container for apagado. |
Containers são efêmeros: se você parar e remover um container, todos os dados criados dentro dele desaparecem.
Volume é um diretório (ou arquivo) armazenado fora do sistema de arquivos do container (ou seja, sistema do host: Windows, Linux ou Mac), mas que é montado dentro do container como um diretorio que o conteiner pode acessar.
Obs.: Se você não removeu o container, o sistema de arquivos dele permaneceu intacto. Mas esses dados so existem se o conteiner ainda existir, pois estão salvos internamente.
Docker vs. Máquina Virtual
| Característica | Docker (Containers) | Máquina Virtual |
|---|---|---|
| Leveza | ✅ Sim | ❌ Não (pesado) |
| Consome menos recursos | ✅ Sim | ❌ Não (usa mais RAM e CPU) |
| Inicia rapidamente | ✅ Sim (segundos) | ❌ Não (minutos) |
| Portabilidade | ✅ Sim | ❌ Limitada |

O Dockerfile é um roteiro de instruções para o Docker saber como montar uma imagem. Ele define:
-
Qual sistema base usar (ex: Python, Node, Ubuntu...)
-
Quais comandos rodar (ex: instalar pacotes, copiar arquivos, rodar servidor etc.)
-
Qual diretório de trabalho usar
-
Qual comando iniciar por padrão
Você pode pensar no Dockerfile como a “receita de bolo” que o docker-compose vai usar para construir o container.
O Docker Compose é uma ferramenta que permite definir e rodar múltiplos containers de forma automatizada usando um único arquivo de configuração (compose.yaml) na pasta raiz, ou, para melhor organização na pasta infra. Mas antes esse arquivo se chamava (docker-compose.yaml).
As imagens Docker podem vir de um dockerfile ou de um dockerhub (repositórios públicos link do dockerhub).
# Usando uma imagem base oficial do Python
FROM python:3.13-slim
# Esse diretório será automaticamente criado dentro do container, como um diretório de trabalho padrão.
WORKDIR /app
# Copia o arquivo de requisitos para dentro do container
COPY requirements.txt .
# Instala as dependências do Python dentro do container
RUN pip install --no-cache-dir -r requirements.txt
# Copia o código do backend para dentro do container
COPY . .
# Expondo a porta para rodar o Django
EXPOSE 9000
# Comando para rodar o servidor do Django
CMD ["python", "manage.py", "runserver", "0.0.0.0:9000"]
Esse arquivo é lido pelo docker compose para montar a imagem corretamente.
version: "3.9"
services:
backend:
build: ./backend # Caminho do Dockerfile do backend
volumes:
- ./backend:/app # Mapeando o código da máquina local para o container
- ./backend/banco.db:/app/banco.db # Caso deseje mapear apenas um banco sql, ou arquivo especifico
working_dir: /app
command: python manage.py runserver 0.0.0.0:9000 # Rodando o servidor Django, sobrescreve o cmd do dockerfile
ports:
- "9000:9000" # Mapear porta local 8000 para a 8000 do container
environment:
- DEBUG=1 # Variável de ambiente (opcional, mas útil para desenvolvimento)
frontend:
build: ./frontend # Caminho do Dockerfile do frontend (React)
volumes:
- ./frontend:/app # Mapeando o código local do frontend para o container
working_dir: /app
command: npm start # Comando para rodar o React (assumindo que tenha npm start)
ports:
- "3000:3000" # Mapear a porta local 3000 para a 3000 do container
environment:
- CHOKIDAR_USEPOLLING=true # Para evitar problemas de mudanças de arquivos no Docker
O build: serve para construir uma imagem customizada a partir de um Dockerfile.
services: # Início da definição dos serviços que serão executados pelo Docker Compose
mysql_knex: # Nome do serviço (pode ser qualquer nome, é usado internamente)
container_name: mysql_knex # Nome do container (visível com `docker ps`, por exemplo)
hostname: mysql_knex # Nome do host dentro da rede interna do Docker (na pratica posso fazer uma conexão de um app python (ou outros) de dentro do docker usando: host:mysql_knex port: 3306)
image: mysql # Imagem a ser usada (a padrão oficial do MySQL do Docker Hub)
restart: always # Reinicia automaticamente o container se ele parar ou o Docker reiniciar
command: # Comando customizado para inicializar o MySQL com configurações específicas
- --character-set-server=utf8mb4 # Define o charset padrão do servidor como UTF-8 completo
- --collation-server=utf8mb4_unicode_ci # Define a collation padrão (ordenação de strings)
- --innodb_force_recovery=0 # Modo de recuperação do InnoDB (0 = normal, sem recuperação)
volumes:
- "D:/dev/volume-to-docker/mysql:/var/lib/mysql" # Monta um volume local do host no container
# Isso garante persistência dos dados do MySQL fora do container
ports:
- 3306:3306 # Expõe a porta padrão do MySQL (3306) para o host
environment: # Variáveis de ambiente passadas para a imagem do MySQL (essas são oficiais)
MYSQL_ROOT_PASSWORD: senha # Define a senha do usuário root (obrigatório)
MYSQL_DATABASE: base_de_dados # **Cria automaticamente** esse banco de dados, se não existir ainda
MYSQL_USER: usuario # Cria um novo usuário com nome 'usuario'
MYSQL_PASSWORD: senha # Define a senha do usuário 'usuario'
TZ: America/Sao_Paulo # Define o timezone do container
OUTRA_VARIAVEL: 135 # Define uma outra variável (não padrão) para usar no docker
/var/lib/mysql está vazia (ou seja, se o banco já foi inicializado). Se estiver vazia, ele: Inicializa os arquivos do MySQL e usa as variáveis de ambiente que você definiu (MYSQL_DATABASE, MYSQL_USER, etc.) para: Criar o banco de dados (MYSQL_DATABASE); Criar o usuário (MYSQL_USER) com senha (MYSQL_PASSWORD); Dar permissão total ao novo usuário nesse banco; Definir a senha do root (MYSQL_ROOT_PASSWORD). Ou seja, esse comportamento é definido pela imagem oficial do MySQL no Docker Hub.Esse arquivo contém configuração do conteiner de postgreSql.
Os traços (-) representam uma lista em yaml. As portas são definidas como: "<host>:<container>", sendo o host a maquina externa e a conteiner a porta configurada dentro do conteiner.
services:
database:
container_name: "postgres-dev" # Define o nome do docker
image: 'postgres:16.0-alpine3.18' # Define a imagem usada
env_file: # ler um arquivo com as variáveis de ambiente
- ../.env
# environment: # Define as variáveis de ambiente manualmente
# POSTGRES_PASSWORD: "postgres" # Define um valor para variável obrigatória dessa imagem
#volumes:
#- postgres-data:/var/lib/postgresql/data # <nome do volume>:<Pasta no Container que quer mapear> Nesse caso, essa pasta é onde o PostgreSQL armazena os dados de banco de dados dentro do container.
#- postgres-impexp:/home # também mapeio a pasta Home
ports:
- "5432:5432"
# volumes:
# postgres-impexp: # defino manualmente onde quero guardar meus volumes no host
# driver: "local"
# driver_opts:
# type: "none"
# device: "/home/user/data/pgsql/impexp" # pasta do host onde quero persistir os dados do docker
# o: "bind"
Puxa diretamente do dockerhub a versão Alpine linux do postgres é projetada para usar a menor quantidade de recursos possível.
Quando o Docker cria um volume, ele escolhe um diretório no host para armazenar esses dados automaticamente, isso se não for definido o local que quer persistir esses dados. Mas geralmente fica salvo em: /var/lib/docker/volumes/.
Comandos Docker
docker build compila e prepara o container com base no Dockerfile, -t e da um nome a imagem, o . é o local do Dockerfile
$ docker --version
$ docker compose pull # Baixa a Imagem sem subir o container
$ docker image ls # Exibe as imagens baixadas do docker
$ docker rmi <nome_da_imagem_ou_id> # remove imagens dockers
$ docker compose up # Baixa (se já não estiver baixado) e monta as camadas da imagem
$ docker compose up -d # (ou --detach) roda/inicia o docker background podendo fechar o terminal.
$ docker compose up -d --force-recreate # Força o conteiner a ser recriado após alguma configuração
$ docker compose -f pasta/compose.yml up # Subo especificando a pasta onde está o yml
$ docker compose stop # para o serviço sem apagar nada
$ docker compose down # Desliga ou exclui o conteiner, com -v pode apagar dados persistentes
$ docker ps # Lista os containers que estiverem rodando
$ docker ps -a # Lista todos os conteiners (instancias das imagens baixadas em execução)
$ docker logs nome_do_conteiner # logs do conteiner
$ docker cp arquivo.txt <IDCONTAINER>:/diretorio_dentro_docker/arquivo.txt # copiar arquivos para dentro do container
$ docker start meu-container # Inicia o container parado
$ docker stop meu-container # Para a execução do container
$ docker exec -it 2ba5449f094b bash # interagir/entrar diretamente com/no container (2ba5449f094b - troque pelo id do container)
$ docker exec postgres-dev pg_isready --host localhost # testa se o docker do postgres está pronto para receber conexões
$ docker system prune -a # Apaga tudo mesmo. Mas antes é necessário parar o container em funcionamento
$ docker network inspect bridge # Ver os IPs dos dockers
$ docker volume create meu_volume # Cria um volume
$ docker volume ls # Lista todos os volumes
$ docker volume inspect meu_volume # Mostra informações sobre o volume, como o caminho no que fica salvo no HOST
$ docker volume rm meu_volume # Remove o volume (se não estiver em uso)
$ docker build -t meu-app . # Cria/compila uma imagem com base no Dockerfile, sem o dockercompose
$ docker run -it --rm -p 8501:8501 meu-app # Roda a imagem compilada anteriormente, rm remove apos parar o container