Search code examples
docker-composetraefik

Docker-compose and traefik port mapping


I'm currently trying to run multiple instances of the same docker-compose file.

Each instance have a traefik service which should only listen for a given host.

I want to have only one docker-compose file, and all params are stored in env variables. Each instance is run in its own directory.

In order to do that, i want traefik to redirect the http traffic (80 and 443) to my internal network, with the ability to define custom ports (eg 81 and 444) to avoid conflict when running more than one instance.

I try to use traefik constraint and port mapping, but if i put other values than 80, 443, and 8080 to TRAEFIK_XXX vars, no traffic seem to reach my containers.

Here is the relevant part of my docker-compose file :

version: "3.9"

services:
  traefik:
    image: traefik:2.10.7
    restart: always
    networks:
      - traefik
    ports:
      - "${TRAEFIK_HTTP_PORT}:80"
      - "${TRAEFIK_HTTPS_PORT}:443"
      - "${TRAEFIK_API_PORT}:8080"
    command:
      # provider
      - "--providers.docker=true"

      # log
      - "--log.level=DEBUG"

      # entry points
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"

      # for https
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true"

      # constraint
      - "--providers.docker.constraints=Label(`traefik.constraint-label`, `traefik_${INSTANCE_ID}`)"

    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=traefik_${INSTANCE_ID}"
      - "traefik.docker.network=traefik_${INSTANCE_ID}"
      - "traefik.http.routers.traefik.rule=Host(`traefik.${BASE_DOMAIN}`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=myresolver"

  strapi:
    build:
      context: ./strapi
      dockerfile: Dockerfile.prod
    restart: unless-stopped
    hostname: "strapi.${BASE_DOMAIN}"
    depends_on:
      - postgres
      - redis
    networks:
      - samplstrap
      - traefik
    ports:
      - "${STRAPI_PORT}:1337"
    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=traefik_${INSTANCE_ID}"
      - "traefik.docker.network=traefik_${INSTANCE_ID}"
      - "traefik.http.services.strapi.loadbalancer.server.port=1337"
      - "traefik.http.routers.strapi.rule=Host(`strapi.${BASE_DOMAIN}`)"
      - "traefik.http.routers.strapi.entrypoints=websecure"
      - "traefik.http.routers.strapi.tls.certresolver=myresolver"

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod
    restart: always
    depends_on:
      - strapi
    networks:
      - samplstrap
      - traefik
    volumes:
      - frontend_node_modules:/app/frontend/node_modules
    ports:
      - "${FRONTEND_PORT}:3000"
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_${INSTANCE_ID}"
      - "traefik.constraint-label=traefik_${INSTANCE_ID}"
      - "traefik.http.services.frontend.loadbalancer.server.port=3000"
      - "traefik.http.routers.frontend.rule=Host(`www.${BASE_DOMAIN}`, `${BASE_DOMAIN}`)"
      - "traefik.http.routers.frontend.entrypoints=websecure"
      - "traefik.http.routers.frontend.tls.certresolver=myresolver"
  
networks:
  traefik:
    external: true
    name: traefik_${INSTANCE_ID}
  samplstrap:
    internal: true

Thanks !


Solution

  • A better solution for that setup is probably having one docker-compose file for Traefik and then another docker-compose file for all other services. Because only one Traefik container is needed and the other services are to be run as several instances.

    My suggestions start with ### in the code.

    File to be used only in/for one directory/instance:

    Filename: compose.traefik.yml

    services:
      traefik:
        image: traefik:2.10.7
        restart: always
        networks:
          - traefik
        ports:
          ### Ports without variables, always like this
          - "80:80"
          - "443:443"
          - "8080:8080"
    
        ### This needs to be added
        volumes: 
          - /var/run/docker.sock:/var/run/docker.sock:ro
    
        command:
          # provider
          - "--providers.docker=true"
    
          # log
          - "--log.level=DEBUG"
    
          # entry points
          - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
          - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
    
          # for https
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          - "--entrypoints.websecure.http.tls=true"
    
          # constraint
          ### Remove this line
          #- "--providers.docker.constraints=Label(`traefik.constraint-label`, `traefik_${INSTANCE_ID}`)"
    
        labels:
          - "traefik.enable=true"
    
          ### Remove this line
          #- "traefik.constraint-label=traefik_${INSTANCE_ID}"
    
          - "traefik.docker.network=traefik"
          - "traefik.http.routers.traefik.rule=Host(`traefik.${BASE_DOMAIN}`)"
          - "traefik.http.routers.traefik.entrypoints=websecure"
          - "traefik.http.routers.traefik.service=api@internal"
          - "traefik.http.routers.traefik.tls=true"
          - "traefik.http.routers.traefik.tls.certresolver=myresolver"
    
    networks:
      traefik:
        external: true
        ### Network name just 'traefik'
        name: traefik
    

    File to be used in/for several directories/instances:

    Filename: compose.instance.yml

    services:
    
      strapi:
        build:
          context: ./strapi
          dockerfile: Dockerfile.prod
        restart: unless-stopped
        hostname: "strapi.${BASE_DOMAIN}"
        depends_on:
          - postgres
          - redis
        networks:
          - samplstrap
          ### Network name just 'traefik'
          - traefik
    
        ### Remove this
        #ports:
        #  - "${STRAPI_PORT}:1337"
    
        labels:
          - "traefik.enable=true"
    
          ### Remove this line
          #- "traefik.constraint-label=traefik_${INSTANCE_ID}"
    
          ### Network name just 'traefik'
          - "traefik.docker.network=traefik"
    
          ### Remove this line
          #- "traefik.http.services.strapi.loadbalancer.server.port=1337"
    
          - "traefik.http.routers.strapi.rule=Host(`strapi.${BASE_DOMAIN}`)"
          - "traefik.http.routers.strapi.entrypoints=websecure"
          - "traefik.http.routers.strapi.tls.certresolver=myresolver"
    
      frontend:
        build:
          context: ./frontend
          dockerfile: Dockerfile.prod
        restart: always
        depends_on:
          - strapi
        networks:
          - samplstrap
          ### Network name just 'traefik'
          - traefik
        volumes:
          - frontend_node_modules:/app/frontend/node_modules
    
        ### Remove this
        #ports:
          #- "${FRONTEND_PORT}:3000"
    
        labels:
          - "traefik.enable=true"
    
          ### Network name just 'traefik'
          - "traefik.docker.network=traefik"
    
          ### Remove this line
          #- "traefik.constraint-label=traefik_${INSTANCE_ID}"
    
          ### Remove this line
          #- "traefik.http.services.frontend.loadbalancer.server.port=3000"
    
          - "traefik.http.routers.frontend.rule=Host(`www.${BASE_DOMAIN}`, `${BASE_DOMAIN}`)"
          - "traefik.http.routers.frontend.entrypoints=websecure"
          - "traefik.http.routers.frontend.tls.certresolver=myresolver"
      
    networks:
      traefik:
        external: true
        ### Network name just 'traefik'
        name: traefik
      samplstrap:
        internal: true
    

    This answer is for making Traefik configuration work. Methods or ports for communication between strapi and frontend is not in the scope of this answer.