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
- Princípios para Escolher Entre COPY e ADD
- ARG: Passando Parâmetros de Construção
- ENV Variáveis de Ambiente em Tempo de Execução
- HEALTHCHECK Configuração de Verificação de Saúde
- Política de Segurança para Usuários Não-root
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.
# 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
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: ⭐⭐)
# 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: ⭐⭐⭐)
# 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"]
- 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) |
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: ⭐⭐)
# 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"]
# 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: ⭐⭐)
# 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"]
# Sobrescrever ENV em tempo de execução
docker run -d -e APP_PORT=8080 -e LOG_LEVEL=debug myapp:1.0
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: ⭐)
# 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: ⭐⭐)
# 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"]
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: ⭐)
# EXPOSE documenta quais portas o contêiner escuta
FROM python:3.12-slim
WORKDIR /app
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
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
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: ⭐⭐)
# 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"]
# Verificar status de saúde
docker inspect myapp --format='{{.State.Health.Status}}'
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: ⭐)
# 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 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"]
# 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}}'
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.gzquando 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
-ede 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-periodpara 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--timeoutnão exceda metade de--intervalpara 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:
EXPOSErealmente 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 requerdocker run -pou-P.-P(em maiúsculas) mapeia automaticamente as portas declaradas porEXPOSEpara 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> whoamideve retornar um nome de usuário diferente de root. Ou usedocker inspect <contêiner> --format='{{.Config.User}}'para visualizar o usuário configurado.
📖 Resumo
- COPY vs. ADD: Use apenas COPY — seu comportamento é transparente e controlável; a descompressão automática do ADD é uma "armadilha" imprevisível.
- ARG: Variáveis de tempo de build (não gravadas na imagem); ENV: Variáveis de tempo de execução (gravadas na imagem)
- WORKDIR define o diretório de trabalho; é mais confiável e persistente do que
RUN cd - Alternar para um usuário não-root é uma melhor prática de segurança — leva apenas duas linhas de código
- HEALTHCHECK permite que o Docker monitore automaticamente a saúde das aplicações e, em conjunto com uma política de reinicialização, alcance auto-recuperação
- EXPOSE é uma declaração de porta; o mapeamento real requer o parâmetro -p
📝 Exercícios
- Exercício Básico (Dificuldade: ⭐): Adicione um usuário não-root ao Dockerfile da Aula 7. Após construir a imagem, use
docker execpara verificar quewhoaminão retorna "root". - 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 inspectpara visualizar Health.Status. - 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 quickviewoutrivy imagepara escanear a imagem em busca de vulnerabilidades de segurança.