Docker y C#: contenerización de aplicaciones a nivel avanzado
La contenerización de aplicaciones .NET con Docker se ha convertido en un estándar de la industria. Si ya se dominan las habilidades básicas con contenedores, es hora de pasar al nivel avanzado. En este artículo, exploraremos escenarios complejos: compilación multi-etapa (multi-stage build), creación de imágenes de producción ligeras, organización de microservicios con Docker Compose, implementación de health checks y gestión eficiente de la configuración. Todos los ejemplos son válidos para .NET 8 y las últimas versiones de Docker.
1. Compilación multi-etapa (Multi-stage build) para .NET
El problema clásico son las imágenes enormes que incluyen el SDK y las herramientas de compilación. La solución es la compilación multi-etapa, donde la imagen final contiene solo el runtime y los archivos binarios compilados.
Veamos un Dockerfile avanzado para ASP.NET Core Web API:
# Etapa 1: Restauración de dependenciasFROM 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"
# Etapa 2: Compilación y publicaciónFROM restore AS buildCOPY . .WORKDIR "/src/MyApp.Api"RUN dotnet publish -c Release -o /app/publish
# Etapa 3: Imagen final (solo 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"]Optimizaciones clave:
- Separación de restore y build: el almacenamiento en caché de la capa con dependencias acelera las compilaciones repetidas.
- Plataforma objetivo: use
--no-restoreen la etapa de publish si restore ya se ha ejecutado. - Minimización de capas: combine comandos
RUNdonde sea posible usando&&. - Uso de
--chmod: para permisos de acceso correctos en contenedores Linux.
2. Docker Compose para microservicios en C#
Docker Compose es indispensable al trabajar con múltiples servicios .NET. Un escenario avanzado incluye la configuración de red, dependencias y variables de entorno.
Ejemplo de docker-compose.yml para una arquitectura de microservicios con API Gateway, servicio de pedidos y 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 avanzadas:
- Healthcheck en Compose: use
condition: service_healthypara dependencias estrictas. - Perfiles (profiles): active/desactive servicios para diferentes entornos de desarrollo.
- Volúmenes integrados para logs:
volumes:para guardar logs fuera del contenedor. - Variables de entorno mediante archivo .env: almacene datos sensibles