How do I round robin between services if the rule matches two services instead of picking one based on priority?

I have a scenario where I want to provide high availability to login users.

I wanted to run two services, one is for visitors S1 and one is for admins S2. I also wanted to visitor requests to go to second service S2 only when there is no logged in users. This way when a user trying to login/logged, the next visitor requests will go the first one S1 and let the second S2 one available for admin users.

  • Scenario 1 - Visitor, None Admin users logged in the past N minutes -> X-Admin-Logged is No, X-Login-Session is No
  • Scenario 2 - Visitor, One of the Admin Users logged in the past N minute -> X-Admin-Logged is yes, X-Login-Session is No.
  • Scenario 3 - Admin User trying to login -> X-Admin-Logged is yes and X-Login-Session is yes (cookie would be set or based on successful login)
  • Scenario 4 - Admin User editing -> X-Admin-Logged is yes and X-Login-Session is yes

I have written cloudflare worker to handle the above using cookie/url and setting the header X-Admin-Logged and X-Login-Session.

  # Scenario 1 - Visitor, No Admin user logged in the past N minutes -> X-Admin-Logged is No, X-Login-Session is No
  # Scenario 2 - Visitor, Admin User logged in the past N minute -> X-Admin-Logged is yes, X-Login-Session is yes.  
  whoami:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`HOST`) && (Headers(`X-Admin-Logged`, `no`) || Headers(`X-Login-Session`, `no`))"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"
      - "traefik.http.routers.whoami.tls=true"
      - "traefik.http.routers.whoami.tls.certresolver=le"
      - "traefik.http.routers.whoami.middlewares=traefik-real-ip"
      - "traefik.http.middlewares.traefik-real-ip.plugin.traefik-real-ip.excludednets=1.1.1.1/24"
    networks:
      - web-servers

  # Scenario 1 - Visitor, No Admin user logged in the past N minutes -> X-Admin-Logged is No, X-Login-Session is No
  # Scenario 2 - Visitor, Admin User logged in the past N minute -> X-Admin-Logged is yes, X-Login-Session is yes.
  # Scenario 3 - Admin User trying to login -> X-Admin-Logged is yes and X-Login-Session is yes
  # Scenario 4 - Admin User editing -> X-Admin-Logged is yes and X-Login-Session is yes
  whoami2:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami2.rule=Host(`HOST`) && (Headers(`X-Admin-Logged`, `no`) || Headers(`X-Login-Session`, `yes`))"
      - "traefik.http.services.whoami2.loadbalancer.server.port=80"
      - "traefik.http.routers.whoami2.tls=true"
      - "traefik.http.routers.whoami2.tls.certresolver=le"
      - "traefik.http.routers.whoami2.middlewares=traefik-real-ip"
      - "traefik.http.middlewares.traefik-real-ip.plugin.traefik-real-ip.excludednets=1.1.1.1/24"
    networks:
      - web-servers

Now, since traefik match and pick the first one instad of round robin, the Visitor requests will always goes to S1 never goes S2 using round robin.

Can somebody help me to achieve this?

Hi @ithiru,
Thanks for your interest in Traefik.

I don't really get the scenario you are trying to achieve.
If I understood correctly, to want to:

  • forward not logged users to S1 and S2
  • forward logged users to S1
  • forward admin users to S2.

I didn't test it, but could you try to create one router per scenario?

    - "traefik.http.routers.unauthenticated.rule=Headers(`X-Login-Session`, `no`)"
    - "traefik.http.routers.unauthenticated.service=service-s1-s2"

    - "traefik.http.routers.admin.rule=Headers(`X-Admin-Logged`, `yes`) && Headers(`X-Login-Session`, `yes`)"
    - "traefik.http.routers.admin.service=service-s2"

    - "traefik.http.routers.authenticated.rule=Headers(`X-Admin-Logged`, `no`) && Headers(`X-Login-Session`, `yes`)"
    - "traefik.http.routers.authenticated.service=service-s1"

With the given example, it could be difficult to maintain, so I would suggest using a configuration file as a dynamic configuration provider.
To create service load balancer (for service-s1-s2), you can have a look at the service documentation.

Thanks for the input. Will try it and provide feedback.