Linkerd can make external traffic visible to your services, but it requires careful configuration of your ingress controller.
Let’s see Linkerd in action with Nginx Ingress.
Imagine this scenario: you have a web service running in Kubernetes, exposed via Nginx Ingress. You want Linkerd to manage traffic to this service, injecting its sidecar, and providing observability.
apiVersion: v1
kind: Service
metadata:
name: my-app-service
namespace: default
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: my-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
Here, Nginx Ingress routes my-app.example.com/ to my-app-service on port 80.
Now, when you install Linkerd, you’ll typically inject the linkerd-proxy sidecar into your application pods. However, traffic coming from Nginx Ingress to your application pod won’t automatically go through the linkerd-proxy if the service is configured to point directly at the pod’s application port.
The key is to have Nginx Ingress target the linkerd-proxy’s HTTP port (usually 4140) instead of the application’s direct port. This is often achieved by creating a new Kubernetes Service that acts as the intermediary, pointing to the linkerd-proxy’s port.
apiVersion: v1
kind: Service
metadata:
name: my-app-service-k8s
namespace: default
spec:
ports:
- port: 80
targetPort: 4140 # Linkerd proxy's HTTP port
protocol: TCP
name: http
selector:
app: my-app
Then, you update your Nginx Ingress resource to point to this new my-app-service-k8s service:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service-k8s # Point to the new service
port:
number: 80
With this setup, Nginx Ingress sends traffic to port 80 of my-app-service-k8s. This service, in turn, directs that traffic to port 4140 on your application pods (where the linkerd-proxy is listening). The linkerd-proxy then processes the traffic, applies policies, collects metrics, and finally forwards it to the actual application on port 8080.
This allows Linkerd to fully observe and control traffic originating from outside the mesh, even when using a traditional ingress controller like Nginx.
The one thing most people don’t realize is that the linkerd-proxy injects itself into the pod and listens on a specific port (4140 for HTTP by default) for incoming traffic that it will then forward to the application’s original port (e.g., 8080). The ingress controller needs to be configured to send traffic to that proxy port, not directly to the application’s port within the pod. This means you often need an extra Kubernetes Service resource that selects the application pods but exposes the proxy’s port, and then have your ingress point to this new service.
The next step is to explore how to configure mTLS for this external traffic.