Cloud Build Series #1: Automatic deployment to Google Kubernetes Engine with Cloud Build

Publish date: 2020-01-27
Tags: gcp, kubernetes, k8s, gke, cloudbuild, azure, aws, aks

By twahyono

Prerequisites

Goal

You want to make automatic deployment whenever the developer push some new commit in the application source code repository.

Creating New Kubernetes Cluster

Create new cluster with f1-micro machine type. For this trial purpose we will use preemptible machine to keep the cost down. Preemptible means we are using spare capacity available from GCP to create node. This node will be restart by Google every 24 hours.

Create new project in GCP and configure default zone

$ gcloud projects create atambua
$ gcloud config set project atambua
$ gcloud config set compute/zone asia-southeast1-a
$ gcloud config list
[compute]
region = asia-southeast1
zone = asia-southeast1-a
[core]
account = your@email.co.id
disable_usage_reporting = True
project = atambua

Check available machine type in your zone

$ gcloud compute machine-types list --filter=zone=asia-southeast1-a

Create new Kubernetes cluster

$ gcloud container clusters create my-cluster --machine-type=f1-micro --preemptible --zone=asia-southeast1-a

Verify that nodes are being created.

$ kubectl get nodes
NAME                                        STATUS   ROLES    AGE   VERSION
gke-my-cluster-default-pool-8d0c1fcb-gc08   Ready    <none>   19s   v1.13.11-gke.14
gke-my-cluster-default-pool-8d0c1fcb-hjjh   Ready    <none>   18s   v1.13.11-gke.14
gke-my-cluster-default-pool-8d0c1fcb-n9b8   Ready    <none>   20s   v1.13.11-gke.14

Creating Google Cloud Build trigger for automatic deployment

Connect repository and create trigger
Connect repo trigger
Edit trigger

Preparing cloudbuild.yaml file

Make sure you already set all default config to proper value to ensure Google Cloud Build step will not failed. Set your cluster to [cluster-name]

$ gcloud config set container/cluster my-cluster

Create cloudbuild.yaml file and put in the the root directory of your project. Cloud Build will running code inside this file whenever you push new commit in the repo and automatically deploy application in the Kubernetes Engine.

cloudbuild.yaml file content:

steps:
- id: 'build image'
  name: 'gcr.io/cloud-builders/docker'
  args: 
    - 'build'
    - '-t'
    - 'gcr.io/${PROJECT_ID}/myreact-app:$SHORT_SHA'
    - '.'
    - '-f'
    - './Dockerfile'
  timeout: 1000s
- id: 'push to container registry'
  name: 'gcr.io/cloud-builders/docker'
  args: 
    - 'push'
    - 'gcr.io/${PROJECT_ID}/myreact-app:$SHORT_SHA'
- id: 'deploy to gke'
  name: 'gcr.io/cloud-builders/gcloud'
  env:
    - 'CLOUDSDK_COMPUTE_ZONE=${_CLOUDSDK_COMPUTE_ZONE}'
    - 'CLOUDSDK_CONTAINER_CLUSTER=${_CLOUDSDK_CONTAINER_CLUSTER}'
    - 'KUBECONFIG=/.kube/config'
  entrypoint: 'bash'
  args:
    - '-c'
    - |
          
          gcloud container clusters get-credentials your-k8s-cluster-name --project your-project-id --zone your-compute-zone
          sed -i 's|gcr.io/project-id/myreact-app|gcr.io/$PROJECT_ID/myreact-app:$SHORT_SHA|' ./deployment.yaml
          kubectl apply -f ./deployment.yaml
timeout: 2000s

Create your Kubernetes deployment

This file will be apply in the cloud builder step id “deploy to gke”. File deployment.yaml will contains Kubernetes instruction to deploy container image to Kubernetes cluster:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: myreact-app
  name: myreact-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myreact-app
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myreact-app
    spec:
      containers:
      - image: gcr.io/project-id/myreact-app
        imagePullPolicy: Always
        name: myreact-app

Evaluate the trigger result in Cloud Build history

Check in the cloud build history if the trigger was run successfully into completion.

Verify that pods are running in the cluster

$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
myreact-app-d5f85b778-k76dz   1/1     Running   0          26m

Exposing your deployment/pods

Before you can access the pods from outside you need to create Kubernetes service to expose the pods

$ kubectl expose deployment myreact-app --port=80 --target-port=80 --type=LoadBalancer

Verify service creation

$ kubectl get svc
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
kubernetes    ClusterIP      10.3.240.1     <none>         443/TCP        33m
myreact-app   LoadBalancer   10.3.241.212   35.198.196.3   80:31119/TCP   21m

Check your application

Try open external ip with your browser, in this case http://35.198.196.3

myreact-app

You successfully deploy application in Kubernetes cluster.