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).

Dockerfile
# 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.

docker-compose.yml
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.

docker-compose_exemplo.yml
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

Exemplo completo do docker-compose sem precisar do dockerfile.
A imagem oficial do MySQL no Docker tem um entrypoint (script de inicialização) que verifica se a pasta /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.

compose.yaml
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

bash
$ 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

Assuntos Relacionados