Linkerd Cheat Sheet
Overview
Linkerd is an ultralight, security-first service mesh for Kubernetes that adds observability, reliability, and security to applications without requiring code changes. It uses a lightweight Rust-based proxy (linkerd2-proxy) as a sidecar that handles all TCP traffic in and out of each pod, providing automatic mTLS, latency-aware load balancing, and fine-grained traffic metrics.
Linkerd is a CNCF graduated project known for its simplicity, minimal resource footprint, and operational ease compared to heavier service meshes. It provides zero-config mutual TLS, golden metrics (success rate, latency, throughput), traffic splitting for canary deployments, retries, timeouts, and multi-cluster communication.
Installation
CLI Installation
# Install Linkerd CLI
curl -fsL https://run.linkerd.io/install | sh
# Add to PATH
export PATH=$HOME/.linkerd2/bin:$PATH
# Verify CLI
linkerd version
# macOS alternative
brew install linkerd
Install on Kubernetes
# Pre-flight check
linkerd check --pre
# Install CRDs
linkerd install --crds | kubectl apply -f -
# Install control plane
linkerd install | kubectl apply -f -
# Verify installation
linkerd check
# Install Viz extension (dashboard + metrics)
linkerd viz install | kubectl apply -f -
# Verify viz
linkerd viz check
# Open dashboard
linkerd viz dashboard
Install with Helm
helm repo add linkerd https://helm.linkerd.io/stable
helm repo update
# Install CRDs
helm install linkerd-crds linkerd/linkerd-crds \
--namespace linkerd --create-namespace
# Generate trust anchor and issuer certificates
step certificate create root.linkerd.cluster.local ca.crt ca.key --profile root-ca --no-password --insecure
step certificate create identity.linkerd.cluster.local issuer.crt issuer.key --profile intermediate-ca --not-after 8760h --no-password --insecure --ca ca.crt --ca-key ca.key
# Install control plane
helm install linkerd-control-plane linkerd/linkerd-control-plane \
--namespace linkerd \
--set identityTrustAnchorsPEM="$(cat ca.crt)" \
--set identity.issuer.tls.crtPEM="$(cat issuer.crt)" \
--set identity.issuer.tls.keyPEM="$(cat issuer.key)"
# Install Viz
helm install linkerd-viz linkerd/linkerd-viz \
--namespace linkerd-viz --create-namespace
Injecting the Sidecar Proxy
# Inject into a deployment
kubectl get deploy my-app -o yaml | linkerd inject - | kubectl apply -f -
# Inject entire namespace
kubectl annotate namespace my-namespace linkerd.io/inject=enabled
# Inject during deployment
cat deployment.yaml | linkerd inject - | kubectl apply -f -
# Verify injection
linkerd check --proxy -n my-namespace
# Namespace annotation for auto-injection
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
annotations:
linkerd.io/inject: enabled
CLI Commands
| Command | Description |
|---|---|
linkerd check | Validate installation health |
linkerd viz dashboard | Open web dashboard |
linkerd viz stat deploy -n <ns> | Show deployment metrics |
linkerd viz top deploy/<name> | Real-time request table |
linkerd viz tap deploy/<name> | Live traffic stream |
linkerd viz routes deploy/<name> | Per-route metrics |
linkerd viz edges deploy -n <ns> | Show service connections |
linkerd inject <file> | Add sidecar proxy to manifests |
linkerd uninject <file> | Remove sidecar from manifests |
linkerd diagnostics proxy-metrics -n <ns> <pod> | Raw proxy metrics |
Observability
Golden Metrics
# Deployment stats (success rate, RPS, latency)
linkerd viz stat deploy -n my-namespace
# Per-route metrics
linkerd viz routes deploy/my-app -n my-namespace
# Live traffic tap
linkerd viz tap deploy/my-app -n my-namespace
# Top requests in real-time
linkerd viz top deploy/my-app -n my-namespace
# Service-to-service edges
linkerd viz edges deploy -n my-namespace
Prometheus Metrics
# Linkerd proxy exposes metrics at :4191/metrics on each pod
# Key metrics:
# request_total — total request count by status/direction
# response_latency_ms — response latency histogram
# tcp_open_total — open TCP connections
# tcp_open_connections — current open connections
# tcp_read_bytes_total — bytes received
# tcp_write_bytes_total — bytes sent
Traffic Management
Traffic Splitting (Canary)
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
name: my-app-canary
namespace: my-namespace
spec:
service: my-app
backends:
- service: my-app-stable
weight: 900
- service: my-app-canary
weight: 100
Service Profiles (Retries, Timeouts, Routes)
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: my-api.my-namespace.svc.cluster.local
namespace: my-namespace
spec:
routes:
- name: GET /api/users
condition:
method: GET
pathRegex: /api/users
responseClasses:
- condition:
status:
min: 500
max: 599
isFailure: true
isRetryable: true
- name: POST /api/orders
condition:
method: POST
pathRegex: /api/orders
timeout: 10s
retryBudget:
retryRatio: 0.2
minRetriesPerSecond: 10
ttl: 10s
# Generate service profile from OpenAPI spec
linkerd viz profile --open-api swagger.json my-api -n my-namespace | kubectl apply -f -
# Generate from live traffic
linkerd viz profile --tap deploy/my-api --tap-duration 30s my-api -n my-namespace
mTLS (Mutual TLS)
# Check mTLS status
linkerd viz edges deploy -n my-namespace
# Verify TLS on live traffic
linkerd viz tap deploy/my-app -n my-namespace --to deploy/my-backend | grep tls=true
# Check identity certificates
linkerd identity -n my-namespace
# Skip outbound mTLS for external services
apiVersion: v1
kind: Pod
metadata:
annotations:
config.linkerd.io/skip-outbound-ports: "3306,6379"
Configuration
Proxy Configuration (Annotations)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
# Resource limits
config.linkerd.io/proxy-cpu-request: "100m"
config.linkerd.io/proxy-memory-request: "64Mi"
config.linkerd.io/proxy-cpu-limit: "500m"
config.linkerd.io/proxy-memory-limit: "128Mi"
# Timeouts
config.linkerd.io/proxy-outbound-connect-timeout: "5000ms"
# Skip ports
config.linkerd.io/skip-inbound-ports: "4222"
config.linkerd.io/skip-outbound-ports: "3306"
# Opaque ports (no protocol detection)
config.linkerd.io/opaque-ports: "3306,6379,27017"
Advanced Usage
Multi-Cluster
# Install multi-cluster extension
linkerd multicluster install | kubectl apply -f -
# Link clusters
linkerd multicluster link --cluster-name target-cluster | kubectl apply -f -
# Check gateway
linkerd multicluster gateways
# Export a service
kubectl label svc/my-api mirror.linkerd.io/exported=true
Authorization Policies
apiVersion: policy.linkerd.io/v1beta3
kind: Server
metadata:
name: my-api
namespace: my-namespace
spec:
podSelector:
matchLabels:
app: my-api
port: 8080
proxyProtocol: HTTP/2
---
apiVersion: policy.linkerd.io/v1alpha1
kind: AuthorizationPolicy
metadata:
name: allow-frontend
namespace: my-namespace
spec:
targetRef:
group: policy.linkerd.io
kind: Server
name: my-api
requiredAuthenticationRefs:
- name: frontend-identity
kind: MeshTLSAuthentication
group: policy.linkerd.io
Troubleshooting
| Issue | Solution |
|---|---|
linkerd check fails | Review specific check failures; ensure CRDs and control plane are healthy |
| Sidecar not injected | Verify namespace annotation; check linkerd.io/inject is enabled |
| High latency after mesh | Check proxy resource limits; increase CPU/memory for proxy |
| mTLS not established | Verify both pods have sidecars; check identity certificates |
| Traffic split not working | Verify backend services exist; check TrafficSplit resource status |
| Dashboard shows no data | Verify Viz extension is installed; check Prometheus connectivity |
| Proxy crash loop | Check resource limits; review proxy logs with kubectl logs -c linkerd-proxy |
| Skip port not working | Verify annotation is on pod template, not deployment metadata |