Docker e C#: conteinerização de aplicações em nível avançado
A conteinerização de aplicações .NET com Docker tornou-se um padrão da indústria. Se as habilidades básicas de trabalho com contêineres já foram dominadas, é hora de passar para o nível avançado. Neste artigo, vamos explorar cenários complexos: multi-stage build, criação de imagens leves de produção, organização de microsserviços com Docker Compose, implementação de health checks e gerenciamento eficiente de configuração. Todos os exemplos são válidos para .NET 8 e versões recentes do Docker.
1. Multi-stage build para .NET
O problema clássico são imagens enormes que incluem SDK e ferramentas de build. A solução é o multi-stage build, onde a imagem final contém apenas o runtime e os arquivos binários compilados.
Vamos analisar um Dockerfile avançado para ASP.NET Core Web API:
# Estágio 1: Restauração de dependênciasFROM mcr.microsoft.com/dotnet/sdk:8.0 AS restoreWORKDIR /srcCOPY ["MyApp.Api/MyApp.Api.csproj", "MyApp.Api/"]COPY ["MyApp.Core/MyApp.Core.csproj", "MyApp.Core/"]RUN dotnet restore "MyApp.Api/MyApp.Api.csproj"
# Estágio 2: Build e publicaçãoFROM restore AS buildCOPY . .WORKDIR "/src/MyApp.Api"RUN dotnet publish -c Release -o /app/publish
# Estágio 3: Imagem final (apenas runtime)FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS finalWORKDIR /appEXPOSE 8080ENV ASPNETCORE_URLS=http://+:8080COPY --from=build /app/publish .ENTRYPOINT ["dotnet", "MyApp.Api.dll"]Otimizações principais:
- Separação de restore e build: o cache da camada com dependências acelera rebuilds.
- Plataforma alvo: use
--no-restoreno estágio de publish se o restore já foi executado. - Minimização de camadas: combine comandos
RUNquando possível, usando&&. - Uso de
--chmod: para permissões corretas em contêineres Linux.
2. Docker Compose para microsserviços em C#
O Docker Compose é indispensável ao trabalhar com vários serviços .NET. Um cenário avançado inclui configuração de rede, dependências e variáveis de ambiente.
Exemplo de docker-compose.yml para uma arquitetura de microsserviços com API Gateway, serviço de pedidos e RabbitMQ:
version: '3.8'
services: rabbitmq: image: rabbitmq:3-management-alpine ports: - "5672:5672" - "15672:15672" healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"] interval: 30s timeout: 10s retries: 5
orders-api: build: context: . dockerfile: src/Orders.Api/Dockerfile ports: - "5001:8080" environment: - ASPNETCORE_ENVIRONMENT=Production - ConnectionStrings__DefaultConnection=Server=db;Database=OrdersDb;User=sa;Password=Your_password123; - RabbitMQ__Host=rabbitmq depends_on: rabbitmq: condition: service_healthy db: condition: service_started restart: unless-stopped
api-gateway: build: context: . dockerfile: src/ApiGateway/Dockerfile ports: - "80:8080" depends_on: - orders-api environment: - ASPNETCORE_ENVIRONMENT=Production - Services__Orders=http://orders-api:8080Técnicas avançadas:
- Healthcheck no Compose: use
condition: service_healthypara dependências estritas. - Perfis (profiles): ative/desative serviços para diferentes ambientes de desenvolvimento.
- Volumes embutidos para logs:
volumes:para salvar logs fora do contêiner. - Variáveis de ambiente via arquivo .env: armazene dados sensíveis