返回
Featured image of post GCP - GitHub + Cloud Build + Private GKE 手把手

GCP - GitHub + Cloud Build + Private GKE 手把手

GitHub + Cloud Build + Private GKE,CI/CD自動部署 Git -> GKE

學習前置條件:

  1. gcloud 已經在本地安裝起來了
  2. GitHub Branch protection rules (分支保護) - 多環境的需求 (Prod/Qa/Dev)
  3. SSH 連線機制 - GCE 連線的時候所需
  4. 搭建一台 Private GKE - 會經由 IAP 連線至 GCE 部署到 Private GKE 走權限內網的方式
  5. Docker Image Tag 分類 - 多環境的需求 (Prod/Qa/Dev)
  6. Firewall 設置
  7. Cloud Nat 的統一 VPC 出口
  8. GCS 的 gsutil cli工具 - cp 檔案
  9. 自動化 CI/CD 部署 DevOps 概念

知識介紹

Git 分類與分支概念

  1. 由 branch 分多環境 (Prod/Qa/Dev)
  2. 由 tag 給予 release 版本


(範例分支圖)


GitHub 專案設置

分支保護的目的是為了讓職責分開,開發人員可以專心的開發需求
主要會有分幾種狀態 - Git flow

Settings/Manage access

分支名稱角色職責由local端推送至remote端
master( or prod)Maintainx
demo ( or qa)Maintainx
develop ( or dev)Writeo
feature/功能 ( or feat)Writeo
hot-fix/修補Writeo

Settings/Branch protection rules

用途是來保護分支讓分支有審核機制,官方文件:因應各個公司不同流程不同。
基本上會使用這幾種:

  1. Require a pull request before merging (合併前需要拉取請求,設立最少幾位同仁檢查)
  2. Require status checks to pass before merging (合併前需要通過狀態檢查,檢查CloudBuild健康狀態)
  3. Include administrators (包括 管理者不能直接 local 直推受保護的 branch 需要Pull Request)

Google Compute Engine (GCE)

create GCE

GCE 簡單說就是一台 VM 這台機器在這次演練中扮演者跳板機的角色,目的是讓 Cloud Build 能夠操作 GKE 的 Master 主機:

# 生一把 bastion 的 ssh key
ssh-keygen -t rsa -C "bastion"

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/xufangde/.ssh/id_rsa): bastion
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in bastion.
Your public key has been saved in bastion.pub.
The key fingerprint is:
SHA256:pdil3UsrmhF/cO8MYEj4klzXP0/J/jhuxhSoJEK4nq4 bastion
The key's randomart image is:
+---[RSA 3072]----+
|     .           |
|    . ..   .     |
|     o. o + ..   |
|    ...B.O....o .|
|   . .=.So=.+ o+.|
|    o  . +.= +o+ |
|   .    . o =o...|
|    .    + o +=..|
|  E.    o    +=..|
+----[SHA256]-----+
<!-- 相關機器設定 -->
name: bastion 
zone: asia-east1-b <!-- 範例使用 -->
machine-type: n1-f1-micro <!-- 能小就小 -->
Network interfaces: default / external-ip: none  <!-- 記得關掉 external-ip -->
Security/SSH:  <!-- ~/.ssh/bastion.pub -->
Service Account: default <!-- 預設的SA會是 [email protected] -->

<!-- [!] 讓 GCE 的 能夠操作的話 Service Account 的 IAM 
要加上一個 Rule `Kubernetes Engine Admin Editor`  -->

Google Kubernetes Engine (GKE)

create private GKE

基本上也是預設的,如果怕練習時間太長就用便宜的機器吧
Networking 要記得設定 Private clustercontrol plane IP range 就用 example


最下方有 Enable control plane authorized networks 控制介面,加上自己的外網IP
不知道怎麼算的可以這樣操作:

  1. 查自己的外網IP且複製起來
  2. CIDR計算器,將IP貼上至 IPv4 / IPv6 再按計算,就可以看相關詳細數字

基本上就是 x.x.x.x/32 限制一台IP入口 這樣,通常都用辦公室的固網,之後設定就直接建立
(其他相關設定由各自參閱GKE相關文章,非本次手把手重點)
建立完之後呢,可以到 GKE的操作介面有一台 GKE 正在運行,可以看到最右邊有 三個點點/Connect/Command-line access 看到似下方指令:

gcloud container clusters get-credentials <gke-name> --region <region-name> --project <project-name>

執行完之後可以嘗試看看操作是否有連線到 gke,會類似下方回饋(因為有用 control plane authorized networks 控制介面)

kubectl version --short

Client Version: v1.21.4
Server Version: v1.20.9-gke.1001

IAP 是什麼?

GCP 有一種連線方式是IAP,VM外網都關閉,由角色權限所分發認可角色進行連線的方式。


Cloud Nat 是什麼?

Cloud Nat 是用來 統一 Cloud Router 所指定的 Network 暴露出一個 External IP
我們的 GKE 與 GCE 都在同一個 Network (default)
如果要 GCE 要操作 GKE 這樣就要在我們的 GKE control plane authorized networks 加上 Cloud Nat 的 External IP/32


Cloud Build

Trigger 觸發器

我覺得 Cloud Build 與 Github 整合的相關功能蠻齊全的算不錯使用

Event

  1. Push to a branch (Pull Request 後 會進行 Merge branch 這時候觸發導致 -> CD 部署至Prod或Qa環境)
  2. Push new tag (新增Tag時會觸發 -> dev分支推送 git tag 的時候新增 Docker Image)
  3. Pull Request (Pull Request時觸發 -> 進行 Coding Test 讓 Maintainer 判斷是否可以合併至branch)

Source

可以使用正規表達式去指定你要觸發的條件,且都有選項範例

  1. Push to a branchPull Request就是指定哪個 正規表達Branch
  2. Push new tag 就是指定哪個 正規表達Tag

Configuration

我會使用 Cloud Build configuration file (yaml or json) 可以指定部署的yaml在哪

Advanced

於 CloudBuild 使用的變數,也可以在 yaml 中寫


手把手

  • Local SSH remote GCE connect Private GKE
  • Local SSH remote proxy GCE connect Private GKE
  • Cloud Build ssh remote proxy GCE connect Private GKE

Local SSH remote GCE connect GKE

調整 Firewall

讓 使用者能夠透過 gcloud cli 通過 iap 抵達機器 先加上 Firewall 的規則 (本次是使用SSH連線)

gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
  --direction=INGRESS \
  --action=allow \
  --rules=tcp:22 \
  --source-ranges=35.235.240.0/20

(預設其實原本有一個 0.0.0.0/0 全開的,建議刪除 default-allow-ssh , 一律透過 IAP 渠道進出)

調整 Identity-Aware Proxy (iap)

Security / Identity-Aware Proxy / SSH AND TCP RESOURCES 選取 bastion 那台機器

添加這項Roll:IAP-secured Tunnel User 讓操作人員透過 gcloud cli 通過 iap 抵達機器 可以把 allUsers 改成自己操作者的帳號或用 SA 操作專案也可以用 SA

本地連線 GCE

# gcloud compute ssh bastion@bastion --project <project-id> --zone <zone> --ssh-key-file=<ssh private key path>
gcloud compute ssh bastion@bastion --project example-project-0123 --zone asia-east1-b --ssh-key-file=~/.ssh/bastion
External IP address was not found; defaulting to using IAP tunneling.
...
bastion@bastion:~$ 

這樣就成功使用 bastion ssh key 連線至 GCE
完成 IAP -> Firewall -> GCE

GCE 操作 Private GKE

由於 知識介紹 有講到 GKE 使用是 Private GKE 所以 GKE control plane authorized networks 需加上 Cloud Nat 的 External IP/32

# gcloud 安裝 kubectl
gcloud components install kubectl
...
# gcloud 連線 gke
bastion@bastion:~$ gcloud container clusters get-credentials example-gke --region asia-east1 --project example-project-0123
Fetching cluster endpoint and auth data.
kubeconfig entry generated for example-gke.
# kubectl 指令
bastion@bastion:~$ kubectl version --short
Client Version: v1.22.1
Server Version: v1.20.9-gke.1001

這樣 GCE 就可以操作 GKE


Local SSH remote proxy GCE connect Private GKE

這個方式就可以完全的不用把 Office IP 寫進 GKE control plane authorized networks
這是我參考這篇文章的做法,將其筆記進此篇

調整 GCE

  1. 安裝 tinyproxy
gcloud compute ssh bastion@bastion --project example-project-0123 --zone asia-east1-b --ssh-key-file=~/.ssh/bastion
External IP address was not found; defaulting to using IAP tunneling.
...
bastion@bastion:~$ sudo apt-get install tinyproxy # 安裝 tinyproxy
...
  1. 修改 tinyproxy.conf vim /etc/tinyproxy/tinyproxy.conf 添加下拉至最後一行 按下 a 填上 Allow localhost 按下 esc 輸入 :wq! 編輯退出
  2. 重啟 sudo service tinyproxy restart

若使用 ssh 對等至 local 可以操作 gce

對等 Local Port 且嘗試操作 kubectl

Local 端也需要有 GKE 的 Conntent 方式

gcloud container clusters get-credentials example-gke --region asia-east1 --project example-project-0123
Fetching cluster endpoint and auth data.
kubeconfig entry generated for example-gke.

Local 端對等 port 8888

gcloud compute ssh bastion@bastion \
 --project example-project-0123 \
 --zone asia-east1-b \
 --ssh-key-file=~/.ssh/bastion \
 -- -L 8888:0.0.0.0:8888 -N -q -f

檢查是否連線 lsof -i:8888

lsof -i:8888
COMMAND   PID ................
ssh     17020 ................

# 這樣代表有一個進程正在執行 ssh PID

嘗試使用 kubectl 碰觸 private gke

HTTPS_PROXY=localhost:8888 kubectl version --short
Client Version: v1.21.4
Server Version: v1.20.9-gke.1001

# 成功

將進程刪除

kill 17020

HTTPS_PROXY=localhost:8888 kubectl version --short
Client Version: v1.21.4
The connection to the server xx.xxx.xxx.xxx was refused - did you specify the right host or port?
# 這樣就連不到了

Cloud Build SSH remote proxy GCE connect Private GKE


終於來到最後的環節,如何撰寫 CloudBuild,我相信官方文件寫得很清楚,先把權限設定先寫一下

Cloud Build SA 設定 (Cloud Build / Setting / Service Account)

Kubernetes Engine / Kubernetes Engine Developer : Enable
Compute Engine / Compute Instance Admin (v1) : Enable
Service Accounts / Service Account User : Enable

Cloud Build Tiggers

由 知識介紹 中 選擇其相關的方式

將 SSH Key 放進 GCS

可以點去 GCS 看到 asia.artifacts.example-project-0123.appspot.com , 這個是管理 GCR Image,我自己是習慣把它放在 asia 區 因為,我們就在亞洲區,在這個 Storage 中 新增一個放置 SSH key 的資料夾 .ssh,把 bastion 的 private/public key 上傳至GCS \

可以用本地測試這個指令看可否複製 key 至 Local

gsutil cp -r gs://asia.artifacts.$PROJECT_ID.appspot.com/.ssh .

重頭戲 cloudbuild.yaml

在使用這個之前我會先把環境先架設一遍,後續維護交給 Cloud Build 去更新上版

K8s 相關的設定 yaml 每個專案不同,我自己是習慣先建立一個 Projest 是 先建立起環境的 kustomiz Project 去管理最開始的初始化 GKE

steps:
  - name: 'gcr.io/cloud-builders/docker'
    id: Docker Pull / Tag / Push.
    entrypoint: sh
    args:
    - -c
    - |
        docker build -t asia.gcr.io/$PROJECT_ID/$_DOCKER_NAME:$TAG_NAME -t asia.gcr.io/$PROJECT_ID/$_DOCKER_NAME:dev . &&
        docker push asia.gcr.io/$PROJECT_ID/$_DOCKER_NAME:$TAG_NAME &&
        docker push asia.gcr.io/$PROJECT_ID/$_DOCKER_NAME:dev        
  - name: 'gcr.io/cloud-builders/gsutil'
    id: get ssh key
    entrypoint: sh
    args:
    - -c
    - gsutil cp -r gs://asia.artifacts.$PROJECT_ID.appspot.com/.ssh /builder/home/
  - name: 'gcr.io/cloud-builders/gsutil'
    id: chmod 400
    entrypoint: sh
    args:
    - -c
    - chmod 400 /builder/home/.ssh/bastion
  - name: gcr.io/cloud-builders/gcloud
    id: GKE - content gke > ssh bastion > Install `kubectl` > Rollout
    entrypoint: sh
    args:
    - -c
    - gcloud container clusters get-credentials example-gke --region asia-east1 --project $PROJECT_ID &&
      gcloud compute ssh bastion@bastion --project $PROJECT_ID --zone asia-east1-b --ssh-key-file=/builder/home/.ssh/bastion --  -L 8888:0.0.0.0:8888 -N -q -f &&
      gcloud components install kubectl &&
      HTTPS_PROXY=localhost:8888 kubectl rollout restart deploy example-deployname

結語:

我在嘗試 Cloud Build 用了很多 id 去分開步驟讓自己更清晰,但最後發現 當我把 gcloud compute ssh 和 kubectl 分開之後 就不能操作了,所以我將其動作和並就可以操作,可喜可賀可喜可賀
每一間公司的 CICD 都有其適合的地方,也許這種方式其實蠻不適合傳統維運人員 ,這種方式主要是以 Git Branch 去觸發 Deploy,以現階段來說這個方式蠻適合我的。

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus