本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

在 Kubernetes 上開發

您如何開發 Kubernetes 應用程式?也就是說,您如何編寫和測試一個應該在 Kubernetes 上運行的應用程式?本文重點介紹您可能需要注意的挑戰、工具和方法,以便成功地單獨或在團隊環境中編寫 Kubernetes 應用程式。

我們假設您是一位開發人員,您有自己喜歡的程式語言、編輯器/IDE 和可用的測試框架。總體目標是在為 Kubernetes 開發應用程式時,盡可能減少對您目前工作流程的變更。例如,如果您是 Node.js 開發人員,並且習慣於熱重新載入設定,也就是說,在您的編輯器中儲存時,正在運行的應用程式會自動更新,那麼處理容器和容器映像、容器登錄檔、Kubernetes 部署、觸發器等等,不僅會讓人感到不知所措,而且還會真正讓樂趣消失殆盡。

在下文中,我們將首先討論整體開發設定,然後回顧行業工具,最後但並非最不重要的是,實際演練三種範例工具,這些工具允許針對 Kubernetes 進行迭代式本機應用程式開發。

在哪裡運行您的叢集?

作為開發人員,您想要考慮您正在開發的 Kubernetes 叢集在哪裡運行,以及開發環境位於何處。從概念上講,有四種開發模式

Dev Modes

許多工具支援純離線開發,包括 Minikube、Docker for Mac/Windows、Minishift 以及我們在下面詳細討論的工具。有時,例如,在某些微服務已經在叢集中運行的微服務設定中,代理設定(將流量轉發到叢集和從叢集轉發流量)更為可取,Telepresence 是此類別中的一個範例工具。即時模式基本上意味著您正在針對遠端叢集進行建構和/或部署,最後,純線上模式意味著您的開發環境和叢集都是遠端的,例如 Eclipse CheCloud 9 就是這種情況。現在讓我們更仔細地看看離線開發的基礎知識:在本機運行 Kubernetes。

Minikube 是那些喜歡在本機 VM 中運行 Kubernetes 的人的熱門選擇。最近,Docker for MacWindows 開始將 Kubernetes 作為實驗性套件(在「edge」通道中)發布。您可能想要優先使用 Minikube 而不是 Docker 桌面選項的一些原因是

  • 您已經安裝並運行了 Minikube
  • 您寧願等到 Docker 發布穩定的套件
  • 您是 Linux 桌面使用者
  • 您是沒有安裝 Hyper-V 的 Windows 10 Pro 的 Windows 使用者

運行本機叢集允許人們離線工作,而且您不必為使用雲端資源付費。雲端供應商的成本通常相當實惠且存在免費層級,但是有些人寧願避免必須向他們的經理批准這些成本,以及可能產生意外成本,例如,在週末讓叢集保持運行時。

有些開發人員更喜歡使用遠端 Kubernetes 叢集,這通常是為了允許更大的計算和儲存容量,並更輕鬆地實現協作工作流程。這意味著您可以更輕鬆地拉攏同事來協助進行偵錯,或與團隊成員分享對應用程式的存取權。此外,對於某些開發人員來說,盡可能地鏡像生產環境可能至關重要,尤其是在涉及外部雲端服務時,例如,專有資料庫、物件儲存、訊息佇列、外部負載平衡器或郵件傳遞系統。

總之,您有充分的理由針對本機叢集以及遠端叢集進行開發。這很大程度上取決於您所處的階段:從早期的原型設計和/或單獨開發到整合一組更穩定的微服務。

現在您已經對運行時環境的選項有了基本的了解,讓我們繼續討論如何迭代地開發和部署您的應用程式。

行業工具

我們現在將回顧允許您在 Kubernetes 上開發應用程式的工具,重點是盡可能減少對您現有工作流程的影響。我們力求提供公正的描述,包括一般條款中使用每個工具的含義。

請注意,這是一個棘手的領域,因為即使對於已建立的技術,例如 JSON 與 YAML 與 XML 或 REST 與 gRPC 與 SOAP,很大程度上取決於您的背景、您的偏好和組織設定。在 Kubernetes 生態系統中比較工具甚至更困難,因為事情發展非常迅速,並且幾乎每週都會宣布新工具;例如,僅在準備這篇文章期間,就出現了 GitkubeWatchpod。為了涵蓋這些新工具以及相關的現有工具,例如 Weave Flux 和 OpenShift 的 S2I,我們計劃發布一篇後續部落格文章,作為您正在閱讀的這篇文章的延伸。

Draft

Draft 旨在幫助您開始將任何應用程式部署到 Kubernetes。它能夠應用啟發法來判斷您的應用程式是用哪種程式語言編寫的,並產生 Dockerfile 以及 Helm 圖表。然後,它為您運行建構,並透過 Helm 圖表將產生的映像部署到目標叢集。它還允許使用者非常輕鬆地設定連接埠轉發到 localhost。

含義

  • 使用者可以隨意自訂圖表和 Dockerfile 範本,甚至可以建立 自訂套件(包含 Dockerfile、圖表等),以供日後使用
  • 要猜測任何應用程式應該如何建構並不是很簡單,在某些情況下,使用者可能需要調整 Draft 產生的 Dockerfile 和 Helm 圖表
  • 使用 Draft 版本 0.12.0 或更舊版本,每次使用者想要測試變更時,他們都需要等待 Draft 將程式碼複製到叢集,然後運行建構、推送映像並發布更新的圖表;這可能很耗時,但它會導致為使用者所做的每個變更(無論是否已提交到 git)建立一個映像
  • 從 Draft 版本 0.12.0 開始,建構在本機執行
  • 使用者沒有選擇 Helm 以外的其他部署選項
  • 它可以監看本機變更並觸發部署,但預設情況下未啟用此功能
  • 它允許開發人員使用本機或遠端 Kubernetes 叢集
  • 部署到生產環境取決於使用者,Draft 作者建議他們的其他專案 - Brigade
  • 可以代替 Skaffold 使用,也可以與 Squash 一起使用

更多資訊

Skaffold

Skaffold 是一種旨在為 CI 整合提供與不同建構系統、映像登錄檔和部署工具的可攜性的工具。它與 Draft 不同,但又有些可比較。它具有產生資訊清單的基本功能,但這並不是一個突出的功能。Skaffold 是可擴展的,並讓使用者選擇在建構和部署其應用程式的每個步驟中使用的工具。

含義

  • 模組化設計
  • 獨立於 CI 供應商運作,使用者不需要 Docker 或 Kubernetes 外掛程式
  • 在沒有 CI 的情況下運作,即從開發人員的筆記型電腦運作
  • 它可以監看本機變更並觸發部署
  • 它允許開發人員使用本機或遠端 Kubernetes 叢集
  • 它可以Used to deploy to production, user can configure how exactly they prefer to do it and provide different kind of pipeline for each target environment
  • 可以代替 Draft 使用,也可以與大多數其他工具一起使用

更多資訊

Squash

Squash 由一個與 Kubernetes 完全整合的偵錯伺服器和一個 IDE 外掛程式組成。它允許您插入中斷點,並執行您在使用 IDE 偵錯應用程式時習慣執行的所有有趣操作。它透過允許您將偵錯工具附加到在 Kubernetes 叢集中運行的 Pod,將 IDE 偵錯體驗與您的 Kubernetes 叢集橋接起來。

含義

  • 可以獨立於您選擇的其他工具使用
  • 需要特權 DaemonSet
  • 與熱門 IDE 整合
  • 支援 Go、Python、Node.js、Java 和 gdb
  • 使用者必須確保容器映像內的應用程式二進位檔案已使用偵錯符號編譯
  • 可以與此處描述的任何其他工具組合使用
  • 它可以與本機或遠端 Kubernetes 叢集一起使用

更多資訊

Telepresence

Telepresence 使用雙向代理將在開發人員工作站上運行的容器與遠端 Kubernetes 叢集連接起來,並模擬叢集內環境,以及提供對組態地圖和密碼的存取權。它旨在透過消除將應用程式部署到叢集的需要,並利用本機容器來抽象網路和檔案系統介面,使其看起來好像應用程式正在叢集中運行,從而縮短容器應用程式開發的迭代時間。

含義

  • 可以獨立於您選擇的其他工具使用
  • 可以與 Squash 一起使用,儘管 Squash 必須用於叢集中的 Pod,而傳統/本機偵錯工具需要用於偵錯透過 Telepresence 連接到叢集的本機容器
  • Telepresence 會帶來一些網路延遲
  • 它透過 side-car 處理程序(sshuttle,基於 SSH)提供連線能力
  • 也提供更具侵入性的依賴注入模式,使用 LD_PRELOAD/DYLD_INSERT_LIBRARIES
  • 它最常用於遠端 Kubernetes 叢集,但也可以與本機叢集一起使用

更多資訊

Ksync

Ksync 在您的本機電腦和 Kubernetes 中運行的容器之間同步應用程式程式碼(和組態),類似於 oc rsync 在 OpenShift 中執行的操作。它旨在透過消除建構和部署步驟來縮短應用程式開發的迭代時間。

含義

  • 它繞過容器映像建構和修訂控制
  • 編譯語言使用者必須在 Pod 內部運行建構(待確認)
  • 雙向同步 – 遠端檔案複製到本機目錄
  • 每次遠端檔案系統更新時,容器都會重新啟動
  • 沒有安全功能 – 僅限開發
  • 利用 Syncthing,一個用於對等同步的 Go 程式庫
  • 需要特權 DaemonSet 在叢集中運行
  • 節點必須使用帶有 overlayfs2 的 Docker – 在撰寫本文時,不支援其他 CRI 實作

更多資訊

實際演練

在以下工具的實際演練中,我們將使用的應用程式是一個簡單的 股票市場模擬器,由兩個微服務組成

  • stock-gen 微服務以 Go 編寫,隨機產生股票資料,並透過 HTTP 端點 /stockdata 公開。第二個微服務 stock-con 是一個 Node.js 應用程式,它從 stock-gen 消耗股票資料流,並透過 HTTP 端點 /average/$SYMBOL 以及 /healthz 的健康檢查端點提供移動平均形式的聚合。

總體而言,應用程式的預設設定如下

Default Setup

在下文中,我們將針對上面討論的工具的代表性選擇進行實際演練:ksync、帶有本機建構的 Minikube 以及 Skaffold。對於每個工具,我們都會執行以下操作

  • 設定各自的工具,包括 stock-con 微服務的部署和本機消耗的準備工作。
  • 執行程式碼更新,也就是說,變更 stock-con 微服務中 /healthz 端點的原始碼,並觀察更新。

請注意,對於目標 Kubernetes 叢集,我們在本機使用了 Minikube,但如果您想繼續操作,也可以為 ksync 和 Skaffold 使用遠端叢集。

演練:ksync

作為準備工作,請安裝 ksync,然後執行以下步驟來準備開發設定

$ mkdir -p $(pwd)/ksync
$ kubectl create namespace dok
$ ksync init -n dok

基本設定完成後,我們就可以告訴 ksync 的本機用戶端監看特定的 Kubernetes 命名空間,然後我們建立一個規格來定義我們想要同步的內容(本機的目錄 $(pwd)/ksync 與容器中的 /app)。請注意,目標 Pod 是透過 selector 參數指定的

$ ksync watch -n dok
$ ksync create -n dok --selector=app=stock-con $(pwd)/ksync /app
$ ksync get -n dok

現在我們部署股票產生器和股票消費者微服務

$ kubectl -n=dok apply \
      -f https://raw.githubusercontent.com/kubernauts/dok-example-us/master/stock-gen/app.yaml
$ kubectl -n=dok apply \
      -f https://raw.githubusercontent.com/kubernauts/dok-example-us/master/stock-con/app.yaml

建立這兩個部署且 Pod 運行後,我們轉發 stock-con 服務以供本機消耗(在單獨的終端機工作階段中)

$ kubectl get -n dok po --selector=app=stock-con  \
                     -o=custom-columns=:metadata.name --no-headers |  \
                     xargs -IPOD kubectl -n dok port-forward POD 9898:9898

這樣我們應該能夠從我們的本機電腦消耗 stock-con 服務;我們透過定期檢查 healthz 端點的回應來做到這一點,如下所示(在單獨的終端機工作階段中)

$ watch curl localhost:9898/healthz

現在變更 ksync/stock-con 目錄中的程式碼,例如,透過在 JSON 回應中新增一個欄位來更新 service.js 中的 /healthz 端點程式碼,並觀察 Pod 如何更新以及 curl localhost:9898/healthz 命令的回應如何變更。總體而言,您最終應該得到如下所示的內容

Preview

演練:帶有本機建構的 Minikube

對於以下操作,您需要啟動並運行 Minikube,我們將利用 Minikube 內部 Docker Daemon 在本機建構映像。作為準備工作,請執行以下操作

$ git clone https://github.com/kubernauts/dok-example-us.git && cd dok-example-us
$ eval $(minikube docker-env)
$ kubectl create namespace dok

現在我們部署股票產生器和股票消費者微服務

$ kubectl -n=dok apply -f stock-gen/app.yaml
$ kubectl -n=dok apply -f stock-con/app.yaml

建立這兩個部署且 Pod 運行後,我們轉發 stock-con 服務以供本機消耗(在單獨的終端機工作階段中),並檢查 healthz 端點的回應

$ kubectl get -n dok po --selector=app=stock-con  \
                     -o=custom-columns=:metadata.name --no-headers |  \
                     xargs -IPOD kubectl -n dok port-forward POD 9898:9898 &
$ watch curl localhost:9898/healthz

現在變更 stock-con 目錄中的程式碼,例如,透過在 JSON 回應中新增一個欄位來更新 service.js 中的 /healthz 端點程式碼。完成程式碼更新後,最後一步是建構新的容器映像並啟動新的部署,如下所示

$ docker build -t stock-con:dev -f Dockerfile .
$ kubectl -n dok set image deployment/stock-con *=stock-con:dev

總體而言,您最終應該得到如下所示的內容

Local Preview

演練:Skaffold

若要執行此演練,您首先需要安裝 Skaffold。完成後,您可以執行以下步驟來準備開發設定

$ git clone https://github.com/kubernauts/dok-example-us.git && cd dok-example-us
$ kubectl create namespace dok

現在我們部署股票產生器(但不部署股票消費者微服務,這是透過 Skaffold 完成的)

$ kubectl -n=dok apply -f stock-gen/app.yaml

請注意,最初我們在執行 skaffold dev 時遇到了驗證錯誤,並且需要應用 Issue 322 中描述的修正程式。基本上,這意味著將 ~/.docker/config.json 的內容變更為

{
   "auths": {}
}

接下來,我們必須稍微修補 stock-con/app.yaml,使其與 Skaffold 一起使用

namespace 欄位新增到 stock-con 部署和服務,值為 dok。將容器規格的 image 欄位變更為 quay.io/mhausenblas/stock-con,因為 Skaffold 會動態管理容器映像標籤。

產生的 app.yaml 檔案 stock-con 如下所示

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  labels:
    app: stock-con
  name: stock-con
  namespace: dok
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: stock-con
    spec:
      containers:
      - name: stock-con
        image: quay.io/mhausenblas/stock-con
        env:
        - name: DOK_STOCKGEN_HOSTNAME
          value: stock-gen
        - name: DOK_STOCKGEN_PORT
          value: "9999"
        ports:
        - containerPort: 9898
          protocol: TCP
        livenessProbe:
          initialDelaySeconds: 2
          periodSeconds: 5
          httpGet:
            path: /healthz
            port: 9898
        readinessProbe:
          initialDelaySeconds: 2
          periodSeconds: 5
          httpGet:
            path: /healthz
            port: 9898
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: stock-con
  name: stock-con
  namespace: dok
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 9898
  selector:
    app: stock-con

開始開發之前的最後一步是設定 Skaffold。因此,在 stock-con/ 目錄中建立一個檔案 skaffold.yaml,內容如下

apiVersion: skaffold/v1alpha2
kind: Config
build:
  artifacts:
  - imageName: quay.io/mhausenblas/stock-con
    workspace: .
    docker: {}
  local: {}
deploy:
  kubectl:
    manifests:
      - app.yaml

現在我們準備好開始開發了。為此,請在 stock-con/ 目錄中執行以下命令

$ skaffold dev

以上命令會觸發 stock-con 映像的建構,然後進行部署。一旦 stock-con 部署的 Pod 運行,我們再次轉發 stock-con 服務以供本機消耗(在單獨的終端機工作階段中),並檢查 healthz 端點的回應

$ kubectl get -n dok po --selector=app=stock-con  \
                     -o=custom-columns=:metadata.name --no-headers |  \
                     xargs -IPOD kubectl -n dok port-forward POD 9898:9898 &
$ watch curl localhost:9898/healthz

如果您現在變更 stock-con 目錄中的程式碼,例如,透過更新 service.js 中的 /healthz 端點程式碼,方法是新增一個欄位到 JSON 回應,您應該會看到 Skaffold 注意到變更並建立新的映像並部署它。產生的畫面看起來會像這樣

Skaffold Preview

到目前為止,您應該已經對不同的工具如何讓您在 Kubernetes 上開發應用程式有所了解,如果您有興趣了解更多關於工具和/或方法的信息,請查看以下資源

透過這篇文章,我們總結了關於如何在 Kubernetes 上開發應用程式的步驟,我們希望您學到了一些東西,如果您有回饋意見和/或想要指出您認為有用的工具,請透過 Twitter 告訴我們:IlyaMichael