Using Ingress

    When it comes to ingress, most controllers do not rewrite theincoming header (example.com) to the internal service name(example.default.svc.cluster.local) by default. In this case, when Linkerdreceives the outgoing request it thinks the request is destined forexample.com and not example.default.svc.cluster.local. This creates aninfinite loop that can be pretty frustrating!

    Luckily, many ingress controllers allow you to either modify the Host headeror add a custom header to the outgoing request. Here are some instructionsfor common ingress controllers:

    NoteIf your ingress controller is terminating HTTPS, Linkerd will only provideTCP stats for the incoming requests because all the proxy sees is encryptedtraffic. It will provide complete stats for the outgoing requests from yourcontroller to the backend services as this is in plain text from thecontroller to Linkerd.

    NoteIf requests experience a 2-3 second delay after injecting your ingresscontroller, it is likely that this is because the service of type:LoadBalancer is obscuring the client source IP. You can fix this by settingexternalTrafficPolicy: Local in the ingress’ service definition.

    This uses emojivoto as an example, take a look at for a refresher on how to install it.

    The sample ingress definition is:

    The important annotation here is:

    1. nginx.ingress.kubernetes.io/configuration-snippet: |
    2. proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
    3. grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;

    This example combines the two directives that NGINX uses for proxying HTTPand gRPC traffic. In practice, it is only necessary to set either theproxy_set_header or grpc_set_header directive, depending on the protocolused by the service, however NGINX will ignore any directives that it doesn’tneed.

    This sample ingress definition uses a single ingress for an applicationwith multiple endpoints using different ports.

    1. apiVersion: extensions/v1beta1
    2. kind: Ingress
    3. metadata:
    4. name: web-ingress
    5. namespace: emojivoto
    6. annotations:
    7. kubernetes.io/ingress.class: "nginx"
    8. nginx.ingress.kubernetes.io/configuration-snippet: |
    9. proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
    10. grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
    11. spec:
    12. rules:
    13. - host: example.com
    14. http:
    15. paths:
    16. - path: /
    17. backend:
    18. serviceName: web-svc
    19. servicePort: 80
    20. - path: /another-endpoint
    21. backend:
    22. serviceName: another-svc
    23. servicePort: 8080

    Nginx will add a l5d-dst-override header to instruct Linkerd what servicethe request is destined for. You’ll want to include both the Kubernetes serviceFQDN (web-svc.emojivoto.svc.cluster.local) and the destinationservicePort.

    To test this, you’ll want to get the external IP address for your controller. Ifyou installed nginx-ingress via helm, you can get that IP address by running:

    1. kubectl get svc --all-namespaces \
    2. -l app=nginx-ingress,component=controller \
    3. -o=custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip

    You can then use this IP with curl:

    1. curl -H "Host: example.com" http://external-ip

    NoteIt is not possible to rewrite the header in this way for the defaultbackend. Because of this, if you inject Linkerd into your Nginx ingresscontroller’s pod, the default backend will not be usable.

    This uses emojivoto as an example, take a look atgetting started for a refresher on how to install it.

    1. apiVersion: extensions/v1beta1
    2. kind: Ingress
    3. metadata:
    4. name: web-ingress
    5. annotations:
    6. kubernetes.io/ingress.class: "traefik"
    7. ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
    8. spec:
    9. rules:
    10. - host: example.com
    11. paths:
    12. - backend:
    13. serviceName: web-svc
    14. servicePort: 80

    The important annotation here is:

    Traefik will add a l5d-dst-override header to instruct Linkerd what servicethe request is destined for. You’ll want to include both the Kubernetes serviceFQDN (web-svc.emojivoto.svc.cluster.local) and the destinationservicePort. Please see the Traefik website for more information.

    To test this, you’ll want to get the external IP address for your controller. Ifyou installed Traefik via helm, you can get that IP address by running:

    1. kubectl get svc --all-namespaces \
    2. -l app=traefik \
    3. -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'

    You can then use this IP with curl:

    1. curl -H "Host: example.com" http://external-ip

    NoteThis solution won’t work if you’re using Traefik’s service weights asLinkerd will always send requests to the service name in l5d-dst-override. Aworkaround is to use traefik.frontend.passHostHeader: "false" instead. Beaware that if you’re using TLS, the connection between Traefik and the backendservice will not be encrypted. There is an to track thesolution to this problem.

    This example is similar to Traefik, and also uses emojivoto as an example.Take a look at getting started for a refresher on how toinstall it.

    In addition to the custom headers found in the Traefik example, it shows how touse a and TLS with a Google-managed certificate.

    The sample ingress definition is:

    1. apiVersion: extensions/v1beta1
    2. kind: Ingress
    3. metadata:
    4. name: web-ingress
    5. namespace: emojivoto
    6. annotations:
    7. kubernetes.io/ingress.class: "gce"
    8. ingress.kubernetes.io/custom-request-headers: "l5d-dst-override: web-svc.emojivoto.svc.cluster.local:80"
    9. ingress.gcp.kubernetes.io/pre-shared-cert: "managed-cert-name"
    10. kubernetes.io/ingress.global-static-ip-name: "static-ip-name"
    11. spec:
    12. rules:
    13. - host: example.com
    14. http:
    15. paths:
    16. - backend:
    17. serviceName: web-svc
    18. servicePort: 80

    To use this example definition, substitute managed-cert-name andstatic-ip-name with the short names defined in your project (n.b. use the namefor the IP address, not the address itself).

    The managed certificate will take about 30-60 minutes to provision, but thestatus of the ingress should be healthy within a few minutes. Once the managedcertificate is provisioned, the ingress should be visible to the Internet.

    This uses emojivoto as an example, take a look at for a refresher on how to install it.

    Ambassador does not use Ingress resources, instead relying on Service. Thesample service definition is:

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. name: web-ambassador
    5. namespace: emojivoto
    6. annotations:
    7. getambassador.io/config: |
    8. ---
    9. apiVersion: ambassador/v1
    10. kind: Mapping
    11. name: web-ambassador-mapping
    12. service: http://web-svc.emojivoto.svc.cluster.local:80
    13. host: example.com
    14. prefix: /
    15. spec:
    16. selector:
    17. app: web-svc
    18. ports:
    19. port: 80
    20. targetPort: http

    The important annotation here is:

    1. add_linkerd_headers: true

    Ambassador will add a l5d-dst-override header to instruct Linkerd what servicethe request is destined for. This will contain both the Kubernetes serviceFQDN (web-svc.emojivoto.svc.cluster.local) and the destinationservicePort.

    To test this, you’ll want to get the external IP address for your controller. Ifyou installed Ambassador via helm, you can get that IP address by running:

    NoteIf you’ve installed the admin interface, this will return two IPs, one of whichwill be <none>. Just ignore that one and use the actual IP address.

    You can then use this IP with curl:

    1. curl -H "Host: example.com" http://external-ip

    This uses books as an example, take a look atDemo: Books for instructions on how to run it.

    If you installed Gloo using the Gateway method (gloo install gateway), thenyou’ll need a VirtualService to be able to route traffic to your Booksapplication.

    To use Gloo with Linkerd, you can choose one of two options.

    As of Gloo v0.13.20, Gloo has native integration with Linkerd, so that therequired Linkerd headers are added automatically.

    Assuming you installed gloo to the default location, you can enable the nativeintegration by running:

    1. kubectl patch settings -n gloo-system default \
    2. -p '{"spec":{"linkerd":true}}' --type=merge

    Gloo will now automatically add the l5d-dst-override header to everykubernetes upstream.

    Now simply add a route to the books app upstream:

    1. glooctl add route --path-prefix=/ --dest-name booksapp-webapp-7000

    As explained in the beginning of this document, you’ll need to instruct Gloo toadd a header which will allow Linkerd to identify where to send traffic to.

    1. apiVersion: gateway.solo.io/v1
    2. kind: VirtualService
    3. metadata:
    4. name: books
    5. namespace: gloo-system
    6. spec:
    7. virtualHost:
    8. domains:
    9. - '*'
    10. name: gloo-system.books
    11. routes:
    12. - matcher:
    13. prefix: /
    14. routeAction:
    15. single:
    16. upstream:
    17. name: booksapp-webapp-7000
    18. namespace: gloo-system
    19. routePlugins:
    20. transformations:
    21. requestTransformation:
    22. transformationTemplate:
    23. headers:
    24. l5d-dst-override:
    25. text: webapp.booksapp.svc.cluster.local:7000
    26. passthrough: {}

    The important annotation here is:

    1. routePlugins:
    2. transformations:
    3. requestTransformation:
    4. transformationTemplate:
    5. headers:
    6. l5d-dst-override:
    7. text: webapp.booksapp.svc.cluster.local:7000
    8. passthrough: {}

    Using the content transformation engine built-in in Gloo, you can instruct it toadd the needed l5d-dst-override header which in the example above is pointingto the service’s FDQN and port: webapp.booksapp.svc.cluster.local:7000

    To easily test this you can get the URL of the Gloo proxy by running:

    1. http://192.168.99.132:30969

    For the example VirtualService above, which listens to any domain and path,accessing the proxy URL () in your browsershould open the Books application.