
Linkerd is a lightweight, open-source service mesh for Kubernetes that provides observability, security, and traffic management features. It uses a sidecar proxy model where lightweight proxies handle pod-to-pod communication while a control plane manages configuration and routing.
This guide explains how to install Linkerd on a Vultr Kubernetes Engine (VKE) cluster. You will deploy a sample application, configure Ingress for external access, and implement traffic management features.
Prerequisites
Before you begin, you need to:
- Have a Vultr Kubernetes Engine (VKE) cluster.
- A domain name with an A record pointing to your cluster's load balancer IP address (such as
linkerd.example.com). - Have access to a Ubuntu-based server or local machine as your workstation for managing your VKE cluster and using Linkerd CLI.
- Install and Configure Kubectl to access your Kubernetes cluster.
- Install Helm on your workstation.
Install the Linkerd CLI
Install the Linkerd command-line interface on your workstation to manage your service mesh deployment.
Update the system package index.
console$ sudo apt update
Download and install the Linkerd CLI.
console$ curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install-edge | sh
Add Linkerd to your PATH.
console$ export PATH=$PATH:$HOME/.linkerd2/bin
Make the PATH change permanent.
console$ echo 'export PATH=$PATH:$HOME/.linkerd2/bin' >> ~/.bashrc $ source ~/.bashrc
Verify the CLI installation.
console$ linkerd version --client
Output:
Client version: edge-25.10.3The server version shows as unavailable because the control plane is not yet installed.
Validate the Kubernetes Cluster
Ensure your cluster meets Linkerd's requirements before installation.
Run pre-installation checks.
console$ linkerd check --pre
All checks should pass with
Status check results are √. If any checks fail, resolve the issues before proceeding.
Install Linkerd Control Plane
Deploy Linkerd's core components to your cluster.
Install the Gateway API CRDs.
console$ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
Install Linkerd CRDs.
console$ linkerd install --crds | kubectl apply -f -
Install the control plane.
console$ linkerd install | kubectl apply -f -
Verify the installation.
console$ linkerd check
Check control plane pods.
console$ kubectl get pods -n linkerd
Output:
NAME READY STATUS RESTARTS AGE linkerd-destination-7b4657cfd8-btqdv 4/4 Running 0 4m40s linkerd-identity-5584896d84-6pmdm 2/2 Running 0 4m40s linkerd-proxy-injector-995fcbf47-dv6qr 2/2 Running 0 4m40s
Install Linkerd Viz Extension
The viz extension provides observability features and the web dashboard.
Install the viz extension.
console$ linkerd viz install | kubectl apply -f -
Verify the viz installation.
console$ linkerd viz check
Expose Linkerd Dashboard
You can expose the Linkerd dashboard securely via Kubernetes Ingress. In this section, expose the Linkerd dashboard securely using TLS encryption.
Install Nginx Ingress Controller
Deploy Nginx Ingress Controller to handle external traffic routing.
Add the Nginx Ingress Helm repository.
console$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
Update Helm.
console$ helm repo update
Install Nginx Ingress Controller.
console$ helm install ingress-nginx ingress-nginx/ingress-nginx \ --create-namespace --namespace ingress-nginx
Wait for the LoadBalancer to get an external IP.
console$ kubectl get service -n ingress-nginx ingress-nginx-controller
Sample output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.99.177.190 192.0.20.11 80:31460/TCP,443:32364/TCP 3m51sNote the
EXTERNAL-IPaddress value. This is where you should point your domain's A record.Verify the Nginx Ingress controller pods are running.
console$ kubectl get pods -n ingress-nginx
Configure Dashboard Authentication
Create basic authentication credentials for securing dashboard access.
Install htpasswd utility.
console$ sudo apt install apache2-utils -y
Generate authentication credentials. Replace
adminwith your preferred username.console$ htpasswd -c auth admin
Enter a strong password when prompted.
Create a Kubernetes secret with the credentials.
console$ kubectl create secret generic web-ingress-auth \ --from-file=auth \ --namespace=linkerd-viz
Remove the local auth file.
console$ rm auth
Install cert-manager
Using cert-manager, you can secure your dashboard with HTTPS using Let's Encrypt TLS certificates.
Add the Jetstack repository to Helm.
console$ helm repo add jetstack https://charts.jetstack.io
Update Helm.
console$ helm repo update
Install cert-manager and all required CRDs in your Kubernetes cluster.
console$ helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \ --set crds.enabled=true
Check cert-manager resources and wait till they become ready.
console$ kubectl get all -n cert-manager
Create a ClusterIssuer for Let's Encrypt.
console$ nano letsencrypt-issuer.yaml
Add the following content. Replace
admin@example.comwith your email.yamlapiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginx
Save and close the file.
Apply the ClusterIssuer.
console$ kubectl apply -f letsencrypt-issuer.yaml
Create Ingress for Linkerd Dashboard
Create an Ingress resource to expose the Linkerd dashboard externally.
Update the
ingress-nginx-controllerConfigMap so the latest version of cert-manager can verify your domain. Without this change, a strict Nginx setting may block cert-manager’s automatic domain check, stopping it from issuing TLS certificates.console$ kubectl patch configmap ingress-nginx-controller -n ingress-nginx --patch '{"data":{"strict-validate-path-type":"false"}}'
Create an Ingress manifest file.
console$ nano linkerd-dashboard-ingress.yaml
Add the following content. Replace
linkerd.example.comwith your domain.yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress namespace: linkerd-viz annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/upstream-vhost: web.linkerd-viz.svc.cluster.local:8084 nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: web-ingress-auth nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required' nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" spec: ingressClassName: nginx tls: - hosts: - linkerd.example.com secretName: linkerd-dashboard-tls rules: - host: linkerd.example.com http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 8084
Save and close the file.
This Ingress routes external traffic from your domain to the Linkerd dashboard service running in the
linkerd-viznamespace. It enforces basic authentication, sets proxy timeouts, and ensures the request is sent to the correct backend service on port 8084.Apply the Ingress manifest.
console$ kubectl apply -f linkerd-dashboard-ingress.yaml
Verify the Ingress was created.
console$ kubectl get ingress -n linkerd-viz
Verify the TLS certificate creation.
console$ kubectl get certificate -n linkerd-viz
Wait until the certificate shows
READYasTrue.
Access the Dashboard
Access your secured Linkerd dashboard through the configured domain.
Open a web browser and navigate to your domain.
https://linkerd.example.comEnter the username and password you created earlier.
Explore the dashboard to view cluster metrics, service mesh topology, and traffic flow.
Deploy a Sample Application
Test Linkerd's features with the Emojivoto sample application.
Deploy the Emojivoto application.
console$ curl -sL https://run.linkerd.io/emojivoto.yml | kubectl apply -f -
Verify the deployment.
console$ kubectl get pods -n emojivoto
Add the application to the mesh.
console$ kubectl get -n emojivoto deploy -o yaml | linkerd inject - | kubectl apply -f -
View the meshed application in the dashboard or via CLI.
console$ linkerd viz -n emojivoto stat deploy
Configure Traffic Splitting
Implement canary deployments using traffic splitting.
Create a second version of the web deployment.
console$ kubectl get deploy web -n emojivoto -o yaml | \ sed 's/name: web/name: web-v2/' | \ kubectl apply -f -
This command copies the existing
webDeployment, renames the copy toweb-v2, and applies it to create a new Deployment.Create a service for the new version.
console$ cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: web-v2 namespace: emojivoto spec: ports: - name: http port: 80 targetPort: 80 selector: app: web version: v2 EOF
This Service exposes the
web-v2pods on port80inside theemojivotonamespace. It routes traffic to pods labeledapp: web,version: v2.Add the new deployment to the mesh.
console$ kubectl get deploy web-v2 -n emojivoto -o yaml | \ linkerd inject - | \ kubectl apply -f -
This command injects the Linkerd proxy into the
web-v2Deployment and updates the cluster so new pods run with the proxy.Create a traffic split manifest.
console$ nano traffic-split.yaml
Add the following content to the file:
yamlapiVersion: policy.linkerd.io/v1beta2 kind: HTTPRoute metadata: name: web-route namespace: emojivoto spec: parentRefs: - name: web-svc kind: Service group: core port: 80 rules: - backendRefs: - name: web-svc port: 80 weight: 80 - name: web-v2 port: 80 weight: 20
Save and close the file.
This TrafficSplit sends 80% of requests to the original
web-svcservice and 20% to the newweb-v2service.Apply the traffic split.
console$ kubectl apply -f traffic-split.yaml
Verify traffic distribution in the dashboard or via CLI.
console$ linkerd viz -n emojivoto stat --from deploy/vote-bot deploy
Conclusion
You have successfully installed Linkerd on a VKE cluster, exposed the dashboard securely through Nginx Ingress with TLS encryption and authentication, and deployed a sample application with traffic splitting capabilities. For more information about advanced Linkerd features, visit the official Linkerd documentation.