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.
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.
If you don't already have a Google Account (Gmail or GSuite), you must create one. Sign-in to Google Cloud Platform Console (console.cloud.google.com) 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
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).
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:
C:\>docker images REPOSITORY TAG gcr.io/dotnet-atamel/iis-site-windows latest mcr.microsoft.com/windows/servercore/iis windowsservercore-ltsc2019 mcr.microsoft.com/windows/servercore ltsc2019
In the next step, we will push this image to Google Container Registry (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:
Make sure the Container Registry API is enabled:
C:>gcloud services enable containerregistry.googleapis.com
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 gcr.io/dotnet-atamel/iis-site-windows The push refers to repository [gcr.io/dotnet-atamel/iis-site-windows] 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:
This step is necessary to access the EAP feature. Make sure you create the service account in your whitelisted project.
Inside Cloud Shell, run the following commands to create a service account and link to your gcloud command.
Create a service account. Make sure to replace
gcloud iam service-accounts create [SA-NAME] --display-name "[SA-DISPLAY-NAME]"
Download the service account key and store it in a json file.
gcloud iam service-accounts list gcloud iam service-accounts keys create [PATH-TO-KEY.json] --iam-account [SA-EMAIL]
Add IAM policy to bind the service account to the editor role:
gcloud projects add-iam-policy-binding [PROJECT-ID] --member "serviceAccount:[SA-EMAIL]" --role "roles/editor"
Active the service account for gcloud:
gcloud auth activate-service-account --key-file=[PATH-TO-KEY.json]
Now, you're ready to create a Kubernetes cluster with Windows nodes using gcloud.
Creating a Kubernetes cluster in GKE with Windows nodes happens in 2 steps:
Windows nodes are only available in the Rapid release channel with IP alias enabled and at least 1 Linux node is needed in the GKE cluster before Windows nodes can be added.
Inside Cloud Shell, Create a GKE cluster (replace
europe-west1-b with a zone of your choice):
gcloud container clusters create windows-cluster --cluster-version=1.14 --enable-ip-alias --num-nodes=1 --zone europe-west1-b
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-pool --cluster=windows-cluster --image-type=WINDOWS_SAC --no-enable-autoupgrade --machine-type=n1-standard-2 --num-nodes=1 --zone europe-west1-b
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 1 Linux node and 1 Windows node:
Before running our Windows container as a pod on GKE, authenticate
kubectl with the GKE cluster by copying/pasting the
gcloud command in the Connect button:
kubectl is now setup to manage our cluster.
Let's create an
iis-site-windows.yaml file to describe our Kubernetes deploymen (replace
dotnet-atamel with your project id):
apiVersion: apps/v1 kind: Deployment metadata: name: iis-site-windows labels: app: iis-site-windows spec: replicas: 2 selector: matchLabels: app: iis-site-windows template: metadata: labels: app: iis-site-windows spec: nodeSelector: kubernetes.io/os: windows containers: - name: iis-site-windows image: gcr.io/dotnet-atamel/iis-site-windows ports: - 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
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 10.107.11.34 184.108.40.206 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
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 --zone=europe-west1-b