Linkerd setup
Linkerd is a service mesh that adds mutual TLS, request-level load balancing, and traffic metrics between meshed pods. A pod is meshed when it carries the linkerd.io/inject: enabled annotation — typically APISIX and the backends it routes to. Traffic to or from pods without the Linkerd proxy is not covered. It is not a hard requirement of any Domino Workspace chart — a cluster without a service mesh works too — but it is part of the validated reference setup.
Requires cert-manager and trust-manager. Linkerd's identity certificate is issued from the same internal cluster-ca ClusterIssuer used elsewhere, and trust-manager distributes that CA's trust roots to the control plane.
1. Create the namespace
The control plane's own namespace needs the linkerd.io/is-control-plane: "true" label before installing anything else — the trust bundle in the next step is distributed only to namespaces carrying it. Apply with kubectl apply -f -:
apiVersion: v1
kind: Namespace
metadata:
name: linkerd
labels:
linkerd.io/is-control-plane: "true"
2. Distribute the trust bundle
Apply with kubectl apply -f -:
apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
name: linkerd-identity-trust-roots
spec:
sources:
- secret:
name: cluster-ca-tls
key: tls.crt
target:
configMap:
key: ca-bundle.crt
namespaceSelector:
matchLabels:
linkerd.io/is-control-plane: "true"
3. Issue the identity certificate
Apply with kubectl apply -f -:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: linkerd-identity-issuer
namespace: linkerd
spec:
secretName: linkerd-identity-issuer
duration: 48h
renewBefore: 25h
issuerRef:
name: cluster-ca
kind: ClusterIssuer
commonName: identity.linkerd.cluster.local
dnsNames:
- identity.linkerd.cluster.local
isCA: true
privateKey:
algorithm: ECDSA
rotationPolicy: Always
usages:
- cert sign
- crl sign
- server auth
- client auth
4. Install the CRDs and control plane
helm repo add linkerd-edge https://helm.linkerd.io/edge
helm repo update
helm upgrade --install linkerd-crds linkerd-edge/linkerd-crds \
--namespace linkerd
helm upgrade --install linkerd-control-plane linkerd-edge/linkerd-control-plane \
--namespace linkerd \
--set identity.externalCA=true \
--set identity.serviceAccountTokenProjection=true \
--set identity.issuer.scheme=kubernetes.io/tls
For a highly available control plane, also set controllerReplicas: 3, highAvailability: true, enablePodAntiAffinity: true, and enablePodDisruptionBudget: true.
See the official installation guide for the full set of options.
5. Install linkerd-viz (dashboard)
Installs into the same linkerd namespace as the control plane:
helm upgrade --install linkerd-viz linkerd-edge/linkerd-viz \
--namespace linkerd
If kube-prometheus-stack is already installed, disable linkerd-viz's bundled Prometheus and point it at the existing one instead — create linkerd-viz-values.yaml and pass it with -f to the helm upgrade above:
prometheus:
enabled: false
prometheusUrl: http://kube-prometheus-stack-prometheus.<kube-prometheus-stack-namespace>:9090
6. Mesh workloads
Linkerd injects its proxy only into pods annotated with linkerd.io/inject: enabled, at pod creation time. Set the annotation either on a whole namespace, or per workload through the pod annotations value of that component's Helm chart:
kubectl annotate namespace <namespace> linkerd.io/inject=enabled
Pods that already exist are not injected retroactively — restart them afterwards:
kubectl rollout restart deployment,statefulset -n <namespace>
Exclude APISIX's client-facing ports from the proxy when meshing APISIX. Set them in the config.linkerd.io/skip-inbound-ports annotation — otherwise Linkerd replaces the client source IP with the pod's own IP, which breaks IP restrictions and PROXY protocol. Mark any TCP stream ports that stay in the mesh with config.linkerd.io/opaque-ports.
Optional: scrape proxy metrics with kube-prometheus-stack
Apply with kubectl apply -f -:
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: linkerd-proxy
namespace: linkerd
labels:
release: kube-prometheus-stack
spec:
namespaceSelector:
any: true
selector:
matchLabels:
linkerd.io/control-plane-ns: linkerd
podMetricsEndpoints:
- port: linkerd-admin
path: /metrics
Verify
kubectl get pods -n linkerd
All pods should be Running. For a more thorough check, run linkerd check — this requires the linkerd CLI, see the official installation guide.