使用 GCP Cloud Build 建立 CI/CD Pipeline 自動化部署服務到 GKE - 以 Nodejs 範例

先備知識:

  • Docker
  • Helm
  • K8S

先備工具:

  • docker
  • kubectl
  • helm
  • Github 帳號
  • GCP 帳號
  • GCP k8s cluster

透過這篇文章可以學會:

  • 使用 Cloud Build 建立 CI/CD Pipeline 並且把服務部署到 GKE 上

範例所有的程式碼在最下面

目錄:

1. 建立 nodejs 專案 & dockerfile
2. 驗證 docker images
3. 建立 Helm Chart
4. 建立 cloud-build.yaml
5. push code to Github 以及在 GCP cloud build 設定 trigger
6. 驗證

建立 Nodejs 專案 & Dockerfile

$ npm init -y # 建立新專案
$ touch index.js # 新增檔案
$ touch Dockerfile # 新增 Dockerfile
$ npm i express # 加入 express

package.json 新增 start 指令

{
  "name": "nodejs-cloud-build-deploy-gke",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}
package.json
const express = require('express');

const app = express();

app.get('/', (req, res) => {
  res.send('OK')
})

app.listen(3000, () => {
  console.log('listen at 3000 port')
})
index.js
FROM node:13.12.0-alpine

WORKDIR /app

COPY . .

RUN npm i

ENV NODE_ENV production

EXPOSE 3000

CMD ["npm","run", "start"]
Dockerfile

驗證 docker images

$ docker build -t node-server:1.0 .
$ docker run -idt -p 3000:3000 node-server:1.0
$ curl localhost:3000

有 return OK 代表 docker images 沒問題了

建立 Helm Chart

$ helm create YOUR_PROJECT_NAME

修改 helm 建立出來的 values.yaml & deployment.yaml

values.yaml 有三個部分需要更改

  1. pull image 的 repository 的位置
  2. service port,要跟我們 docker image expose 的 port 一樣
  3. ingress,設定被訪問的 hostname

deployment.yaml 有一個部分需要修改

  1. health check  的 containerPort 要跟 docker image expose 的 port 一樣

先來看 values.yaml 部分

  1. pull image 的 repository 的位置
repository: gcr.io/YOUR_GCP_PROJECT_ID/YOUR_REPOSITORY_NAME

2.  service port

3. ingress

deployment.yaml 的部分

建立 cloud build 設定黨

上面已經建立完基礎的程式和 Dockerfile 了

現在要來準備我們 cloud build  檔案了

建立一個 cloudbuild-sandbox.yaml 的檔案在 project 根目錄

通常我會用環境來區分不同的 cloud build 設定黨

舉例來說,當今天要建立正式環境的就會叫做 cloudbuild-prod.yaml

我們期望透過 cloud build 來 build docker images 和 deploy to gke

所以可以想像一下 pipeline 一定會有以下幾個步驟

  1. build image and storage image
  2. deploy to gke

關於第一點在 google search cloud build images 馬上就可以找到官方的教學

Building container images | Cloud Build Documentation | Google Cloud

steps:
  - name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/$PROJECT_ID/YOUR_PROJECT_NAME:$SHORT_SHA", "."]
    waitFor: ['-']
    id: 'build-image'
images: ["gcr.io/$PROJECT_ID/YOUR_PROJECT_NAME"]
build images 的指令

第二點 deploy to gke 就比較複雜

需要先準備 helm image 在 gcr (Container Registry) 內

可以參考一下的文件

cloud-builders-community/helm at master · GoogleCloudPlatform/cloud-builders-community
Community-contributed images for Google Cloud Build - cloud-builders-community/helm at master · GoogleCloudPlatform/cloud-builders-community

準備好後,就是要來撰寫我們的 helm 指令了

會分兩部分

  1. 先透過 gcloud 指令拿取 k8s credentials
  2. 透過 helm 部署服務到指定的 namespace
- name: gcr.io/cloud-builders/gcloud
    args: ['container', 'clusters', 'get-credentials', 'ben-prod', '--region', 'asia-east1']
    id: 'prepare-credentials'
gcloud 指令拿取 k8s credentials
- name: 'gcr.io/$PROJECT_ID/helm'
    args: ['--namespace=default','upgrade','--install','node-api','node-api','-f','node-api/values.yaml','--set','image.tag=$SHORT_SHA' ]
    env:
    - 'CLOUDSDK_COMPUTE_ZONE=asia-east1'
    - 'CLOUDSDK_CONTAINER_CLUSTER=ben-prod'
    waitFor: ['build-image', 'prepare-credentials']
tags: ['cloud-builders-community']
helm 部署服務

完整的檔案如下

steps:
  - name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/$PROJECT_ID/node-api:$SHORT_SHA", "."]
    waitFor: ['-']
    id: 'build-image'
  - name: gcr.io/cloud-builders/gcloud
    args: ['container', 'clusters', 'get-credentials', 'ben-prod', '--region', 'asia-east1']
    id: 'prepare-credentials'
  - name: 'gcr.io/$PROJECT_ID/helm'
    args: ['--namespace=default','upgrade','--install','node-api','node-api','-f','node-api/values.yaml','--set','image.tag=$SHORT_SHA' ]
    env:
    - 'CLOUDSDK_COMPUTE_ZONE=asia-east1'
    - 'CLOUDSDK_CONTAINER_CLUSTER=ben-prod'
    waitFor: ['build-image', 'prepare-credentials']
tags: ['cloud-builders-community']
images: ["gcr.io/$PROJECT_ID/node-api"]
cloudbuild-sandbox.yaml

push code to Github 以及在 GCP cloud build 設定 trigger

先把 code 推送到 Github 上

進到 GCP 的 Cloud Build 頁面,點選觸發條件 > 建立觸發條件

連結 Github 存放區 讓 cloud build 可以讀取的 code

設定來源 > 存放區

分之版本就是要偵測的 branch,當該分支有異動時,就會觸發 cloud build

設定 cloud build 的檔案

就可以按下建立了!

接下來就會在觸發條件的頁面看到剛剛建立好的觸發條件,點擊右方的 執行

就可以看到正在運行的 cloud build

驗證

部署成功後就可以驗證服務到底有沒有建立起來了

看到 OK 就代表好了!

測試的程式碼

GitHub - wuchienhsun/nodejs-cloud-build-deploy-gke
Contribute to wuchienhsun/nodejs-cloud-build-deploy-gke development by creating an account on GitHub.