《關於我怎麼把一年內學到的新手 IT/SRE 濃縮到 30 天筆記這檔事》 Day 29 GitLab CI/CD - 上傳 GitLab Registry 再部署到 Kubernetes

本篇大綱

今天要用 Kaniko 製作 Docker Image 上傳到自己的 GitLab Registry,上傳以後再執行部署命令到 Kubernetes。

內文

今天來要使用 Kaniko 跑在 Kubernetes executor 來製作 Docker Image,製作完成 Image 以後再部署到 Kubernetes 上,製作開發的流水線。

規劃&設計

這次 Lab 我會使用 Nginx + HTML 作為 Docker Image,用 Deployment & Service 建立 Backend,透過 Istio 的 VirtualService 對應進去。

建立 Docker Image 的部分會使用 Kubernetes executor,採用 unprivileged container 的 Kaniko 幫忙 Build Image。

部署的部分會採用 Shell executor,Shell executor 上一篇也確認使用 kubectl 是沒有問題的。

為什麼要 Kaniko?Docker in Docker 不好嗎?

day29-01.png

Google 搜尋 Container Privilege 就會找到 Trend Micro 的相關文章,當中就有提到 --privileged=true 會讓所有隔離功能都停用,可以看到 Host 上所有的硬體設備(E.g. 硬碟),可以執行 mount 指令。

之前有追蹤 NAS 的使用者 FB 群組,有一家受害者被入侵 Quick Connect,資料全都被加密,但實際上該使用者在開啟某個 Docker Container 時候,照著某個影片教學把 Privileged 權限打開了,被入侵的前夕出現了國外的連線紀錄,這件事告訴我們,對於 Privileged Container 真的要謹慎應對,不要隨意給予 Privileged 權限。

Docker Build Image 的時候會需要 --privileged=true 的權限,這樣其實不太好,最近 Google 推出 Kaniko 迴避掉 privileged 的部分,不需要額外權限給予 Container,對於安全提升一部分保障。

Kaniko 建立 Image 上傳到 GitLab Registry

這裡仿照 GitLab 官方對於 Kaniko 的示範教學套用:

1
2
3
4
5
6
7
8
9
10
11
12
13
build-image:
stage: build
rules:
- if: $CI_COMMIT_TAG # 如果有打上 Git Tag 則開始跑此 Job
image:
name: gcr.io/kaniko-project/executor:v1.9.0-debug
entrypoint: [""] # 把原本的 Entrypoint 清掉
script:
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
--destination "${CI_REGISTRY_IMAGE}:latest"

這裡代表的就是要套用 Git Tag 才會跑這個 Job,/kaniko/executor 就是讓 Docker image 可以 Build 的命令,建立 Image 成功後直接上傳到 GitLab Registry,Destination 可以用版本號碼或者 Latest。

Shell executor 部署 Application 到 Kubernetes

筆者會事先寫好 YAML 檔在 deploy/ 資料夾裡面,直接用 Apply 就可以(Application 變複雜以後可以改用 Helm Chart 部署),Apply 之後再 Set Image 給 Deployment。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
deploy-app:
stage: deploy
needs:
- build-image # 要先跑完 build-image 這個 Job 才能執行此動作
when: manual # 手動按下部署
rules:
- if: $CI_COMMIT_TAG # 如果有打上 Git Tag 則開始跑此 Runner
tags:
- shell
script:
- kubectl apply -f deploy/ -n production
- kubectl set image -n production deploy my-application web-app=${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} --record
- sleep 10 # 等待一下 10 秒
- kubectl get pod -n production # 列出 Pod 資訊在 Log 上確保是 Running

這裡把部署作為手動,確認版本沒有問題就可以部署上去。

組合結果

那我們就可以把上面的想法組合起來,變成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
stages:
- build
- deploy

build-image:
stage: build
rules:
- if: $CI_COMMIT_TAG
image:
name: gcr.io/kaniko-project/executor:v1.9.0-debug
entrypoint: [""]
script:
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
--destination "${CI_REGISTRY_IMAGE}:latest"

deploy-app:
stage: deploy
needs:
- build-image
when: manual
rules:
- if: $CI_COMMIT_TAG
tags:
- shell
script:
- kubectl apply -f deploy/ -n production
- kubectl set image -n production deploy my-application web-app=${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} --record
- sleep 10
- kubectl get pod -n production

等等把上面檔案儲存為 .gitlab-ci.yml,接下來就開始實戰 CI/CD。

實戰 CI/CD

建立專案,把 Visibility Level 設定為 Public,不然到時侯 Registry 要拉 Image 需要有權限,需要設定相關的 Image Pull Secret,這裡節省篇幅直接使用 Public

day29-02.png

專案樹狀圖:

1
2
3
4
5
6
7
8
9
10
.
├── deploy
│   ├── deployment.yaml
│   ├── service.yaml
│   └── virtualservice.yaml
├── Dockerfile
├── .gitlab-ci.yml
├── README.md
└── src
└── index.html

src/index.html 的內容:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<body>

<h1>This is my application</h1>
<p>version: v0.0.1</p>

</body>
</html>

Dockerfile 的內容:

1
2
FROM nginx:1.22
COPY src /usr/share/nginx/html

deploy/deployment.yaml 的內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-application
labels:
app: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-app
image: registry.yjerry.tw/tico88612/my-application:latest
ports:
- containerPort: 80

deploy/service.yaml 的內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: my-application
labels:
app: web
spec:
type: ClusterIP
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80

deploy/virtualservice.yaml 的內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-application-vs
labels:
app: web
spec:
hosts:
- myapp.yjerry.tw
gateways:
- istio-ingress/my-ingressgateway
http:
- name: "web"
route:
- destination:
host: my-application
port:
number: 80

接下來就把檔案加入 Commit + Tag 並上傳

1
2
3
4
git add .
git commit -m "Initial Commit"
git tag v0.0.1
git push origin v0.0.1

Push Tag 完成以後就會開始跑 Job,跑到 Stage: deploy 的時候就會停下來,那就按下繼續。

day29-03.png

就會看到已經更改完成了!

day29-04.png

設定好 DNS 就可以開網頁來瀏覽服務是否成功。

day29-05.png

這樣就簡單做完基礎的流水線了,是不是很棒呢?開發完的程式直接流水線部署在自己的基礎設施上。

明天就邁入 30 天發文的最後一天了,來做個總結跟未來探索路線吧!

本系列內容也會同步貼到我的 iT 邦幫忙 https://ithelp.ithome.com.tw/users/20112934 歡迎來點一下追蹤,那我們就下一篇文章見啦!

Source


《關於我怎麼把一年內學到的新手 IT/SRE 濃縮到 30 天筆記這檔事》 Day 29 GitLab CI/CD - 上傳 GitLab Registry 再部署到 Kubernetes
https://blog.yangjerry.tw/2022/10/14/it2022-day29/
作者
Jerry Yang
發布於
2022年10月14日
許可協議