What's on this page
Meshing Windows workloads
In this guide, we’ll walk you through an example of meshing a Windows workload with Buoyant Enterprise for Linkerd.
Prerequisites
- A hybrid Kubernetes cluster with both Linux and Windows nodes
- Buoyant Enterprise for Linkerd installed on the cluster
Step 1: Install the Linkerd Windows CNI Plugin
In order to mesh workloads that run on your Windows nodes, you need to install the Linkerd Windows CNI plugin on those nodes.
To install the CNI plugin, you can use Helm:
helm upgrade -i -n windows-cni --create-namespace \
linkerd-enterprise-windows-cni \
--wait \
oci://ghcr.io/buoyantio/charts/linkerd-enterprise-windows-cni \
--devel
This will deploy a DaemonSet on all your Windows nodes. The DaemonSet installs the CNI plugin on these nodes.
Step 2: Provision a Windows based server workload
Now you are ready to provision a Windows server workload that is meshed. First let’s create a namespace:
kubectl create ns win-test
Next, let’s create a service for the workload:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: win-webserver
namespace: win-test
---
kind: Service
apiVersion: v1
metadata:
name: win-webserver
namespace: win-test
spec:
selector:
app: win-webserver
ports:
- name: http
port: 80
EOF
Finally, the Windows application deployment:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: win-webserver
name: win-webserver
namespace: win-test
spec:
replicas: 1
selector:
matchLabels:
app: win-webserver
template:
metadata:
labels:
app: win-webserver
annotations:
linkerd.io/inject: enabled
config.linkerd.io/proxy-image: ghcr.io/buoyantio/proxy-win
name: win-webserver
spec:
containers:
- name: windowswebserver
image: mcr.microsoft.com/windows-cssc/python:3.9-nanoserver-ltsc2022
command:
- python
- -m
- http.server
- "80"
imagePullPolicy: IfNotPresent
serviceAccountName: win-webserver
nodeSelector:
kubernetes.io/os: windows
EOF
Make sure your workload is up and running:
kubectl rollout status --namespace=win-test deployment win-webserver
Note that the nodeSelector of the workload is set to
kubernetes.io/os: windows. The Linkerd injector uses this information to
determine that this workload needs to be injected with Windows-specific
configuration. In case your nodes use a different labeling scheme, you can
explicitly instruct the injector to treat this workload as a Windows one by
setting the linkerd.io/inject annotation to windows.
Note also that we are setting the config.linkerd.io/proxy-image annotation to
point to the Windows-specific proxy image, which is
ghcr.io/buoyantio/proxy-win.
Step 3: Provision a Linux client workload
Now, let’s provision a workload that we can use as a client that can communicate with the Windows server:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: linux-client
namespace: win-test
annotations:
linkerd.io/inject: enabled
labels:
app: linux-client
spec:
containers:
- name: client
image: curlimages/curl
command:
- "sh"
- "-c"
- >
while true; do
sleep 3600;
done
nodeSelector:
kubernetes.io/os: linux
EOF
Wait for the client to start:
kubectl wait --namespace=win-test --for=condition=ready pod -l app=linux-client
Step 4: Exercise meshed traffic between client and server
Now you are ready to exercise some traffic between the client and the server:
kubectl exec -c client --stdin linux-client -n win-test -- curl -I -s http://win-webserver
You should see output similar to:
HTTP/1.0 200 OK
server: SimpleHTTP/0.6 Python/3.9.24
date: Wed, 29 Oct 2025 08:52:15 GMT
content-type: text/html; charset=utf-8
content-length: 676
Now you can observe metrics in the client proxy and convince yourself that traffic is TLS’d:
linkerd diagnostics proxy-metrics -n win-test pod/linux-client | grep request_total
You should see metrics that indicate outbound meshed communication with the windows web server:
request_total{
direction="outbound"
authority="win-webserver.win-test.svc.cluster.local"
target_addr="10.244.1.158:80"
target_ip="10.244.1.158"
target_port="80"
tls="true"
server_id="win-webserver.win-test.serviceaccount.identity.linkerd.cluster.local"
dst_control_plane_ns="linkerd"
dst_deployment="win-webserver"
dst_namespace="win-test"
dst_pod="win-webserver-5cc489cfd4-5fbzp"
dst_pod_template_hash="5cc489cfd4"
dst_service="win-webserver"
dst_serviceaccount="win-webserver"
dst_zone="0"
dst_zone_locality="local"
} 1f
Note that the tls label is set to true and the server_id label corresponds
to the expected TLS identity of the server.
Congratulations, you have meshed communication between a Linux and Windows workload!