diff --git a/Dockerfile b/Dockerfile
index aa6464e644..2c79af3489 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM golang:1.15.6 AS builder
+FROM golang:1.16 AS builder
WORKDIR /go/src/github.com/kubernetes-sigs/aws-ebs-csi-driver
COPY . .
RUN make
diff --git a/Dockerfile.windows b/Dockerfile.windows
new file mode 100644
index 0000000000..420096dd38
--- /dev/null
+++ b/Dockerfile.windows
@@ -0,0 +1,23 @@
+# Copyright 2019 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM --platform=$BUILDPLATFORM golang:1.16 AS builder
+WORKDIR /go/src/github.com/kubernetes-sigs/aws-ebs-csi-driver
+COPY . .
+RUN make bin/aws-ebs-csi-driver.exe
+
+FROM mcr.microsoft.com/windows/servercore:1809
+COPY --from=builder /go/src/github.com/kubernetes-sigs/aws-ebs-csi-driver/bin/aws-ebs-csi-driver.exe /aws-ebs-csi-driver.exe
+
+ENTRYPOINT ["/aws-ebs-csi-driver.exe"]
diff --git a/Makefile b/Makefile
index 91781e98c7..743eabc945 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,10 @@ GOBIN=$(shell pwd)/bin
bin/aws-ebs-csi-driver: | bin
CGO_ENABLED=0 GOOS=linux go build -mod=vendor -ldflags ${LDFLAGS} -o bin/aws-ebs-csi-driver ./cmd/
+.PHONY: bin/aws-ebs-csi-driver.exe
+bin/aws-ebs-csi-driver.exe: | bin
+ CGO_ENABLED=0 GOOS=windows go build -mod=vendor -ldflags ${LDFLAGS} -o bin/aws-ebs-csi-driver.exe ./cmd/
+
bin /tmp/helm /tmp/kubeval:
@mkdir -p $@
diff --git a/charts/aws-ebs-csi-driver/templates/node-windows.yaml b/charts/aws-ebs-csi-driver/templates/node-windows.yaml
new file mode 100644
index 0000000000..b6cde40d7b
--- /dev/null
+++ b/charts/aws-ebs-csi-driver/templates/node-windows.yaml
@@ -0,0 +1,185 @@
+kind: DaemonSet
+apiVersion: apps/v1
+metadata:
+ name: ebs-csi-node-windows
+ namespace: kube-system
+ labels:
+ {{- include "aws-ebs-csi-driver.labels" . | nindent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app: ebs-csi-node
+ {{- include "aws-ebs-csi-driver.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ labels:
+ app: ebs-csi-node
+ {{- include "aws-ebs-csi-driver.labels" . | nindent 8 }}
+ {{- if .Values.node.podAnnotations }}
+ annotations: {{ toYaml .Values.node.podAnnotations | nindent 8 }}
+ {{- end }}
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: eks.amazonaws.com/compute-type
+ operator: NotIn
+ values:
+ - fargate
+ nodeSelector:
+ kubernetes.io/os: windows
+ {{- with .Values.node.nodeSelector }}
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ serviceAccountName: {{ .Values.serviceAccount.node.name }}
+ priorityClassName: {{ .Values.node.priorityClassName | default "system-cluster-critical" }}
+ tolerations:
+ {{- if .Values.node.tolerateAllTaints }}
+ - operator: Exists
+ {{- else }}
+ - key: CriticalAddonsOnly
+ operator: Exists
+ - operator: Exists
+ effect: NoExecute
+ tolerationSeconds: 300
+ {{- end }}
+ {{- with .Values.node.tolerations }}
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ containers:
+ - name: ebs-plugin
+ image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+ args:
+ - node
+ - --endpoint=$(CSI_ENDPOINT)
+ {{- if .Values.volumeAttachLimit }}
+ - --volume-attach-limit={{ .Values.volumeAttachLimit }}
+ {{- end }}
+ - --logtostderr
+ - --v=5
+ env:
+ - name: CSI_ENDPOINT
+ value: unix:/csi/csi.sock
+{{- if .Values.proxy.http_proxy }}
+ - name: HTTP_PROXY
+ value: {{ .Values.proxy.http_proxy | quote }}
+ - name: HTTPS_PROXY
+ value: {{ .Values.proxy.http_proxy | quote }}
+ - name: NO_PROXY
+ value: {{ .Values.proxy.no_proxy | quote }}
+{{- end }}
+ volumeMounts:
+ - name: kubelet-dir
+ mountPath: C:\var\lib\kubelet
+ mountPropagation: "None"
+ - name: plugin-dir
+ mountPath: C:\csi
+ - name: csi-proxy-disk-pipe
+ mountPath: \\.\pipe\csi-proxy-disk-v1beta2
+ - name: csi-proxy-volume-pipe
+ mountPath: \\.\pipe\csi-proxy-volume-v1beta2
+ - name: csi-proxy-filesystem-pipe
+ mountPath: \\.\pipe\csi-proxy-filesystem-v1beta1
+ ports:
+ - name: healthz
+ containerPort: 9808
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: healthz
+ initialDelaySeconds: 10
+ timeoutSeconds: 3
+ periodSeconds: 10
+ failureThreshold: 5
+ {{- if .Values.node.resources }}
+ {{- with .Values.node.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- else }}
+ {{- with .Values.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- end }}
+ - name: node-driver-registrar
+ image: {{ printf "%s:%s" .Values.sidecars.nodeDriverRegistrarImage.repository .Values.sidecars.nodeDriverRegistrarImage.tag }}
+ args:
+ - --csi-address=$(ADDRESS)
+ - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)
+ - --v=5
+ env:
+ - name: ADDRESS
+ value: unix:/csi/csi.sock
+ - name: DRIVER_REG_SOCK_PATH
+ value: C:\var\lib\kubelet\plugins\ebs.csi.aws.com\csi.sock
+{{- if .Values.proxy.http_proxy }}
+ - name: HTTP_PROXY
+ value: {{ .Values.proxy.http_proxy | quote }}
+ - name: HTTPS_PROXY
+ value: {{ .Values.proxy.http_proxy | quote }}
+ - name: NO_PROXY
+ value: {{ .Values.proxy.no_proxy | quote }}
+{{- end }}
+ volumeMounts:
+ - name: plugin-dir
+ mountPath: C:\csi
+ - name: registration-dir
+ mountPath: C:\registration
+ {{- if .Values.node.resources }}
+ {{- with .Values.node.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- else }}
+ {{- with .Values.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- end }}
+ - name: liveness-probe
+ image: {{ printf "%s:%s" .Values.sidecars.livenessProbeImage.repository .Values.sidecars.livenessProbeImage.tag }}
+ args:
+ - --csi-address=unix:/csi/csi.sock
+ volumeMounts:
+ - name: plugin-dir
+ mountPath: C:\csi
+ {{- if .Values.node.resources }}
+ {{- with .Values.node.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- else }}
+ {{- with .Values.resources }}
+ resources: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- range .Values.imagePullSecrets }}
+ - name: {{ . }}
+ {{- end }}
+ {{- end }}
+ volumes:
+ - name: kubelet-dir
+ hostPath:
+ path: C:\var\lib\kubelet
+ type: Directory
+ - name: plugin-dir
+ hostPath:
+ path: C:\var\lib\kubelet\plugins\ebs.csi.aws.com
+ type: DirectoryOrCreate
+ - name: registration-dir
+ hostPath:
+ path: C:\var\lib\kubelet\plugins_registry
+ type: Directory
+ - name: csi-proxy-disk-pipe
+ hostPath:
+ path: \\.\pipe\csi-proxy-disk-v1beta2
+ type: ""
+ - name: csi-proxy-volume-pipe
+ hostPath:
+ path: \\.\pipe\csi-proxy-volume-v1beta2
+ type: ""
+ - name: csi-proxy-filesystem-pipe
+ hostPath:
+ path: \\.\pipe\csi-proxy-filesystem-v1beta1
+ type: ""
diff --git a/examples/kubernetes/windows/README.md b/examples/kubernetes/windows/README.md
new file mode 100644
index 0000000000..06f0083ace
--- /dev/null
+++ b/examples/kubernetes/windows/README.md
@@ -0,0 +1,74 @@
+## Windows
+
+**This example requires pre-release versions of csi-proxy and the driver that do not exist yet. It is intended for developers only for now. Only basic read/write (mount/unmount and attach/detach) functionality has been tested, other features like resize don't work yet.**
+
+This example shows how to create a EBS volume and consume it from a Windows container dynamically.
+
+
+## Prerequisites
+
+1. A 1.18+ Windows node. Windows support has only been tested on 1.18 EKS Windows nodes. https://docs.aws.amazon.com/eks/latest/userguide/windows-support.html
+2. [csi-proxy](https://github.com/kubernetes-csi/csi-proxy) built from commit c201c0afb8f12ceac6d5d778270c2702ca563889 or newer installed on the Windows node.
+3. The driver vX.Y.Z+ (TODO: no such version exists yet) Node plugin (DaemonSet) installed on the Windows node.
+4. The driver vX.Y.Z+ (TODO: no such version exists yet) Controller plugin (Deployment) installed on a Linux node. The Controller hasn't been tested on Windows.
+
+## Usage
+
+1. Create a sample app along with the StorageClass and the PersistentVolumeClaim:
+```
+kubectl apply -f specs/
+```
+
+2. Validate the volume was created and `volumeHandle` contains an EBS volumeID:
+```
+kubectl describe pv
+```
+
+3. Validate the pod can write data to the volume:
+```
+kubectl exec -it windows-server-iis-7c5fc8f6c5-t5mk9 -- powershell
+
+PS C:\> New-Item -Path data -Name "testfile1.txt" -ItemType "file" -Value "This
+is a text string."
+
+
+ Directory: C:\data
+
+
+Mode LastWriteTime Length Name
+---- ------------- ------ ----
+-a---- 4/7/2021 12:31 AM 22 testfile1.txt
+```
+
+4. Validate a different pod can read data from the volume:
+```
+kubectl delete po windows-server-iis-7c5fc8f6c5-t5mk9
+
+kubectl exec -it windows-server-iis-7c5fc8f6c5-j44qv -- powershell
+
+PS C:\> ls data
+
+
+ Directory: C:\data
+
+
+Mode LastWriteTime Length Name
+---- ------------- ------ ----
+-a---- 4/7/2021 12:31 AM 22 testfile1.txt
+```
+
+5. OPTIONAL: In case you want to run some e2e tests with Windows pods, make sure to cordon Linux nodes for the duration of the test and modify the vpc-admission-webhook so that the Pods created as part of the tests get scheduled to the Windows nodes.
+```
+kubectl cordon -l kubernetes.io/os=linux
+# edit the webhook such that OSLabelSelectorOverride=all, otherwise the webhook
+# won't mutate Pods created by the test and they won't run
+kubectl edit deployment -n kube-system vpc-admission-webhook
+deployment.apps/vpc-admission-webhook edited
+ginkgo -nodes=1 -v --focus="External.Storage.*default.fs.*should.store.data" ./tests/e2e-kubernetes/ -- -kubeconfig=$KUBECONFIG -gce-zone=us-west-2a -node-os-distro=windows
+```
+
+6. Cleanup resources:
+```
+kubectl delete -f specs/
+kubectl uncordon -l kubernetes.io/os=linux
+```
diff --git a/examples/kubernetes/windows/specs/windows.yaml b/examples/kubernetes/windows/specs/windows.yaml
new file mode 100644
index 0000000000..566e1b47b8
--- /dev/null
+++ b/examples/kubernetes/windows/specs/windows.yaml
@@ -0,0 +1,59 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: windows-server-iis
+spec:
+ selector:
+ matchLabels:
+ app: windows-server-iis
+ tier: backend
+ track: stable
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: windows-server-iis
+ tier: backend
+ track: stable
+ spec:
+ containers:
+ - name: windows-server-iis
+ image: mcr.microsoft.com/windows/servercore:1809
+ ports:
+ - name: http
+ containerPort: 80
+ imagePullPolicy: IfNotPresent
+ command:
+ - powershell.exe
+ - -command
+ - "Add-WindowsFeature Web-Server; Invoke-WebRequest -UseBasicParsing -Uri 'https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.6/ServiceMonitor.exe' -OutFile 'C:\\ServiceMonitor.exe'; echo '