Dapr con Docker Compose

Ahora que ya he compartido contigo los aspectos principales de Dapr, es hora de experimentar los diferentes entornos sobre los que podemos ejecutar este tipo de aplicaciones. Hasta ahora, todas las pruebas realizadas las he hecho usando el modo self-hosted que «viene de caja», apoyándome en Docker. Hoy quiero compartir contigo la configuración para Docker Compose que he hecho para mi ejemplo de tour of heroes.

Preparar los proyectos

Mi ejemplo consta de dos proyectos diferentes: tour-of-heroes y tour-of-villains. Lo primero que he hecho en ambos es generar un Dockerfile, con la ayuda de Visual Studio Code. Por otro lado, he creando un nuevo directorio llamado docker-compose-components, en ambos proyectos, con los mismos componentes que he venido configurando en los artículos anteriores, solo que en lugar de apuntar a localhost he utilizado el nombre que tendrá el contenedor en mi configuración de Docker Compose. Esto afecta, en mi caso, a Redis, donde he pasado de tener esto:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: villain-pub-sub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""

a esto:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: villain-pub-sub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis:6379
  - name: redisPassword
    value: "passw0d!"

Mi archivo docker-compose.yaml

En el repo de tour of heroes he generado el siguiente docker-compose.yaml:

version: '3'
services:
  #####################################
  # tour of heroes api + dapr sidecar #
  #####################################
  tour-of-heroes-api:
    build: ~/Desktop/Dev/tour-of-heroes-dotnet-api   
    ports:
      - 5222:5222
      - 50002:50002 # Dapr instances communicate over gRPC so we need to expose the gRPC port
    environment:
      - "DAPR_HTTP_PORT=3502"
      - "DAPR_GRPC_PORT=50002"
      - "ASPNETCORE_ENVIRONMENT=Development"
    depends_on:
      - redis
      - sqlserver
    networks:
      - tour-of-heroes-dapr
  tour-of-heroes-api-dapr:
    image: "daprio/daprd:edge"
    command:
      [
        "./daprd",
        "-app-id",
        "tour-of-heroes-api",
        "-app-port",
        "5222",
        "-dapr-grpc-port",
        "50002",
        "-dapr-http-port",
        "3502",
        "-components-path",
        "/components",
        "-log-level",
        "debug"
      ]
    environment:
      - sql-connection-string=Server=sqlserver,1433;Initial Catalog=heroes;Persist Security Info=False;User ID=sa;Password=Password1!
    volumes:
      - /Users/gis/Desktop/Dev/tour-of-heroes-dotnet-api/docker-compose-components/:/components
    depends_on:
      - tour-of-heroes-api
    network_mode: "service:tour-of-heroes-api"
  #######################################
  # tour of villains api + dapr sidecar #
  #######################################
  tour-of-villains-api:
    build: ~/Desktop/Dev/tour-of-villains-api
    ports:
      - 5111:5111
      - 50001:50001 # Dapr instances communicate over gRPC so we need to expose the gRPC port
    environment:
      - "DAPR_HTTP_PORT=3501"
      - "DAPR_GRPC_PORT=50001"
      - ConnectionStrings__DefaultConnection=Server=sqlserver,1433;Initial Catalog=heroes;Persist Security Info=False;User ID=sa;Password=Password1!
    depends_on:
      - redis
      - sqlserver
    networks:
      - tour-of-heroes-dapr
  tour-of-villains-api-dapr:
    image: "daprio/daprd:edge"
    command:
      [
        "./daprd",
        "-app-id",
        "tour-of-villains-api",
        "-app-port",
        "5111",
        "-dapr-grpc-port",
        "50001",
        "-dapr-http-port",
        "3501",
        "-components-path",
        "/components",
        "-log-level",
        "debug"
      ]
    volumes:
      - "~/Desktop/Dev/tour-of-villains-api/docker-compose-components:/components"
    depends_on:
      - tour-of-villains-api
    network_mode: "service:tour-of-villains-api"
  ############################
  # Redis state store        #
  ############################
  redis:
    image: "redis:alpine"
    ports:
      - "6380:6379"
    command: ["--requirepass", "passw0d!"]
    networks:
      - tour-of-heroes-dapr
  ############################
  # SQL Server               #
  ############################
  sqlserver:
    image: mcr.microsoft.com/mssql/server
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=Password1!
      - MSSQL_PID=Express
    networks:
      - tour-of-heroes-dapr
  ###########################
  # Dapr dashboard          #
  ###########################
  # dapr-dashboard:
  #   image: "ghcr.io/dapr/dashboard:latest"
  #   ports:
  #     - 8000:8080
  #   networks:
  #     - tour-of-heroes-dapr
networks:
  tour-of-heroes-dapr: null

En él se puede ver que tengo dos contenedores por cada API: uno para la propia aplicación y el otro con el sidecar de Dapr, que depende del principal. Además he añadido un SQL Server para que las APIs puedan usarlo para almacenar los héroes y los villanos, y un Redis, ya que el que genera Dapr con dapr init ya no es necesario.

He dejado comentado Dapr Dashboard porque me parece una buena herramienta para ver lo que ocurre dentro de este entorno completamente dockerizado, pero a día de hoy no está soportado en la última versión, aunque sí que es cierto que hay una pull request al respecto, pendiente de ser aceptada.

De esta forma podrás levantar todos los elementos de un entorno, incluidos los servicios asociados a los componentes (si tienen versión dockerizada), dejando tu equipo limpio cuando no estés jugando con Dapr.

¡Saludos!