Docker: Comandos Avançados de Dockerfile

Última atualização: 2026-08-26

Dockerfiles de nível de produção não devem apenas executar, mas também ser seguros, configuráveis e monitoráveis — tudo isso é alcançado através de instruções avançadas.

1. O Que Você Vai Aprender



2. Uma História Sobre uma Auditoria de Segurança

(1) Ponto de Dor: Executar contêineres como root é uma vulnerabilidade de alto risco

O relatório de auditoria de segurança de Charlie observa que "contêineres executando como root" é uma vulnerabilidade de alto risco. Se uma pessoa atacante obtiver acesso a um contêiner através de uma vulnerabilidade da aplicação, ela terá privilégios de root e poderá modificar arquivos do sistema e montar diretórios do host. A pontuação da auditoria é de apenas 45 pontos.

(2) Soluções para Proteger Dockerfiles

Alice adicionou uma linha USER appuser ao Dockerfile, elevando a pontuação de segurança de 45 para 85.

DOCKERFILE
# Reforço de segurança: executar como usuário não-root
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# Criar e alternar para usuário não-root
RUN useradd -m appuser
USER appuser

CMD ["python", "app.py"]

(3) Benefício: Dobrar a pontuação de segurança

Adicionei apenas duas linhas (RUN useradd + USER), e a pontuação de segurança passou de 45 para 85, passando na auditoria.



3. COPY vs ADD

(1) Comparação de Funcionalidades

Função COPY ADD
Copiar arquivos locais para a imagem
Baixar arquivo de URL
Extrair automaticamente tar/gzip/bzip2/xz
Build Multi-estágio --from

(2) Princípios de Seleção

📌 Ponto-chave: A melhor prática é usar apenas COPY. O comportamento de extração automática e download de URL do ADD é imprevisível e propenso a erros. Quando a extração for necessária, use explicitamente o comando RUN tar para maior transparência e controle.

▶ Exemplo: Diferenças no Comportamento Entre COPY e ADD (Dificuldade: ⭐⭐)

DOCKERFILE
# COPY: simplesmente copia o arquivo tar como está
COPY archive.tar.gz /tmp/
# Resultado: /tmp/archive.tar.gz (ainda comprimido)

# ADD: extrai automaticamente o arquivo tar
ADD archive.tar.gz /tmp/
# Resultado: /tmp/archive/ (conteúdo extraído)

▶ Exemplo: Build multi-estágio com COPY --from (Dificuldade: ⭐⭐⭐)

DOCKERFILE
# Multi-estágio: copiar artefato do estágio builder
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o server

FROM alpine:3.19
COPY --from=builder /src/server /usr/local/bin/server
CMD ["server"]


  1. ARG e ENV

(1) Comparação do Escopo de Aplicação

Dimensão ARG ENV
Estágios Disponíveis Tempo de build (docker build) Tempo de execução (docker run)
Persistência Não grava nos metadados da imagem Grava nos metadados da imagem
Sobrescritível --build-arg docker run -e
CMD/ENTRYPOINT Disponível
Segurança Não exposto em tempo de execução Exposto em tempo de execução (visível via docker inspect)
100%
graph TB
    BUILD["Tempo de Build"] -->|ARG| LAYER["Camada da Imagem"]
    RUN["Tempo de Execução"] -->|ENV| CONTAINER["Env do Contêiner"]
    BUILD -->|ENV persiste| CONTAINER

▶ Exemplo: ARG Construção de Número de Versão (Dificuldade: ⭐⭐)

DOCKERFILE
# Usar ARG para variáveis de tempo de build
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim

ARG APP_VERSION=1.0
LABEL version="${APP_VERSION}"

WORKDIR /app
COPY . .
CMD ["python", "app.py"]
BASH
# Construir com versão Python personalizada
docker build --build-arg PYTHON_VERSION=3.11 -t myapp:3.11 .

# Construir com versão de aplicação personalizada
docker build --build-arg APP_VERSION=2.0 -t myapp:v2.0 .

▶ Exemplo: ENV Configuração de Variável de Ambiente (Dificuldade: ⭐⭐)

DOCKERFILE
# ENV: disponível em tempo de execução
FROM python:3.12-slim

ENV APP_PORT=5000 \
    APP_HOST=0.0.0.0 \
    LOG_LEVEL=info

WORKDIR /app
COPY . .
CMD ["python", "app.py"]
BASH
# Sobrescrever ENV em tempo de execução
docker run -d -e APP_PORT=8080 -e LOG_LEVEL=debug myapp:1.0
⚠️ Nota: Não armazene informações sensíveis (senhas/chaves) em variáveis ENV, pois elas serão gravadas nos metadados da imagem e podem ser visualizadas por qualquer pessoa com docker inspect. Injete informações sensíveis em tempo de execução usando docker run -e, ou use Docker Secrets.



4. WORKDIR Diretório de Trabalho

▶ Exemplo: WORKDIR—Definindo o Diretório de Trabalho (Dificuldade: ⭐)

DOCKERFILE
# WORKDIR define o diretório de trabalho para instruções subsequentes
FROM python:3.12-slim

# Cada WORKDIR cria o diretório se ele não existir
WORKDIR /app
COPY . .

# WORKDIR pode ser relativo (relativo ao WORKDIR anterior)
WORKDIR src
RUN pwd  # Saída: /app/src
Regra Descrição
Usar caminhos absolutos WORKDIR /app em vez de WORKDIR app
Criar automaticamente Criar automaticamente se o diretório não existir
Afeta RUN/CMD/ENTRYPOINT/COPY Comandos subsequentes são executados com base no WORKDIR
Não usar RUN cd RUN cd /app && ... é válido apenas para o RUN atual; WORKDIR permanece em vigor


5. Princípios de Segurança para Usuários Não-root

(1) Riscos de Executar Contêineres como root

Risco Descrição
Escalonamento de Privilégios Vulnerabilidade do contêiner + privilégios de root = Pessoa atacante obtém privilégios de root no host
Modificação de Arquivos Qualquer arquivo dentro do contêiner (incluindo arquivos do sistema) pode ser modificado
Riscos de Montagem Ao montar um diretório do host, o contêiner root pode modificar arquivos do host
CIS Benchmark "Contêineres executam como não-root" é um requisito obrigatório na Linha de Base de Segurança CIS Docker

▶ Exemplo: Executando como um USER não-root (Dificuldade: ⭐⭐)

DOCKERFILE
# Melhor prática: criar um usuário dedicado e alternar para ele
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# Criar usuário não-root com UID/GID específico
RUN groupadd -r appgroup && \
    useradd -r -g appgroup -u 1000 -m appuser

# Garantir que o usuário da aplicação seja proprietário dos arquivos
RUN chown -R appuser:appgroup /app

# Alternar para usuário não-root
USER appuser

CMD ["python", "app.py"]
🔒 Segurança: Todos os comandos (RUN/CMD/ENTRYPOINT) após USER appuser são executados como appuser. Mesmo que uma pessoa atacante obtenha acesso ao contêiner, ela não terá privilégios de root.



6. EXPOSE Declaração de Porta

▶ Exemplo: EXPOSE Declaração de Porta (Dificuldade: ⭐)

DOCKERFILE
# EXPOSE documenta quais portas o contêiner escuta
FROM python:3.12-slim
WORKDIR /app
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
⚠️ Nota: EXPOSE é uma declaração de documentação; ela não expõe realmente a porta. O mapeamento de porta do contêiner ainda requer docker run -p 5000:5000. O propósito do EXPOSE é: ① Documentação; ② docker run -P seleciona automaticamente portas declaradas com EXPOSE ao fazer mapeamento aleatório.



7. HEALTHCHECK Verificação de Saúde

HEALTHCHECK permite que o Docker verifique automaticamente se as aplicações dentro dos contêineres estão saudáveis e as reinicie automaticamente se não estiverem.

(1) Sintaxe da Verificação de Saúde

DOCKERFILE
HEALTHCHECK [OPTIONS] CMD command
Opção Padrão Descrição
--interval 30s Intervalo de Verificação
--timeout 30s Tempo Limite
--start-period 0s Período de tolerância de inicialização do contêiner
--retries 3 Marcar como "unhealthy" após X falhas consecutivas

▶ Exemplo: HEALTHCHECK verificação com curl (Dificuldade: ⭐⭐)

DOCKERFILE
# Verificação de saúde com curl
FROM python:3.12-slim

WORKDIR /app
COPY . .
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

EXPOSE 5000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

CMD ["python", "app.py"]
BASH
# Verificar status de saúde
docker inspect myapp --format='{{.State.Health.Status}}'
💻 Saída:

TEXT 📖 Somente leitura
healthy

(1) Descrição do Status de Saúde

Status Significado Comportamento do Docker
starting Durante o período de tolerância (start-period) Não contado
healthy Passou na inspeção Operando normalmente
unhealthy Falhou nas tentativas consecutivas Dispara um alerta; pode reiniciar automaticamente quando combinado com uma política de reinicialização


8. LABEL Metadados

▶ Exemplo: Adicionando Metadados ao LABEL (Dificuldade: ⭐)

DOCKERFILE
# LABEL adiciona metadados à imagem
LABEL maintainer="alice@example.com"
LABEL version="1.0"
LABEL description="Flask web application for production"
LABEL org.opencontainers.image.source="https://github.com/example/app"


9. Exemplo Completo: Escrevendo um Dockerfile Seguro para uma Aplicação Spring Boot

DOCKERFILE
# ============================================
# Dockerfile de nível de produção para Spring Boot
# Recursos: usuário não-root, HEALTHCHECK, ARG, LABEL
# ============================================

# Argumento de build para nome do arquivo JAR
ARG JAR_FILE=app.jar

# Estágio 1: Build (futuro multi-estágio, aqui apenas copiar)
FROM eclipse-temurin:21-jre-alpine

# Metadados
LABEL maintainer="dev-team@example.com"
LABEL version="2.0"

# Criar usuário não-root
RUN addgroup -S appgroup && \
    adduser -S appuser -G appgroup

# Definir diretório de trabalho
WORKDIR /app

# Copiar o arquivo JAR (usar ARG para flexibilidade)
COPY target/${JAR_FILE} app.jar

# Garantir que o usuário da aplicação seja proprietário dos arquivos
RUN chown -R appuser:appgroup /app

# Alternar para usuário não-root
USER appuser

# Expor porta da aplicação
EXPOSE 8080

# Verificação de saúde
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

# Executar a aplicação
ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--server.port=8080"]
BASH
# Construir com nome JAR personalizado
docker build --build-arg JAR_FILE=myapp-2.0.jar -t spring-app:2.0 .

# Executar com sobrescrita de ambiente
docker run -d -p 8080:8080 --name spring spring-app:2.0

# Verificar status de saúde
docker inspect spring --format='User: {{.Config.User}}, Health: {{.State.Health.Status}}'
💻 Saída:

TEXT 📖 Somente leitura
User: appuser, Health: healthy

❓ Perguntas Frequentes

P: ADD pode extrair automaticamente arquivos tar? R: Sim, mas este é um "recurso armadilha" — se você só quer copiar um arquivo tar (sem extraí-lo), ADD irá extraí-lo inesperadamente. Melhor prática: Use COPY exclusivamente e use explicitamente RUN tar -xzf file.tar.gz quando precisar extrair, para garantir comportamento transparente e controlável.

P: Qual é a diferença entre ARG e ENV? R: ARG está disponível apenas durante o processo de build e não é gravado na imagem; ENV é gravado na imagem e também é visível em tempo de execução. Uma regra simples: use ENV para qualquer coisa que precise ser acessível em tempo de execução (como configuração de porta), e use ARG para qualquer coisa usada apenas durante o build (como números de versão ou URLs de download). Use o -e de tempo de execução para armazenar senhas, não ENV.

P: Como devo configurar HEALTHCHECK para evitar falsos positivos? R: Três pontos-chave: ① Defina --start-period para permitir tempo para a aplicação iniciar (pelo menos 30 segundos para aplicações Java); ② Verifique o endpoint de saúde real da aplicação (ex.: /health); não apenas verifique se a porta está acessível; ③ Garanta que --timeout não exceda metade de --interval para evitar um acúmulo de verificações.

P: Por que os contêineres não devem ser executados como root? R: Quando um contêiner é executado como root, uma pessoa atacante que obtiver acesso ao contêiner através de uma vulnerabilidade da aplicação obterá privilégios de root. Combinado com uma vulnerabilidade do kernel, isso pode levar a um escape para o host. Executar como usuário não-root reduz significativamente a superfície de ataque — o CIS Docker Benchmark lista "executar como não-root" como um requisito obrigatório.

P: EXPOSE realmente expõe portas? R: Não. EXPOSE é meramente uma declaração de documentação que informa às pessoas usuárias quais portas o contêiner pretende usar. O mapeamento real requer docker run -p ou -P. -P (em maiúsculas) mapeia automaticamente as portas declaradas por EXPOSE para portas aleatórias no host.

P: Como posso verificar se o contêiner está sendo executado como um usuário não-root? R: docker exec <contêiner> whoami deve retornar um nome de usuário diferente de root. Ou use docker inspect <contêiner> --format='{{.Config.User}}' para visualizar o usuário configurado.


📖 Resumo


📝 Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Adicione um usuário não-root ao Dockerfile da Aula 7. Após construir a imagem, use docker exec para verificar que whoami não retorna "root".
  2. Exercício Avançado (Dificuldade: ⭐⭐): Adicione a diretiva HEALTHCHECK e use curl para verificar o endpoint de saúde da aplicação. Após construir e executar a aplicação, use docker inspect para visualizar Health.Status.
  3. Desafio (Dificuldade: ⭐⭐⭐): Escreva um Dockerfile completo e de nível de produção para a aplicação Flask da Aula 7, incluindo: ARG número de versão + configuração ENV + usuário não-root + HEALTHCHECK + LABEL. Depois, use docker scout quickview ou trivy image para escanear a imagem em busca de vulnerabilidades de segurança.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%