Skip to content

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.