Running Windows containers on Google Cloud (Part 2)

1. Overview

In the first part of the lab, you deployed a Windows container app to Google Compute Engine (GCE). This second part of the lab builds on the first part and you deploy the same app to Google Kubernetes Engine (GKE) for added resiliency and scalability.

What you'll learn

  • Push a Windows container to Google Container Registry
  • Create a Kubernetes cluster with Windows nodes on GKE
  • Run Windows container as a pod in GKE
  • Expose the Windows container behind a Kubernetes service

What you'll need

  • A Google Cloud Platform project.
  • A Browser, such Chrome or Firefox.

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with Google Cloud Platform?

Novice Intermediate Proficient

2. Setup and Requirements

For this codelab, you need a Google Cloud Platform project to interact with PowerShell. If you have an existing project, you can either use that or you can create a new project using the following steps.

Self-paced environment setup

If you don't already have a Google Account (Gmail or GSuite), you must create one. Sign-in to Google Cloud Platform Console ( and create a new project:



Remember the project ID, a unique name across all Google Cloud Platform projects. It will be referred to later in this codelab as PROJECT_ID.

Next, you'll need to enable billing in Google Cloud Platform Console in order to use Google Cloud Platform resources like Google Cloud Datastore and Cloud Storage.

New users of Google Cloud Platform are eligible for a $300 free trial. Running through this codelab shouldn't cost you more than a few dollars, but it could be more if you decide to use more resources or if you leave them running (see the "cleanup" section at the end of this document).

3. RDP into the Windows VM

Log into the Windows VM that you already created in the first part of the lab. You can simply click on the RDP button of the VM (or use your own RDP client if you like):


Once inside the VM, open a command prompt in admin mode. In the command prompt, you can see the Windows container image: iis-site-windows

C:\>docker images
REPOSITORY                                 TAG                       latest   windowsservercore-ltsc2019       ltsc2019

In the next step, we will push this image to Google Container Registry (GCR).

4. Push container image to GCR

We need to host the Windows container image in a public image repository before we can use it in other part of Google Cloud. Google Container Registry (GCR) is a good place for container images.

To push a container image from a Windows VM to GCR, we need to:

  1. Make sure that the Container Registry API is enabled in your project.
  2. Configure Docker to point to GCR.

Make sure the Container Registry API is enabled:

C:>gcloud services enable

Configure Docker to point to GCR:

C:>gcloud auth configure-docker
Do you want to continue (Y/n)?  Y

Docker configuration file updated.

Now, you can push the image to GCR (replace dotnet-atamel with your project id):

C:>docker push
The push refers to repository []
4d8626c6a788: Pushed
8bd5cd9c33e0: Pushed
df246b0408a9: Pushed
fda45f6f282a: Pushed
f3f872f1087c: Pushed
7626b1fc1993: Pushed
fac2806747d6: Skipped foreign layer
c4d02418787d: Skipped foreign layer
latest: digest: sha256:2153656a3c4affefbe9973b79fe45cc35742c7495d6f4b1a689b5d9927dc92cb size: 2201

If you go to GCR section in Cloud Console, you can see the image:


5. Create a Kubernetes cluster with Windows nodes

Before creating a Kubernetes cluster, make sure the project id set to your project and a compute/zone is set the zone you want (replace your-project-id and ${ZONE} with your preferred zone):

gcloud config set project your-project-id
export ZONE=europe-west1-b
gcloud config set compute/zone ${ZONE}

Creating a Kubernetes cluster in GKE with Windows nodes happens in 2 steps:

  1. Create a GKE cluster with IP alias and 1 Linux node. At least 1 Linux node is needed before Windows nodes can be added to the cluster.
  2. Add a Windows node pool to the GKE cluster.

Create a GKE cluster. Replace CLUSTER_NAME with your preferred name for the cluster. Also replace CLUSTER_VERSION with version 1.16.8-gke.9 or higher:

export CLUSTER_NAME=your-cluster-name
export CLUSTER_VERSION=your-cluster-version
gcloud container clusters create ${CLUSTER_NAME} \
  --enable-ip-alias \
  --num-nodes=2 \

Once we have the basic GKE cluster, we can go ahead and add a Windows pool for Windows nodes to it:

gcloud container node-pools create windows-node-pool \
  --cluster=${CLUSTER_NAME} \
  --image-type=WINDOWS_LTSC \
  --no-enable-autoupgrade \

Notice that we're disabling automatic node upgrades. Windows container versions need to be compatible with the node OS version. To avoid unexpected workload disruption, it is recommended that users disable node autoupgrade for Windows node pools.

For Windows Server containers in GKE, you're already licensed for underlying Windows host VMs – containers need no additional licensing.

In the end, the GKE cluster is ready with 2 Linux nodes and 3 Windows nodes:


6. Verify cluster initialization

Before running our Windows container as a pod on GKE, make sure the cluster is initialized.

Authenticate kubectl with the GKE cluster by copying/pasting the gcloud command in the Connect button:


Alternatively, you can just run the following command:

gcloud container clusters get-credentials ${CLUSTER_NAME}

kubectl is now setup to manage our cluster.

Before using the cluster, wait for several seconds until is created. This webhook adds scheduling tolerations to Pods created with the windows (or windows) node selector to ensure they are allowed to run on Windows Server nodes. It also validates the Pod to ensure that it only uses features supported on Windows.

kubectl get mutatingwebhookconfigurations

NAME                                                 CREATED AT     2020-01-20T15:09:16Z

Now the cluster is ready for Windows containers.

7. Run Windows container as a pod in GKE

Let's create an iis-site-windows.yaml file to describe our Kubernetes deployment (replace ${PROJECT_ID} with your project id):

apiVersion: apps/v1
kind: Deployment
  name: iis-site-windows
    app: iis-site-windows
  replicas: 2
      app: iis-site-windows
        app: iis-site-windows
      nodeSelector: windows
      - name: iis-site-windows
        - containerPort: 80

Note that we're creating 2 pods with the image we pushed earlier to GCR. We're also making sure that the pods are scheduled onto Windows nodes with the nodeSelector tag.

Create the deployment:

kubectl apply -f iis-site-windows.yaml

deployment.apps/iis-site-windows created

After a few minutes, you should see the deployment created and pods running:

kubectl get deployment,pods

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/iis-site-windows   2/2     2            2           3m4s

NAME                                    READY   STATUS    RESTARTS   AGE
pod/iis-site-windows-5b6dfdf64b-k5b6r   1/1     Running   0          3m4s
pod/iis-site-windows-5b6dfdf64b-msr9s   1/1     Running   0          3m4s

8. Create a Kubernetes Service

To make pods accessible to the outside world, we need to create a Kubernetes service with LoadBalancer type:

kubectl expose deployment iis-site-windows --type="LoadBalancer"

service/iis-site-windows exposed

In a few minutes, you should see a new service with an external IP:

kubectl get service

NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
iis-site-windows   LoadBalancer  80:30035/TCP

And if we go to that external IP, we will see our app:


This is very similar to the previous lab where we deployed to GCE but the big difference is that Kubernetes is managing the pods. If something goes wrong with the pod or the node that the pod is running, Kubernetes will recreate and reschedule the pod for us. Great for resiliency.

Similarly, scaling pods is a single command in Kubernetes:

kubectl scale deployment iis-site-windows --replicas=4

deployment.extensions/iis-site-windows scaled
kubectl get pods

NAME                                READY   STATUS
iis-site-windows-5b6dfdf64b-2kn65   1/1     Running
iis-site-windows-5b6dfdf64b-8rvbm   1/1     Running
iis-site-windows-5b6dfdf64b-bq8dg   1/1     Running
iis-site-windows-5b6dfdf64b-zjr6c   1/1     Running

9. Cleanup

Once you're done testing, it's a good idea to delete the cluster.

First, delete the service and the deployment, which also deletes your external load balancer:

kubectl delete service,deployment iis-site-windows

service "iis-site-windows" deleted
deployment.extensions "iis-site-windows" deleted

Next, delete your cluster:

gcloud container clusters delete windows-cluster

10. Congratulations!

What we've covered

  • Push a Windows container to Google Container Registry
  • Create a Kubernetes cluster with Windows nodes on GKE
  • Run Windows container as a pod in GKE
  • Expose the Windows container behind a Kubernetes service

Next Steps