Docker dynamic labels when not using swarm

I am trying to move a Traefik web service config from a yml file to embedding the config as labels in the docker-compose file. I have tried several times and not seen any evidence that the labels are being read.

The docs https://docs.traefik.io/providers/docker/#docker-swarm-mode seem to state that config can be read from the docker-compose file. And several searches show people have to move the labels to the deploy section of the docker-compose file. As I understand it that is only when running a docker swarm.

  • I am not running a swarm
  • I have multiple docker-compose files on the same server. Only the labels in the Traefik docker-compose file (traefik and whoami services) seem to work.

Do I have to move over to a swarm to be able to take advantage of the labels?

version: '3'
services:
  web:
    build: nginx

#    networks:
#      - outside
#      - default

    #ports:
      # Port should be set in docker-compose.override.yml
      # - "9999:80"

    volumes:
      - ./src/public:/usr/share/nginx/html:ro

      - ./nginx/sites-enabled:/etc/nginx/sites-enabled
      - ./nginx/snippets:/etc/nginx/snippets
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./files:/files
      - /var/run/docker.sock:/var/run/docker.sock:ro

    labels:
      - "traefik.enable=true"

      - "traefik.http.routers.web.entrypoints=websecure"
      - "traefik.http.routers.web.rule=Host(`fiagt.gxxxs.page`)"
      - "traefik.http.routers.web.service=fiagt"

      # Authentication
      - "traefik.http.routers.web.middlewares=usersfile@file"

      # Certificate name and san
      - "traefik.http.routers.web.tls.certresolver=basic"
      - "traefik.http.routers.web.tls.domains[0].main=gxxxs.page"
      - "traefik.http.routers.web.tls.domains[0].sans=*.gxxxs.page"

      # Services
      - "traefik.http.services.web.servers.url=http://192.168.1.130:8007/index.php"
      - "traefik.http.services.web.loadbalancer.server.port=80"
      - "traefik.http.services.web.passhostheader=false"
      - "traefik.http.services.web.hostname=fiagt.docker.dev.gxxxs.page"

    links:
      - php

  php:
    build: php

#    networks:
#      - default

    ulimits:
      nproc: 65535
      nofile:
        soft: 20000
        hard: 40000

    #mem_limit: 4000000000
    #memswap_limit: 8000000000
    privileged: true

    volumes:
      - ./src/public:/usr/share/nginx/html
      # On the php service run ps aux | grep php-fpm to see where the php-fpm.conf is found
      #decided to stop sharing these files and use the Dockerfile to create the required entries
      #- ./php/conf:/usr/local/etc
      - ./files:/files
    links:
      - db

  # The Database
  db:
    image: mysql:5.7
    volumes:
      - ./mysql/db:/var/lib/mysql
      - ./mysql/source:/docker-entrypoint-initdb.d
    #restart: always
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: "no"
      MYSQL_ROOT_PASSWORD: 
      MYSQL_DATABASE: fiagt
      MYSQL_USER: root
      MYSQL_PASSWORD: 
    ports:
      - "33061:3306"

# Add a phpmyadmin container when needed.
# http://docker.dev:8000 to launch
# credentials:
  phpmyadmin:
    image: nazarpc/phpmyadmin

    #ports:
    #- "9998:80"

    links:
      - db:mysql

    labels:
      - "traefik.enable=true"

      - "traefik.http.routers.phpmyadmin.entrypoints=websecure"
      - "traefik.http.routers.phpmyadmin.rule=Host(`fiagtadm.gxxxs.page`)"
      - "traefik.http.routers.phpmyadmin.service=fiagtadm"

      # Authentication
      - "traefik.http.routers.phpmyadmin.middlewares=usersfile@file"

      # Certificate name and san
      - "traefik.http.routers.phpmyadmin.tls.certresolver=basic"
      - "traefik.http.routers.phpmyadmin.tls.domains[0].main=gxxxs.page"
      - "traefik.http.routers.phpmyadmin.tls.domains[0].sans=*.gxxxs.page"

      # Services
      - "traefik.http.services.phpmyadmin.servers.url=http://192.168.1.130:9007/index.php"
      - "traefik.http.services.phpmyadmin.passhostheader=false"

#networks:
#  outside:
#    external:
#      name: adbname

Hello,

You don't have to move to swarm.

You need to manage the different networks related to your docker-compose files.


The exhaustive list of labels that you can use for services: Docker | Traefik | v2.1

As the IP are dynamic (related to Docker) and detected automatically by Traefik, you just have to define (if needed) the port by using traefik.http.services.<random_name>.loadbalancer.server.port

Thank you Idez,
the docs are helpful, but I did not succeed yet.

First a historic statement - I learnt to use docker on an old Mac with VirtualBox and networking was a nightmare to get working. I recently moved my docker env to Ubuntu and did not think to review the network settings - I'd be happy if I can remove all the network references - I tried - but so far I kept getting problems.

Back to the settings - I removed the unsupported parameters and tried again. Still no luck ( I assume a docker-compose down / docker-compose up for my app will trigger Traefik to refresh the list of routers).

For simplicity, I'll omit the 2nd service.

version: '3'

networks:
  default:
    external:
      name: nucnuc

services:
  web:
    build: nginx

    # networks:
    #   - nucnuc
    #   - default

    ports:
      # Set the required port number here and update launcher :: siteCatalog.yml
      - "8007:80"
    #ports:
      # Port should be set in docker-compose.override.yml
      # - "9999:80"

    volumes:
      - ./src/public:/usr/share/nginx/html:ro

      - ./nginx/sites-enabled:/etc/nginx/sites-enabled
      - ./nginx/snippets:/etc/nginx/snippets
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./files:/files
      - /var/run/docker.sock:/var/run/docker.sock:ro

    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=nucnuc"

      - "traefik.http.routers.web.rule=Host(`fiagt.gxxxs.page`)"
      - "traefik.http.routers.web.entrypoints=websecure"

      - "traefik.http.routers.web.service=fiagt"

      # Authentication
      - "traefik.http.routers.web.middlewares=usersfile@file"

      # Certificate name and san
      - "traefik.http.routers.web.tls.certresolver=basic"
      - "traefik.http.routers.web.tls.domains[0].main=gxxxs.page"
      - "traefik.http.routers.web.tls.domains[0].sans=*.gxxxs.page"

      # Services
      - "traefik.http.services.fiagt.loadbalancer.server.port=8007"
      - "traefik.http.services.fiagt.loadbalancer.server.scheme=http"
      - "traefik.http.services.fiagt.passhostheader=false"


    links:
      - php
...omitted

Should the port be the internal port or the published port ?

traefix services has
- --providers.docker.exposedbydefault=false

which results in:

traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=web-fiagt-f8e56f8ab78916eddc35f99a819e28eb245a158b86058afa0469118838d7a644
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" container=php-fiagt-263b9a6865705787fa78cdf960f4bfd2ce09cee397a81885377f001fd26d23af providerName=docker
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=phpmyadmin-fiagt-8c0cedbb6c07ec241d2bec97bbde3386f17a55e88dbe6603c0859a389c5789c1
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=db-fiagt-6f3d844d133568f3b94e144748eb0ecaf0e9909f14ff4016c47ed2e0d96013ff
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=jaeger-agent-jaeger-1fa2fd0ca2fd0870b2f09bac1d21201b8437455cc92fdd1c03db29b35486bd2a
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=jaeger-collector-jaeger-826afb0c5c9272e6bdaf976dbb7e22712bc2895d6b2370c52e09e70d04f83dde
traefik_1  | time="2020-02-18T16:00:19Z" level=debug msg="Filtering disabled container" providerName=docker container=cassandra-jaeger-73e7b1bbf82c84731c09b7a35ebfe4c5064641c3fe56e0f6f736742b214d480d

But I think that is expected.

For completeness here is the traefik docker-compose file.

version: '3'

networks:
  default:
    external:
      name: nucnuc

services:
  traefik:
    # The official v2.1 Traefik docker image
    image: traefik:v2.1.4
#    networks:
#      - nucnuc
    command: 
      # - --accesslog=true
      - --api
      - --api.insecure=false # Enables the web UI
      - --entrypoints.web.address=:80 #Declares the web entrypoint in Traefik
      - --entrypoints.websecure.address=:443 #Declares the websecure entrypoint in Traefik
      - --global.sendAnonymousUsage=true
      - --log.level=DEBUG
      - --providers.docker=true #and tells Traefik to listen to docker
      # Enable a tls challenge named "basic"
      - "--certificatesresolvers.basic.acme.email=steve@groom.ch"
      - "--certificatesresolvers.basic.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.basic.acme.dnschallenge.provider=cloudflare"
      # - "--certificatesresolvers.basic.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      # Providers
      - --providers.file.directory=/conf
      - --providers.file.watch=true
      - --providers.docker.exposedbydefault=false
      - --tracing=true
      - --tracing.serviceName=traefik
      - --tracing.jaeger=true
      - --tracing.jaeger.samplingServerURL=http://localhost:5778/sampling
      - --tracing.jaeger.samplingType=const
      - --tracing.jaeger.samplingParam=1.0
      - --tracing.jaeger.traceContextHeaderName=uber-trace-id
      - --tracing.jaeger.collector.endpoint=http://jaeger-collector:14268/api/traces?format=jaeger.thrift

    ports:
      - "80:80"
      - "443:443"
      - "8080:8080" # The Web UI (enabled by --api.insecure=true)

    labels:
      #
      - "traefik.enable=true"
      - "traefik.docker.network=nucnuc"
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`traefik.gxxxs.page`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls.certresolver=leresolver"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.middlewares=usersfile@file"
#      - "traefik.http.routers.traefik.middlewares=forwardAuth"
 
      # Global Redirect to https
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=websecure"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"

      # Middleware Redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"

      # Authentication
      #- "traefik.http.middlewares.authtraefik.basicauth.users=user:your htaccess password cipher" # user/password"

      # Certificate name and san
      - "traefik.http.routers.traefik.tls.certresolver=basic"
      - "traefik.http.routers.traefik.tls.domains[0].main=gxxxs.page"
      - "traefik.http.routers.traefik.tls.domains[0].sans=*.gxxxs.page"

    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - "./letsencrypt:/letsencrypt"
      - "./conf:/conf"
    
    environment:
      - CF_API_EMAIL=<your cloudflare email address>
      - CF_DNS_API_TOKEN=<your cloudflare api token>
      - CF_ZONE_API_TOKEN=<your cloudflare api token>

# #
  whoami:
    # A container that exposes an API to show its IP address
    image: containous/whoami
#    networks:
#      - nucnuc

    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=nucnuc"

      - "traefik.http.routers.whoami.rule=Host(`whoami.gxxxs.page`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"

      - "traefik.http.routers.whoami.tls=true"
      - "traefik.http.routers.whoami.tls.certresolver=basic"
      - "traefik.http.routers.whoami.tls.domains[0].main=gxxxs.page"
      - "traefik.http.routers.whoami.tls.domains[0].sans=*.gxxxs.page"
#      - "traefik.http.routers.whoami.tls.certresolver=le"
#      - "traefik.http.routers.whoami.tls.certificates.certFile=/letsencrypt"

      - "traefik.http.routers.whoami.middlewares=usersfile@file"      
#      - "traefik.http.middlewares.authtraefik.basicauth.users=user:your htaccess password cipher" # user/password

regards
Steve

Should be the internal port (80)

Yes it's expected and right.

@Idez, thanks for the pointers. I managed to get it working in the end.

One thing that was throwing me was that the service names used in docker-compose have to be unique across the docker-machine.

I had two different solutions using service web and eventually spotted that the Traefik router on one solution was actually invoking the web service on the other. I now have it working, but don't feel this is the best solution as I would like to reuse docker-compose files as templates in several projects.

regards
Steve