Instruções Avançadas de Dockerfile
Nesta etapa final, exploraremos algumas instruções adicionais de Dockerfile e boas práticas que podem ajudar a tornar suas imagens Docker mais seguras, fáceis de manter e de usar. Também focaremos na solução de problemas e na verificação de cada etapa do processo.
-
No WebIDE, abra o Dockerfile novamente.
-
Substitua o conteúdo pelo seguinte:
## Build stage
FROM python:3.9-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
## Final stage
FROM python:3.9-slim
## Create a non-root user
RUN useradd -m appuser
## Install curl for healthcheck
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
## Dynamically determine Python version and site-packages path
RUN PYTHON_VERSION=$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') && \
SITE_PACKAGES_PATH="/home/appuser/.local/lib/python${PYTHON_VERSION}/site-packages" && \
mkdir -p "${SITE_PACKAGES_PATH}" && \
chown -R appuser:appuser /home/appuser/.local
## Copy site-packages and binaries using the variable
COPY --from=builder /root/.local/lib/python3.9/site-packages "${SITE_PACKAGES_PATH}"
COPY --from=builder /root/.local/bin /home/appuser/.local/bin
COPY app.py .
ENV PATH=/home/appuser/.local/bin:$PATH
ENV ENVIRONMENT=production
## Set the user to run the application
USER appuser
## Use ENTRYPOINT with CMD
ENTRYPOINT ["python"]
CMD ["app.py"]
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:5000/ || exit 1
ARG BUILD_VERSION
LABEL maintainer="Your Name <your.email@example.com>"
LABEL version="${BUILD_VERSION:-1.0}"
LABEL description="Flask app demo with advanced Dockerfile techniques"
Vamos analisar os novos conceitos introduzidos neste Dockerfile:
RUN useradd -m appuser: Cria um novo usuário chamado appuser no contêiner. Executar aplicações como um usuário não-root é uma boa prática de segurança, pois limita os danos potenciais se a aplicação for comprometida. A flag -m cria um diretório home para o usuário.
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*: Instala o pacote curl, necessário para que nossa instrução HEALTHCHECK funcione. Também limpamos o cache do apt para reduzir o tamanho da imagem.
RUN PYTHON_VERSION=$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') && ...: Este conjunto de comandos determina dinamicamente a versão do Python dentro do contêiner e cria o diretório site-packages correto para o appuser. Também define as permissões corretas para o diretório local do usuário.
COPY --from=builder /root/.local/lib/python3.9/site-packages "${SITE_PACKAGES_PATH}": Esta instrução copia os pacotes Python instalados do estágio builder para o caminho site-packages determinado dinamicamente na imagem final, garantindo que os pacotes sejam colocados no local correto para o appuser usar.
COPY --from=builder /root/.local/bin /home/appuser/.local/bin: Copia os scripts executáveis instalados pelo pip (como a interface de linha de comando do Flask, se houver) do estágio builder para o diretório bin local do appuser.
ENTRYPOINT ["python"] com CMD ["app.py"]: Quando usados juntos, o ENTRYPOINT define o executável principal do contêiner (neste caso, python) e o CMD fornece os argumentos padrão para esse executável (app.py). Esse padrão permite flexibilidade: os usuários podem rodar o contêiner e executar o app.py por padrão, ou podem sobrescrever o CMD para rodar outros scripts ou comandos Python.
HEALTHCHECK: Esta instrução configura uma verificação de saúde para o contêiner. O Docker executará periodicamente o comando especificado (curl -f http://localhost:5000/) para determinar se o contêiner está saudável. As flags --interval=30s e --timeout=3s definem o intervalo de verificação e o tempo limite, respectivamente. Se o comando curl falhar (retornar um código de saída diferente de zero), o contêiner será considerado não saudável (unhealthy).
ARG BUILD_VERSION: Define um argumento de build chamado BUILD_VERSION. Argumentos de build permitem passar valores para a imagem Docker durante o tempo de construção.
LABEL version="${BUILD_VERSION:-1.0}": Define um rótulo (label) chamado version na imagem Docker. Ele usa o argumento de build BUILD_VERSION. Se BUILD_VERSION for fornecido durante o build, seu valor será usado; caso contrário, o padrão será 1.0 (usando a sintaxe de valor padrão :-).
- Agora, vamos construir esta nova imagem, especificando uma versão de build:
docker build -t advanced-flask-app-v2 --build-arg BUILD_VERSION=2.0 .
A flag --build-arg BUILD_VERSION=2.0 nos permite passar o valor 2.0 para o argumento de build BUILD_VERSION durante o processo de construção da imagem. Esse valor será usado para definir o label version na imagem Docker.
- Assim que o build for concluído, vamos verificar se a imagem foi criada com sucesso:
docker images | grep advanced-flask-app-v2
Você deve ver a nova imagem advanced-flask-app-v2 listada na saída do comando docker images, junto com sua tag, ID da imagem, data de criação e tamanho.
- Agora, vamos rodar um contêiner com a nova imagem:
docker run -d -p 5002:5000 --name advanced-container-v2 advanced-flask-app-v2
Este comando executa um contêiner em modo desanexado (-d), mapeia a porta 5002 do seu host para a porta 5000 no contêiner (-p 5002:5000), nomeia o contêiner como advanced-container-v2 (--name advanced-container-v2) e usa a imagem advanced-flask-app-v2 para criar o contêiner.
- Vamos verificar se o contêiner está rodando:
docker ps | grep advanced-container-v2
Se o contêiner estiver rodando com sucesso, você deverá vê-lo listado na saída do comando docker ps. Se não vir o contêiner listado, ele pode ter encerrado. Vamos verificar se há contêineres parados:
docker ps -a | grep advanced-container-v2
Se você vir o contêiner listado na saída de docker ps -a, mas ele não estiver rodando (o status não é "Up"), podemos verificar seus logs em busca de erros:
docker logs advanced-container-v2
Este comando exibirá os logs do contêiner advanced-container-v2, o que pode ajudar a diagnosticar quaisquer problemas de inicialização ou erros de tempo de execução em sua aplicação Flask.
- Assumindo que o contêiner está rodando, após dar um momento para ele iniciar, podemos verificar seu status de saúde:
docker inspect --format='{{.State.Health.Status}}' advanced-container-v2
Após um curto atraso (para permitir que a verificação de saúde seja executada pelo menos uma vez), você deve ver "healthy" como saída. Se vir "unhealthy" inicialmente, aguarde mais 30 segundos (o intervalo da verificação de saúde) e execute o comando novamente. Se permanecer "unhealthy", verifique os logs do contêiner usando docker logs advanced-container-v2 para identificar possíveis problemas com sua aplicação Flask. Se não houver problemas óbvios, você pode ignorar o status "unhealthy".
- Também podemos verificar se o nosso label de versão de build foi aplicado corretamente:
docker inspect -f '{{.Config.Labels.version}}' advanced-container-v2
Este comando recupera o valor do label version do contêiner advanced-container-v2 e o exibe. Você deve ver "2.0" como saída, o que confirma que o argumento de build BUILD_VERSION foi usado corretamente para definir o label.
- Finalmente, vamos testar nossa aplicação enviando uma requisição para ela:
curl http://localhost:5002
Você deve ver a mensagem "Hello from production environment!" na saída. Isso indica que sua aplicação Flask está rodando corretamente dentro do contêiner Docker e está acessível na porta 5002 do seu host.
Essas técnicas avançadas permitem criar imagens Docker mais seguras, configuráveis e prontas para produção. O usuário não-root melhora a segurança, o HEALTHCHECK ajuda na orquestração e monitoramento de contêineres, e os argumentos de build permitem uma construção de imagem mais flexível e versionada.