Routing traffic

I'm replacing a Zuul Router, that uses static routes like this:
(Sample Zuul Config)

zuul:
  routes:
    # routes are in a specific order of precedence

    # Client services
    report-service:
      path: /**/reports/**
      url: https://report-app-dev.....

    data-service:
      path: /**/datasets/**/data
      url: https://dataset-data-app-dev.....

The Report backend service should respond to:

GET http://mybackendservice:port/health
GET http://mybackendservice:port/info
GET http://mybackendservice:port/reports/whatever

I've created several frontend rules..

traefik.frontend.rule.rule1 Path: /reports/health; ReplacePath: /health
traefik.frontend.rule.rule2 Path: /reports/info; ReplacePath: /info
traefik.frontend.rule.rule3 Path: /reports

It shows up in the trafefik dashboard as:

frontend-fabric:/FA_App/Report-App
      Route Rule
      Path: /reports/health; ReplacePath: /health
      Path: /reports/info; ReplacePath: /info
      Path: /reports/
      Entry Points
      http
      Backend
      fabric:/FA_App/Report-App

But, testing in the browser, I get:

http://myfrontend:port/reports/health -   404 page not found
http://myfrontend:port/reports/info -   404 page not found
http://myfrontend:port/reports -   404 page not found

The Access log shows:

[23/Jul/2019:17:17:35 +0000] "GET /reports/health HTTP/1.1" 404 19 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" 2 "backend not found" "/reports/health" 0ms
[25/Jul/2019:16:17:37 +0000] "GET /reports HTTP/1.1" 404 19 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" 3 "backend not found" "/reports" 4ms
[25/Jul/2019:16:17:38 +0000] "GET /favicon.ico HTTP/1.1" 404 19 "http://myurl.com:8029/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" 4 "backend not found" "/favicon.ico" 0ms

If I reduce this to a single rule:

traefik.frontend.rule.default2=PathPrefix: /reports

The app works ok..

But /reports/health doesnt work.. obv service is expecting just /health, not /reports/health, so I tried a second rule

PathPrefixStrip: /reports/health, ReplacePath: /health

but this doesnt seem to do anything.. I tried putting it first and it breaks everything..

Hi @solidcloudio, you might want to read carefully this section: https://docs.traefik.io/v1.7/basics/#frontends.

You want to use PathPrefix alone: traefik.frontend.rule.default2=PathPrefixStrip: /reports will match any request in /reports(.*) and will automatically remove the /reports string.

I read this many times, I think the confusion is in the labels.. The sample shows:

<StatelessServiceType ServiceTypeName="WebServiceType">
  <Extensions>
      <Extension Name="Traefik">
        <Labels xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
          <Label Key="traefik.frontend.rule.example2">PathPrefixStrip: /a/path/to/strip</Label>
          <Label Key="traefik.enable">true</Label>
          <Label Key="traefik.frontend.passHostHeader">true</Label>
        </Labels>
      </Extension>
  </Extensions>
</StatelessServiceType>

Whats unclear to me is what is a valid entry for the Label Key, anything? I've seen:

traefik.frontend.rule.default
traefik.frontend.rule.default2
traefik.frontend.rule.example2
traefik.frontend.rule.rule1
traefik.frontend.rule.rule2

All these are valid ?

docs only show one:

traefik.frontend.rule=EXPR

That doenst really make it clear what's a valid entry here..

OK, I updated my rules... dashboard shows:

Route Rule
Path: /reports/health; ReplacePath: /health
PathPrefix: /reports

Entry Points
https

Backend
fabric:/FA_App/Reports-App

So if I hit:

https://myserver:8029/reports/health, it works; routes the traffic to the Reports service and re-writes the request as health.. so I see the health endpoint response.

If I try https://myserver:8029/reports I get a 404 page not found.

I'm trying:

rule1 - Path: /reports/health; ReplacePath: /health
rule2 - PathPrefix: /reports

rule1 seems to work, but anything other than /reports/health doesn't work.

/reports - 404 page not found
/reports/rptA - 404 page not found

Shouldn't rule2 be a catchall here as rule 1 doesnt apply? Access log reports "backend not found"

Rule 1 should catch /reports/health but not /reports or /reports/anything else.. So its first..
Rule 2 should catch everything else, right ?

Hmm, if I change the rule order it doesnt have any effect, the helth route works, but thats the only one..

Traefik handles multple rules with an AND operation: (https://docs.traefik.io/v1.7/basics/#combining-multiple-rules)

Your 2 rules combine to be:

Match if:

  • The Path is EXACTLY /reports/health AND,
  • The Path begins with /reports

The solution is to create a new service with only the PathPrefix rule.

Note that you may have to assign the two services priorities to ensure the health rule gets processed first, but that depends how the provider builds the rules in the server.

hmm, well there is obv no sample for that with Service Fabric.. Here is one of my services

<StatelessServiceType ServiceTypeName="Report-AppType" UseImplicitHost="true">
      <Extensions>
        <Extension Name="Traefik">
          <Labels xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
            <Label Key="traefik.enable">true</Label>
            <Label Key="traefik.frontend.rule1">PathPrefix: /reports</Label>
            <Label Key="traefik.frontend.rule2">Path: /reports/health; ReplacePath: /health</Label>
            <Label Key="traefik.frontend.entryPoints">https</Label>
            <Label Key="traefik.backend.healthcheck.path">/health</Label>
            <Label Key="traefik.backend.healthcheck.port">8074</Label>
            <Label Key="traefik.backend.healthcheck.interval">60s</Label>
            <Label Key="traefik.backend.healthcheck.hostname">localhost</Label>
            <Label Key="traefik.servicefabric.groupname">App1</Label>
          </Labels>
        </Extension>
      </Extensions>
    </StatelessServiceType>

How can I create a new service? Trying this:

        <Label Key="traefik.frontend1.entryPoints">https</Label>
        <Label Key="traefik.frontend1.rule1">PathPrefix: /reports</Label>
        <Label Key="traefik.frontend2.rule1">Path: /reports/health; ReplacePath: /health</Label>
        <Label Key="traefik.frontend2.entryPoints">https</Label>           

Hmm, well that didnt work, Dashboard shows No Routing rules now.. trying:traefik.frontends.frontend1.... and traefik.frontends.frontend2....

That doesnt work either... hmm, no rules shown on the dashboard.. If I call the API on my trafeak Entrypoint http://myserver:8030/api/providers

The routes are missing for the report service..

 "frontend-fabric:\/App1\/Report-App": {
        "entryPoints": [
          "https"
        ],
        "backend": "fabric:\/App1\/Report-App",
        "passHostHeader": true,
        "priority": 0,
        "basicAuth": null
      },
      "frontend-fabric:\/App1\/Entity-App": {
        "entryPoints": [
          "https"
        ],
        "backend": "fabric:\/App1\/Entity-App",
        "routes": {
          "traefik.frontend.rule.default": {
            "rule": "PathPrefix: \/entities"
          }
        },
        "passHostHeader": true,
        "priority": 0,
        "basicAuth": null
      },

If I dig into the Service Fabric provider: https://github.com/containous/traefik-extra-service-fabric/blob/f6e0f1081f62552dc5df721bd9c61723ac1bac32/servicefabric_tmpl.go

It uses:

[frontends]

{{range $groupName, $groupServices := getGroupedServices .Services }}

  {{ $service := index $groupServices 0 }}

  [frontends."{{ $groupName }}"]

    backend = "{{ $groupName }}"

    priority = 50

  {{range $key, $value := getFrontendRules $service }}

    [frontends."{{ $groupName }}".routes."{{ $key }}"]

      rule = "{{ $value }}"

  {{end}}

{{end}}

Later in that template it shows:

      {{range $key, $value := getFrontendRules $service }}

        [frontends."frontend-{{ $frontendName }}".routes."{{ $key }}"]

          rule = "{{ $value }}"

      {{end}}

I'm not a GO developer, but this looks like a templating language that is producing the configuration on the fly. So the system probably picks up all the property data from the Service Fabric API, loads it into a context, and parses this template..

I'll have to keep experiementing with this.. I've probably lost most the audience here off in some templating language..

If I call the Trafaek/api/providers method

The /api/providers call returns info about the active configuration:

"frontend-fabric:\/App1\/Comment-App": {
        "entryPoints": [
          "https"
        ],
        "backend": "fabric:\/App1\/Comment-App",
        "routes": {
          "traefik.frontend.rule.default": {
            "rule": "PathPrefix: \/comments"
          }
        },
        "passHostHeader": true,
        "priority": 0,
        "basicAuth": null
      },
      "frontend-fabric:\/App1\/Report-App": {
        "entryPoints": [
          "https"
        ],
        "backend": "fabric:\/App1\/Report-App",
        "passHostHeader": true,
        "priority": 0,
        "basicAuth": null
      },

So, you can see, my config section wasnt parsed correctly as there are no routes present for the Reporting service.

So, after a journey down the rabbit-hole, learning go, learning go's template language and a bunch of other tools. The Service fabric provider isn't intelligent enough to translate labels into multiple frontends with different routes.

This is required as you can't enter multiple routes in Traefik v1.7 without Traefik treating them like an AND condition. You have to define multiple frontends for this to work.

The only way to make this work in v1.7 is to write a more manual config for the frontends, similar to how jjcolonge outlined here https://github.com/jjcollinge/traefik-on-service-fabric/blob/master/Docs/CustomTemplates.MD

It's possible in v2.0, but as of now, no-body has put in the effort to create the v2.0 provider for Service Fabric.