本篇大綱
今天要用 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 不好嗎?
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 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"
|
這裡代表的就是要套用 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 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
|
這裡把部署作為手動,確認版本沒有問題就可以部署上去。
組合結果
那我們就可以把上面的想法組合起來,變成這樣:
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
。
專案樹狀圖:
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
的時候就會停下來,那就按下繼續。
就會看到已經更改完成了!
設定好 DNS 就可以開網頁來瀏覽服務是否成功。
這樣就簡單做完基礎的流水線了,是不是很棒呢?開發完的程式直接流水線部署在自己的基礎設施上。
明天就邁入 30 天發文的最後一天了,來做個總結跟未來探索路線吧!
本系列內容也會同步貼到我的 iT 邦幫忙 https://ithelp.ithome.com.tw/users/20112934 歡迎來點一下追蹤,那我們就下一篇文章見啦!
Source