上篇文章中我們探討了本地開發應用程式與 Kubernetes 整合的測試流程,透過不同的 Kubernetes 部署工具會有不同的結果,如果採用
的是 KIND 這種工具,本身就有提供額外的指令幫助開發者將本地測試的 Contianer Image 給載入到 KIND 叢集中,可以提升整體開發效
率,但是如果採用的不是 KIND 的話,那該怎麼辦?
因此本篇就要來介紹另外一個開源工具 Skaffold
,看看我們可以如何使用這套工具來提升本地開發 Kubernetes 應用的效率 (前提是你有需要一個 Kubernetes 來測試)
Skaffold 介紹 Skaffold 官方是這樣介紹自己工具的
Skaffold is a command line tool that facilitates continuous development for Kubernetes-native applications. Skaffold handles the workflow for building, pushing, and deploying your application, and provides building blocks for creating CI/CD pipelines. This enables you to focus on iterating on your application locally while Skaffold continuously deploys to your local or remote Kubernetes cluster.
簡單來說 Skaffold 是一個幫助開發 Kubernetes-natvie 應用程式的工具,其會幫你建置你的 Container Image, 推送 Container Image 到 部署你的應用程式到 Kubernetes 叢集,將這些動作一次整合,讓開發者能夠專心於應用程式開發,而應用程式最後如何跑到 Kubernetes 上則全部交給 Skaffold 來處理。
與之前的議題相比之下, Skaffold 除了支援本地的 Kubernetes 外,也支援遠方的 Kuberentes 叢集,我們來看一下其支援哪些類型的 Kuberentes 吧
下表節錄自官方文件 , 可以看到對於本地的 Kubernetes 叢集支援不少,包含了 minikube
, kind
k3d
之前提過的都有支援,此外 docker-desktop
這類型也有支援。
Remote 的話則是以 Google 為主,由於本章節探討的都是本地的部署,所以接下來還是會以本地的 Kuberentes 叢集為範例去介紹與使用
Kubernetes context
Local cluster type
Notes
docker-desktop
Docker Desktop
docker-for-desktop
Docker Desktop
This context name is deprecated
minikube
minikube
kind-(.*)
kind
This pattern is used by kind >= v0.6.0
(.*)@kind
kind
This pattern was used by kind < v0.6.0
k3d-(.*)
k3d
This pattern is used by k3d >= v3.0.0
架構 下圖節錄自官方文件
圖片中藍色基底就是 Skaffold 中最常使用到的功能,接下來我們就一個一個介紹每個區塊在做什麼事情
Detecting Source Code 如同前言所述, Skaffold 希望開發者可以專注於程式碼的開發,而後續的流程都讓其來幫忙搞定,因此其內建一個偵測系統,當目標目錄內的程式碼有所更動時,就會自動地執行相關工作流程,這樣對於使用者來說,只需要存擋,等待一點時間就可以於 Kubernetes 叢集中看到最新的程式碼
Bulding Artifacts 當程式碼被偵測到更動後, Skaffold 就會開始建置相關產物,這邊支援多種類型,譬如 Dockerfile, Bazel, Jib Maven 甚至是其他自定義的腳本。除了本地的產物產生之外, Skaffold 也有跟 Google Cloud Build 有所整合,這部分我認為跟 Skaffold 是 Google 開源有很大的關係,所以目前只有 Google 家的服務有支援。
Test Artifacts 當產物產生後,會對這個產物進行測試,這個階段能做的選擇比較少,目前是基於 Container-structure-test 這套開源軟體來進行測試,有興趣瞭解這個專案做什麼的可以點選前述連結或是到官方頁面 瞭解更多
Tagging Artifacts 當產物產生也測試完畢之後,接下來會對產物進行 Tag 的動作,該 Tag 會打到 Container Image 上,目前有支援四種選項,包含
Git Commit IDs
Sha256 Hash
Go Tempate with Environment Variable Support
Date & Time
四者詳細的差異可以觀看官方頁面 來瞭解更多,基本上就是讓你選擇不同的 image tag
Pushing Artifac 這個步驟就是想辦法將上述的產物給送到 Kubernetes 裡面,這部分如果 Kubernetes 是本地機器,可以忽略這個步驟直接使用,就如同前述的 Kubeadm 的環境一樣。 如果是遠方的環境的話,這邊就會根據遠方 Kubernetes Cluster 不同種類而採用的方式來處理,其判斷準則則是依據 KUBECONFIG CURRENT-CONTEXT 的名稱,就以最上面的支援環境來說
Kubernetes context
Local cluster type
Notes
docker-desktop
Docker Desktop
docker-for-desktop
Docker Desktop
This context name is deprecated
minikube
minikube
kind-(.*)
kind
This pattern is used by kind >= v0.6.0
(.*)@kind
kind
This pattern was used by kind < v0.6.0
k3d-(.*)
k3d
This pattern is used by k3d >= v3.0.0
可以看到不同版本的 KIND
產生的 kubernetes context 名稱不同,但是只要有符合這兩個規則, Skaffold 都會視為是 KIND 並且用 KIND 的方式幫你推上 KIND 叢集
Deploying Artifacts 最後則是將應用程式部署到 Kuberentes 裡面,這邊支援三種工具來部署,分別是
kubectl
helm
kustomize
我認為這三種基本上已經涵蓋了大部分人的使用情境, Skaffold 會將檔案內的 ImageTag 換成前面步驟產生的 Tag 並且將內容推到 Kubernetes 內部去更新
想要瞭解更多關於 Skaffold 的介紹可以參閱官網
安裝 安裝指令也非常簡單,整個 Skaffold 的運作核心都在其 Binary,所以也只有一個軟體需要下載與安裝
1 2 curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \ sudo install skaffold /usr/local /bin/
安裝完畢後可以看到該指令有非常多的用法可以使用,接下來將會介紹本地開發時可能會使用的指令及相關用法。
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 33 34 $ skaffold A tool that facilitates continuous development for Kubernetes applications. Find more information at: https://skaffold.dev/docs/getting-started/ End-to-end pipelines: run Run a pipeline dev Run a pipeline in development mode debug [beta] Run a pipeline in debug mode Pipeline building blocks for CI/CD: build Build the artifacts deploy Deploy pre-built artifacts delete Delete the deployed application render [alpha] Perform all image builds, and output rendered Kubernetes manifests Getting started with a new project: init [alpha] Generate configuration for deploying an application fix Update old configuration to a newer schema version Other Commands: completion Output shell completion for the given shell (bash or zsh) config Interact with the Skaffold configuration credits Export third party notices to given path (./skaffold-credits by default) diagnose Run a diagnostic on Skaffold schema List and print json schemas used to validate skaffold.yaml configuration survey Opens a web browser to fill out the Skaffold survey version Print the version information Usage: skaffold [flags] [options] Use "skaffold <command> --help" for more information about a given command . Use "skaffold options" for a list of global command -line options (applies to all commands).
Demo 這邊我們直接使用官方的範例 Repo 來測試
1 2 git clone https://github.com/GoogleContainerTools/skaffold cd skaffold/examples/getting-started
此外,我的系統中目前有之前由 KIND 所建立的 Kuberentes 叢集
前述講到整個 Skaffold 的架構,裡面有些階段都會有些不同的選擇,實際上這些選擇都是依賴一個 yaml 的設定檔案來處理,該資料夾內就有一個這樣的檔案
1 2 3 4 5 6 7 8 9 10 $ cat skaffold.yaml apiVersion: skaffold/v2beta7 kind: Config build: artifacts: - image: skaffold-example deploy: kubectl: manifests: - k8s-*
這裡面設定幾個部分
產物的部分,會把 image 叫做 skafoold-example
部署的部分會把所有符合 k8s-*
字眼的檔案都用 kubectl 給部署進去
預設的情況下都會使用 Dockerfile 來建置產物
1 2 3 4 5 6 7 8 9 10 11 $ cat Dockerfile FROM golang:1.12.9-alpine3.10 as builder COPY main.go . RUN go build -o /app main.go FROM alpine:3.10 ENV GOTRACEBACK=single CMD ["./app" ] COPY --from=builder /app .
下方則是相關的 Kubernetes yaml, 非常乾淨與單純
1 2 3 4 5 6 7 8 9 $ cat k8s-pod.yaml apiVersion: v1 kind: Pod metadata: name: getting-started spec: containers: - name: getting-started image: skaffold-example
接下來我們可以呼叫 skaffold
這個指令來執行 一次完整的 workflow
, 包含建置 image, push image 以及 deploy 到 kubernetes 裡面。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 $ skaffold dev Listing files to watch... - skaffold-example Generating tags... - skaffold-example -> skaffold-example:v1.14.0-7-g677d665c3 Checking cache... - skaffold-example: Not found. Building Found [kind-kind] context, using local docker daemon. Building [skaffold-example]... Sending build context to Docker daemon 3.072kB Step 1/7 : FROM golang:1.12.9-alpine3.10 as builder 1.12.9-alpine3.10: Pulling from library/golang 9d48c3bd43c5: Pull complete 7f94eaf8af20: Pull complete 9fe9984849c1: Pull complete cf0db633a67d: Pull complete 0f7136d71739: Pull complete Digest: sha256:e0660b4f1e68e0d408420acb874b396fc6dd25e7c1d03ad36e7d6d1155a4dff6 Status: Downloaded newer image for golang:1.12.9-alpine3.10 ---> e0d646523991 Step 2/7 : COPY main.go . ---> afab364bca27 Step 3/7 : RUN go build -o /app main.go ---> Running in 7ac080c720c1 ---> cbcc0f655527 Step 4/7 : FROM alpine:3.10 3.10: Pulling from library/alpine 21c83c524219: Already exists Digest: sha256:f0e9534a598e501320957059cb2a23774b4d4072e37c7b2cf7e95b241f019e35 Status: Downloaded newer image for alpine:3.10 ---> be4e4bea2c2e Step 5/7 : ENV GOTRACEBACK=single ---> Running in 3336c2434250 ---> f7da9bb5a8f4 Step 6/7 : CMD ["./app" ] ---> Running in ad83b9fb99e8 ---> c18d1a41c91d Step 7/7 : COPY --from=builder /app . ---> 4dec7885d19b Successfully built 4dec7885d19b Successfully tagged skaffold-example:v1.14.0-7-g677d665c3 Tags used in deployment: - skaffold-example -> skaffold-example:4dec7885d19bcf6a6fef2bc62c609390787a73be61501ad0bdaffd3b229fd9a5 Loading images into kind cluster nodes... - skaffold-example:4dec7885d19bcf6a6fef2bc62c609390787a73be61501ad0bdaffd3b229fd9a5 -> Loaded Images loaded in 1.629866454s Starting deploy... - pod/getting-started created Waiting for deployments to stabilize... Deployments stabilized in 13.655262ms Press Ctrl+C to exit Watching for changes... [getting-started] Hello world! [getting-started] Hello world! [getting-started] Hello world! [getting-started] Hello world! [getting-started] Hello world! [getting-started] Hello world
上述的範例可以觀察到
Push 的規則, 偵測到使用的是 KIND,所以就呼叫 KIND 的方式把 Image 送進去
1 2 Loading images into kind cluster nodes... - skaffold-example:4dec7885d19bcf6a6fef2bc62c609390787a73be61501ad0bdaffd3b229fd9a5 -> Loaded
Deploy 的部分則是用 Kubectl 的方式將 Yaml 送進去,然後自動輸出相關的 Log.
修改程式碼 接下來我們開兩個視窗,一個視窗透過 skaffold dev
來偵測並處理整個流程,另一個視窗則是用來修改 main.go
接下來我們修改 main.go
改成下列內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package mainimport ( "fmt" "time" ) func main () { for { fmt.Println("Hello world!-hwchiu-ithome" ) time.Sleep(time.Second * 1 ) } }
當檔案存下去之後,馬上觀察另外一個視窗,會發現很快就偵測到程式碼的更動,並且馬上將修改的內容直接送到 Kubernetes 裡面
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 [getting-started] Hello world!-hwchiu [getting-started] Hello world!-hwchiu [getting-started] Hello world!-hwchiu [getting-started] Hello world!-hwchiu Generating tags... - skaffold-example -> skaffold-example:v1.14.0-7-g677d665c3-dirty Checking cache... - skaffold-example: Not found. Building Found [kind-kind] context, using local docker daemon. Building [skaffold-example]... Sending build context to Docker daemon 3.072kB Step 1/7 : FROM golang:1.12.9-alpine3.10 as builder ---> e0d646523991 Step 2/7 : COPY main.go . ---> 5a9d1bded1b1 Step 3/7 : RUN go build -o /app main.go ---> Running in 0b71f1abe4e7 ---> bcc350de6d46 Step 4/7 : FROM alpine:3.10 ---> be4e4bea2c2e Step 5/7 : ENV GOTRACEBACK=single ---> Using cache ---> f7da9bb5a8f4 Step 6/7 : CMD ["./app" ] ---> Using cache ---> c18d1a41c91d Step 7/7 : COPY --from=builder /app . ---> a73f3a1b761b Successfully built a73f3a1b761b Successfully tagged skaffold-example:v1.14.0-7-g677d665c3-dirty Tags used in deployment: - skaffold-example -> skaffold-example:a73f3a1b761b040dfab47ba89b145da88c517ec7d031c32e5d61cb5e3bf205d3 Loading images into kind cluster nodes... - skaffold-example:a73f3a1b761b040dfab47ba89b145da88c517ec7d031c32e5d61cb5e3bf205d3 -> Loaded Images loaded in 1.327803742s Starting deploy... - pod/getting-started configured Waiting for deployments to stabilize... Deployments stabilized in 2.156854ms Watching for changes... [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome [getting-started] Hello world!-hwchiu-ithome
這時候用 kubectl 去觀察系統上的資源
1 2 3 $ kubectl get pods NAME READY STATUS RESTARTS AGE getting-started 1/1 Running 1 111s
可以發現這個 Pod 的 Restart
次數有增加,這是因為 Container Image 更新後,Pod 重啟,載入新的 Image 最後顯示出新的 log 資訊 Hello world!-hwchiu-ithome
到這邊我們就基本介紹了 Skaffold 的操作流程跟一個簡單 Demo, 如果對於這個工具有興趣的話可以嘗試玩玩看,將其整合到 Helm 或是 Kustomize 等不同部署方式,看看是否真的能夠提升自己的開發效率。
個人資訊 我目前於 Hiskio 平台上面有開設 Kubernetes 相關課程,歡迎有興趣的人參考並分享,裡面有我從底層到實戰中對於 Kubernetes 的各種想法
組合包https://hiskio.com/packages/7ey2vdnyN
疑難雜症除錯篇https://hiskio.com/courses/440/about?promo_code=LG28Q5G
單堂(CI/CD)https://hiskio.com/courses/385?promo_code=13K49YE&p=blog1
基礎概念https://hiskio.com/courses/349?promo_code=13LY5RE
另外,歡迎按讚加入我個人的粉絲專頁,裡面會定期分享各式各樣的文章,有的是翻譯文章,也有部分是原創文章,主要會聚焦於 CNCF 領域https://www.facebook.com/technologynoteniu
如果有使用 Telegram 的也可以訂閱下列頻道來,裡面我會定期推播通知各類文章https://t.me/technologynote
你的捐款將給予我文章成長的動力