今天要用 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 是沒有問題的。
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,對於安全提升一部分保障。
這裡仿照 GitLab 官方對於 Kaniko 的示範教學套用:
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。
筆者會事先寫好 YAML 檔在 deploy/
資料夾裡面,直接用 Apply 就可以(Application 變複雜以後可以改用 Helm Chart 部署),Apply 之後再 Set Image 給 Deployment。
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
這裡把部署作為手動,確認版本沒有問題就可以部署上去。
那我們就可以把上面的想法組合起來,變成這樣:
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。
建立專案,把 Visibility Level 設定為 Public
,不然到時侯 Registry 要拉 Image 需要有權限,需要設定相關的 Image Pull Secret,這裡節省篇幅直接使用 Public
。
專案樹狀圖:
.
├── deploy
│ ├── deployment.yaml
│ ├── service.yaml
│ └── virtualservice.yaml
├── Dockerfile
├── .gitlab-ci.yml
├── README.md
└── src
└── index.html
src/index.html
的內容:
<!DOCTYPE html>
<html>
<body>
<h1>This is my application</h1>
<p>version: v0.0.1</p>
</body>
</html>
Dockerfile
的內容:
FROM nginx:1.22
COPY src /usr/share/nginx/html
deploy/deployment.yaml
的內容:
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
的內容:
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
的內容:
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 並上傳
git add .
git commit -m "Initial Commit"
git tag v0.0.1
git push origin v0.0.1
Push Tag 完成以後就會開始跑 Job,跑到 Stage: deploy
的時候就會停下來,那就按下繼續。
就會看到已經更改完成了!
設定好 DNS 就可以開網頁來瀏覽服務是否成功。
這樣就簡單做完基礎的流水線了,是不是很棒呢?開發完的程式直接流水線部署在自己的基礎設施上。
明天就邁入 30 天發文的最後一天了,來做個總結跟未來探索路線吧!
本系列內容也會同步貼到我的 Blog https://blog.yangjerry.tw 歡迎來我的 Blog 點一下 RSS 追蹤,那我們就下一篇文章見啦!