Introduction

ကျွန်တော်ဒီနေ့ရေးမှာကတော့ gke cluster တစ်ခုပေါ်ကို cloud build နဲ့ continuous deployment လုပ်တဲ့အကြောင်းပဲဖြစ်ပါတယ်။ ဒီ topic ကကျွန်တော်မနေ့ကမှဖတ်ထားတာဖြစ်ပါတယ်။ နားလည်သလောက်လေးပြန်ရေးလိုက်တာပါ။ cloud build ဆိုတာ google cloud ရဲ့ ci cd tool တစ်ခုဖြစ်ပါတယ်။ cloud build မှာ trigger တွေ create ပြီး ci cd pipeline တွေလုပ်ကြပါတယ်။ ဒီနေ့ lab ရဲ့ သဘောတရားကတော့ github က repo ကို cloud build မှာ trigger ပေးထားမှာဖြစ်ပါတယ်။ main branch နဲ့ တစ်ခြား branch တွေက commit တစ်ခုလာတိုင်း trigger event က continuous deployments steps တွေရေးထားတဲ့ file ကိုသွားအလုပ်လုပ်မှာဖြစ်ပါတယ်။ main branch က လာရင် docker image ကို latest tag ပေးပြီး gke ပေါ်မှာ deployment တစ်ခုအဖြစ်သွား run မယ်။ တစ်ခြား branch ကလာရင် docker image ကို branch name ပေးမယ်။ ပြီးရင် gke ပေါ်ကို deployment တစ်ခု run မယ်။ ဒီလောက်ပါပဲ lab ရဲ့သဘောတရားကတော့။ ဒါဆိုအခုပဲ lab ကို စလိုက်ကြရအောင်နော်။

Create a GKE cluster

ပထမဆုံးအနေနဲ့ gke cluster တစ်ခုကို create ပေးရပါမယ်။ cloud shell ထဲကို သွားလိုက်ပါ။ cloud shell ထဲကို ရောက်ပြီဆိုလျှင် ကျွန်တော်တို့ လိုအပ်တာတွေစလုပ်လို့ရပါပြီ။ ပထမဆုံး gcloud auth login အရင်လုပ်ပေးရပါမယ်။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317905)$ gcloud auth login
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=wFQ4YUqdUgZxfvYdALW8wSi9GK0Url&prompt=consent&access_type=offline&code_challenge=MThbWkkc2LCeQ9lq4ymjlpbYb03-PPPWCKLXRPpfUjA&code_challenge_method

Enter verification code: <your_code>

You are now logged in as [thaunghtikeoo.tho1234@gmail.com].
Your current project is [clever-circlet-317904].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

login ပြီးတဲ့အခါ လိုအပ်တဲ့ variables တွေသတ်မှတ်ပေးရပါမယ်။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ export PROJECT=$(gcloud info --format='value(config.project)')
thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ export ZONE=us-central1-b
thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ export CLUSTER=gke-deploy-cluster

ပြီးသွားရင်တော့ gcloud config ထဲမှာ values တွေထည့်ပေးရပါမယ်။ gke cluster အတွက်သုံးမယ့် cluter name ၊ zone ၊ project_id စသည့် values တွေကိုအောက်ကလိုသတ်မှတ်ပေးရပါမယ်။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ gcloud config set project $PROJECT
Updated property [core/project].
thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ gcloud config set compute/zone $ZONE
Updated property [compute/zone].
thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ gcloud config set container/cluster $CLUSTER
Updated property [container/cluster].

ပြီးသွားရင်တော့ console ကနေ အောက်ပါ services တွေအတွက် api တွေကို access ရဖို့လုပ်ပေးရပါမယ်။

gcloud services enable container.googleapis.com \
    containerregistry.googleapis.com \
    cloudbuild.googleapis.com \
    sourcerepo.googleapis.com

အပေါ်က steps တွေအကုန်ပြီးရင်တော့ gke cluster တစ်ခုကို create ပါမယ်။ အပေါ်မှာ သတ်မှတ်ခဲ့တဲ့ variables တွေကိုပြန်သုံးထားပါတယ်။

gcloud container clusters create ${CLUSTER} \
    --project=${PROJECT} \
    --zone=${ZONE} \
    --scopes "https://www.googleapis.com/auth/projecthosting,storage-rw"

ပြီးသွားရင်တော့ cluster ကို access လုပ်ဖို့ credentials ကိုယူရပါမယ်။

 thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ gcloud container clusters get-credentials $CLUSTER --zone $ZONE
Fetching cluster endpoint and auth data.
kubeconfig entry generated for gke-deploy-cluster.

kubeconfig file ရပြီဆိုတော့ cluster ထဲကို access ရပါပြီ။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ kubectl get nodes
NAME                                                STATUS   ROLES    AGE     VERSION
gke-gke-deploy-cluster-default-pool-3b77fbf9-530t   Ready    <none>   5m59s   v1.19.9-gke.1900
gke-gke-deploy-cluster-default-pool-3b77fbf9-cqv4   Ready    <none>   6m      v1.19.9-gke.1900
gke-gke-deploy-cluster-default-pool-3b77fbf9-wb40   Ready    <none>   6m      v1.19.9-gke.1900

Sample Web App

lab မှာသုံးမယ့် app ကတော့ docker curriculum က cat app လေးပဲဖြစ်ပါတယ်။ app ကအောက်ကပုံထဲကလိုဖြစ်ပြီး အပေါ်မှာ branch name ကိုတွေ့ရမှာဖြစ်ပါတယ်။

main

ပြီးရင် cluster ကို cloud build နဲ့ access ရဖို့ အောက်ကလို rolebinding တွေလုပ်ပေးရပါမယ်။ cluster က cloud build က deployment တွေကို RUN နိုင်ဖို့ပါ။

export PROJECT_NUMBER="$(gcloud projects describe \
    $(gcloud config get-value core/project -q) --format='get(projectNumber)')"

gcloud projects add-iam-policy-binding ${PROJECT} \
    --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
    --role=roles/container.developer

Setup Build Triggers

ဒီအဆင့်မှာတော့ cicd အတွက် trigger တွေလုပ်ပေးရမှာဖြစ်ပါတယ်။ main branch အတွက် trigger တစ်ကြောင်းကို အောက်ကအတိုင်း တစ်ဆင့်ချင်း create ပါမယ်။ အရင်ဆုံး console ထဲက cloud build ထဲကိုသွားပါ။ ပြီးရင် trigger အတွက်လိုအပ်တာတွေလုပ်ပေးရပါမယ်။ name ကိုတော့ cat-main-branch လို့ပေးလိုက်ပြီး event မှာ push to a branch ကို ရွေးလိုက်ပါတယ်။ main branch ကို commit ဖြစ်တိုင်း trigger ကအလုပ်လုပ်မှာဖြစ်ပါတယ်။ source မှာတော့ github ကကျွန်တော့်ရဲ့ rep ကိုချိတ်ပေးလိုက်ပါတယ်။

mt1

configuration မှာ trigger အလုပ်လုပ်မယ့် file path ကိုထည့်ပေးပါ။ ကျွန်တော် ကတော့ git repo ထဲက /builder/cloudbuild-canary.yaml ထဲမှာ deployment configuration တွေကိုထည့်ထားလို့ အဲ့ဒီ path ကိုထည့်ပေးလိုက်တာပါ။ variables တွေက cloudbuild-canary.yaml ထဲမှာသုံးမယ့် var တွေပါ။ gke cluster name နဲ့ zone ကိုထည့်ထားပေးတာပါ။ ပြီးရင် create ကိုနှိပ်လိုက်ပါ။

mt2

ကျွန်တော့်ရဲ့ configuration ကတော့ အောက်ကအတိုင်း cat:latest docker image တစ်ခု gcr ထဲကို build မယ်။ gke cluster credentials တွေကို ယူမယ်။ gke ပေါ်ကို deploy လုပ်မယ်။ ဒါပါပဲ

# Copyright 2018 Google LLC
# 
# 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
# 

#     https://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.


steps:

### Build

  - id: 'build'
    name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: 
      - '-c'
      - |
          docker build -t gcr.io/$PROJECT_ID/cat:latest .



### Test


### Publish
  - id: 'publish'
    name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: 
      - '-c'
      - |
          docker push gcr.io/$PROJECT_ID/cat:latest



### Deploy
  - id: 'deploy'
    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'
      - |
          CLUSTER=$$(gcloud config get-value container/cluster)
          PROJECT=$$(gcloud config get-value core/project)
          ZONE=$$(gcloud config get-value compute/zone)

          gcloud container clusters get-credentials "$${CLUSTER}" \
            --project "$${PROJECT}" \
            --zone "$${ZONE}"  
         

          kubectl apply -f kubernetes/deploy.yaml
          kubectl apply -f kubernetes/svc.yaml

Run Trigger

ပြီးသွားရင်တော့ trigger ကို run လို့ရပါပြီ။ ဒါပေမယ့် trigger ကဒီအတိုင်းဆိုအလုပ်လုပ်မှာမဟုတ်သေးပါဘူး။ commit တစ်ခုလာမှ လုပ်မှာဆိုတော့ initial commit တစ်ခုကိုတော့ လုပ်ပေးရပါမယ်။ git repo ထဲသွားပြီး file တစ်ခုခုကို commit လုပ်ပေးလိုက်ပါ။

runt

ခဏကြာတော့ build history ထဲက ထိပ်ဆုံးမှာ build တစ်ခုကိုတွေ့ရမှာဖြစ်ပါတယ်။

building

build တာပြီးသွားတဲ့အခါ build log တွေကိုကြည့်ဖို့ build ကို click ပြီး logs တွေကိုကြည့်နိုင်ပါပြီ။

buildlog

Deployments On Gke

build success ဖြစ်တဲ့အခါ gke ပေါ်မှာ git repo ထဲက kubernetes directory ထဲမှာသတ်မှတ်ခဲ့တဲ့အတိုင်း cat deployment နဲ့ service တစ်ခုကိုတွေ့ရမှာဖြစ်ပါတယ်။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ kubectl get all -n cat
NAME                              READY   STATUS    RESTARTS   AGE
pod/cat-master-69d7bc46cf-zkbqv   1/1     Running   0          17m

NAME          TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE
service/cat   LoadBalancer   10.3.252.79   35.224.48.100   80:32637/TCP   17m

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cat-master   1/1     1            1           17m

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/cat-master-69d7bc46cf   1         1         1       17m

cat service က LoadBalancer IP ကိုခေါ်ကြည့်ရင် sample app ထဲကအတိုင်းပဲတွေ့ရမှာဖြစ်တယ်။

main

Other Branches

main branch အကြောင်းပြီးပြီဆိုတော့ တစ်ခြား branch တွေအတွက်လည်း စမ်းကြည့်ပါဦးမယ်။ အခုလက်ရှိမှာတော့ dev branch တစ်ခုပဲရှိပါသေးတယ်။ demo အတွက်က တစ်ခုဆိုလုံလောက်တာမို့ dev နဲ့ပဲစမ်းလိုက်ပါမယ်။ အရင်ဆုံး main branch trigger တုန်းကလို trigger တစ်ခု create ပါမယ်။ name ကိုတော့ cat-other-branch လို့ပေးလိုက်မယ်။ repo က cat github repo ၊ branch မှာ main ကလွဲပြီး ကျန်တဲ့ branch အကုန်ဆိုတော့ invert regex ကိုရွေးခဲ့တယ်။ အခုတော့ dev တစ်ခုပဲရှိတာကိုတွေ့ရပါလိမ့်မယ်။

dt1

configuration မှာ file ကိုထည့်ပါ။ file ထဲမှာသုံးမယ့် လိုအပ်တဲ့ variable တွေကို သတ်မှတ်ပေးပါ။ ပြီးရင် create ကိုနှိပ်ပေးပါ။

dt2

ကျွန်တော့်ရဲ့ cloud build deployment configuration ကတော့ အောက်ကအတိုင်းပဲဖြစ်တယ်။ docker image ကို cat ၊ tag ကို branch name ပေးမယ်။ ပြီးရင် gcr ထဲကို push မယ်။ gke cluster access ယူမယ်။ kubernetes deployment ထဲက image ကို tag latest အစား create ခဲ့တဲ့ branch name နဲ့အစားထိုးမယ်။ kubernetes deployment တွေလုပ်မယ်။ ဒီလောက်ပါပဲ။

# Copyright 2018 Google LLC
# 
# 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
# 
#     https://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.


steps:

### Build

  - id: 'build'
    name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: 
      - '-c'
      - |
          docker build -t gcr.io/$PROJECT_ID/cat:${BRANCH_NAME} .



### Test


### Publish
  - id: 'publish'
    name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: 
      - '-c'
      - |
          docker push gcr.io/$PROJECT_ID/cat:${BRANCH_NAME}



### Deploy
  - id: 'deploy'
    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'
      - |
          CLUSTER=$$(gcloud config get-value container/cluster)
          PROJECT=$$(gcloud config get-value core/project)
          ZONE=$$(gcloud config get-value compute/zone)

          gcloud container clusters get-credentials "$${CLUSTER}" \
            --project "$${PROJECT}" \
            --zone "$${ZONE}"  
          
          sed -i 's|gcr.io/$PROJECT_ID/cat:latest|gcr.io/$PROJECT_ID/cat:${BRANCH_NAME}|' ./kubernetes/deploy.yaml  
          sed -i 's|cat-master|cat-${BRANCH_NAME}|' ./kubernetes/deploy.yaml
          sed -i 's|cat-branch|cat-${BRANCH_NAME}|' ./kubernetes/svc.yaml
 
          kubectl apply -f kubernetes/deploy.yaml
          kubectl apply -f kubernetes/svc.yaml

အခု trigger ကို run ပါမယ်။ initial commit တစ်ခုလိုတဲ့အတွက် dev branch ကို commit တစ်ခုလုပ်ပေးလိုက်ပါ။ ခဏကြာတော့ build တစ်ခုကို ထိပ်ဆုံးမှာတွေ့ရမှာပါ။

devbuild

build တာပြီးသွားတဲ့အခါ logs ထဲကို ဝင်ကြည့်ရင် gke ပေါ်ကို deploy ခဲ့တာကိုတွေ့ရမှာပါ။

devblog

container registry ထဲက cat repo ထဲမှာလည်း dev နဲ့ latest ဆိုပြီး tag တွေကိုတွေ့နိုင်ပါတယ်။

catcr

gke မှာလည်း cat-dev ဆိုပြီး deployment နဲ့ service တစ်ခုကိုတွေ့ရမှာဖြစ်ပါတယ်။

thaunghtikeoo_tho1234@cloudshell:~ (clever-circlet-317904)$ kubectl get all -n cat
NAME                              READY   STATUS    RESTARTS   AGE
pod/cat-dev-d69c88fc7-7lbsn       1/1     Running   0          11m
pod/cat-master-69d7bc46cf-zkbqv   1/1     Running   0          59m

NAME                 TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
service/cat          LoadBalancer   10.3.252.79    35.224.48.100   80:32637/TCP   59m
service/cat-dev      LoadBalancer   10.3.251.179   35.202.92.182   80:31828/TCP   33s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cat-dev      1/1     1            1           11m
deployment.apps/cat-master   1/1     1            1           59m

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/cat-dev-d69c88fc7       1         1         1       11m
replicaset.apps/cat-master-69d7bc46cf   1         1         1       59m

cat-dev service ရဲ့ loadbalancer ip ကိုခေါ်ကြည့်ရင်လည်း အောက်ကလိုတွေ့ရမှာဖြစ်ပါတယ်။

devcat

Conclusion

demo ကနည်းနည်းရှည်သွားတော့ မျက်လုံးနဲ့ကြည့်ရင်တော့နည်းနည်းခက်နိုင်ပါတယ်။ gcp account ရှိရင်တော့လိုက်စမ်းကြည့်လို့ရပါတယ်။ ကျွန်တော်နားလည်တာကို ပြန်လည်ရှင်းပြတာပဲဖြစ်ပါတယ်။ အမှားတွေပါရင်လည်း နားလည်ပေးကြပါခင်ဗျာ။ ဆက်လက်ကြိုးစားပါဦးမယ်။ အားလုံးကိုကျေးဇူးတင်ပါတယ်။

Thanks for reading …