iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0
DevOps

關於我怎麼把一年內學到的新手 IT/SRE 濃縮到 30 天筆記這檔事系列 第 29

Day 29 GitLab CI/CD - 上傳 GitLab Registry 再部署到 Kubernetes

  • 分享至 

  • xImage
  •  

本篇大綱

今天要用 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 不好嗎?

https://ithelp.ithome.com.tw/upload/images/20221013/20112934U4TYzbdr26.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 的示範教學套用:

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。

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。

實戰 CI/CD

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

https://ithelp.ithome.com.tw/upload/images/20221013/20112934SVDV2kHaOU.png

專案樹狀圖:

.
├── 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 的時候就會停下來,那就按下繼續。

https://ithelp.ithome.com.tw/upload/images/20221013/20112934BYUhRx5gx6.png

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

https://ithelp.ithome.com.tw/upload/images/20221013/20112934eqcC8nb5qk.png

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

https://ithelp.ithome.com.tw/upload/images/20221013/20112934sgCeOOHDiB.png

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

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

本系列內容也會同步貼到我的 Blog https://blog.yangjerry.tw 歡迎來我的 Blog 點一下 RSS 追蹤,那我們就下一篇文章見啦!

Source


上一篇
Day 28 GitLab Runner - 安裝起來分配工作吧!
下一篇
Day 30 完賽宣言 - 下一步該如何走?
系列文
關於我怎麼把一年內學到的新手 IT/SRE 濃縮到 30 天筆記這檔事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言