Search code examples
linkerd

linkerd Dtab expression not transforming as expected


I've got linkerd running locally per this getting started page, and the basic proxy example works. My use case requires me to proxy web requests to one of several .NET WebApi services, so I made a little sample WebApi project running locally that has two routes:

  1. localhost:58371 returns hello world
  2. localhost:58371/api/values returns ["value1", "value2"]

Mapping requests with matching routes

If I leave my linkerd.yaml file like it comes out-of-the-box:

routers: - protocol: http dtab: | /svc => /#/io.l5d.fs

then mapping routes directly works:

curl -H "Host: web" http://localhost:4140/ --> hello world

curl -H "Host: web" http://localhost:4140/api/values --> ["value1", "value2"]

Mapping mismatched routes

Now, I would like to map localhost:4140/tacos --> localhost:58371/api/values. So, I update my .yaml file to:

routers: - protocol: http dtab: | /svc => /#/io.l5d.fs; /tacos => /api/values; and restart linkerd.

However, http://localhost:4140/ always seems to resolve to http://localhost:58371/tacos, not http://localhost:58371/api/values. What am I not understanding?

I've read through a bunch of example dtab transformations on linkerd's site, and I've played around with a bunch of different configurations in my yaml file. Surely it's just something silly that I'm missing because this seems like a really simple use case.


Solution

  • By default, linkerd uses the value of the HTTP Host header associated with the request to route traffic. In your example, you're setting Host: web, so all traffic is going to the "web" service that's found in service discovery, regardless of the request URI's path.

    So rather than sending your request to localhost:4140/tacos, you should send it to -H 'Host: tacos' localhost:4140/api/values. You would also need to adjust your dtab as follows:

    /svc       => /#/io.l5d.fs;
    /svc/tacos => /svc/web;
    

    That will route all traffic with Host: tacos to the "web" service that's found in service discovery. This is just the default configuration, however.

    If you're interested in routing based on the URI path instead of the HTTP Host header, you can use linkerd's path identifier. Something like:

    routers:
    - protocol: http
      identifier:
        kind: io.l5d.path
        segments: 1
      dtab: |
        /svc => /#/io.l5d.fs;
    

    With that configuration, a request to localhost:4140/api/values would be routed to the "api" service in service discovery, and a request to localhost:4140/tacos would be routed to the "tacos" service, and both of those routing decisions can be changed by modifying your dtab.

    I should note that linkerd does not do arbitrary HTTP URI path rewriting based on dtab rules. Since it's a proxy, it expects to proxy the request without modification, with a few exceptions (such as the consume option on the path identifier). You could always write a linkerd plugin though that would fit your specific use case.