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

在 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 是那些喜歡在本地虛擬機器中執行 Kubernetes 的人的熱門選擇。最近,Docker for MacWindows 開始將 Kubernetes 作為實驗性軟體包(在“edge”通道中)釋出。您可能更喜歡使用 Minikube 而不是 Docker 桌面選項的一些原因是:

  • 您已經安裝並運行了 Minikube
  • 您寧願等到 Docker 釋出穩定版本
  • 您是 Linux 桌面使用者
  • 您是 Windows 使用者,但沒有帶有 Hyper-V 的 Windows 10 專業版

執行本地叢集允許人們離線工作,並且您無需為使用雲資源付費。雲提供商的成本通常相當實惠,並且存在免費套餐,但有些人寧願避免向經理批准這些成本,以及可能產生意外成本,例如,在週末將叢集保持執行。

一些開發人員更喜歡使用遠端 Kubernetes 叢集,這通常是為了獲得更大的計算和儲存容量,並更輕鬆地實現協作工作流程。這意味著您可以更輕鬆地請同事協助除錯或在團隊中共享應用程式訪問許可權。此外,對於某些開發人員來說,儘可能地映象生產環境可能至關重要,尤其是在涉及外部雲服務時,例如專有資料庫、物件儲存、訊息佇列、外部負載均衡器或郵件交付系統。

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

現在您對執行時環境的選項有了基本的瞭解,接下來讓我們看看如何迭代開發和部署您的應用程式。

行內工具

現在我們將審查允許您在 Kubernetes 上開發應用程式的工具,重點是最大限度地減少對現有工作流程的影響。我們努力提供公正的描述,包括使用每種工具的一般含義。

請注意,這是一個棘手的領域,因為即使是像 JSON 與 YAML 與 XML 或 REST 與 gRPC 與 SOAP 這樣的成熟技術,很多都取決於您的背景、偏好和組織設定。在 Kubernetes 生態系統中比較工具更難,因為事物發展非常迅速,幾乎每週都有新工具釋出;例如,僅在準備這篇文章期間,GitkubeWatchpod 就問世了。為了涵蓋這些新工具以及相關的現有工具,如 Weave Flux 和 OpenShift 的 S2I,我們計劃發表您正在閱讀的這篇博文的後續文章。

Draft

Draft 旨在幫助您開始將任何應用程式部署到 Kubernetes。它能夠根據應用程式的程式語言應用啟發式演算法,並生成 Dockerfile 和 Helm chart。然後它為您執行構建,並透過 Helm chart 將生成的映象部署到目標叢集。它還允許使用者非常輕鬆地設定埠轉發到 localhost。

影響

  • 使用者可以根據自己的喜好自定義 chart 和 Dockerfile 模板,甚至可以建立自定義包(包含 Dockerfile、chart 等)以備將來使用
  • 猜測任何應用程式的構建方式都不是非常簡單,在某些情況下,使用者可能需要調整 Draft 生成的 Dockerfile 和 Helm chart
  • 使用Draft 0.12.0 版或更早版本,使用者每次要測試更改時,都需要等待 Draft 將程式碼複製到叢集,然後執行構建,推送映象併發布更新的 chart;這可能很耗時,但它會導致為使用者所做的每個更改(無論是否提交到 git)生成一個映象
  • 截至 Draft 0.12.0 版,構建在本地執行
  • 使用者無法選擇 Helm 以外的部署工具
  • 它可以監視本地更改並觸發部署,但此功能預設未啟用
  • 它允許開發人員使用本地或遠端 Kubernetes 叢集
  • 部署到生產環境由使用者決定,Draft 作者推薦他們的另一個專案——Brigade
  • 可以替代 Skaffold,並與 Squash 一起使用

更多資訊

Skaffold

Skaffold 旨在為不同構建系統、映象倉庫和部署工具提供 CI 整合可移植性的工具。它與 Draft 不同,但有些可比。它具有生成清單的基本能力,但這並不是其突出特點。Skaffold 具有可擴充套件性,允許使用者在構建和部署應用程式的每個步驟中選擇工具。

影響

  • 模組化設計
  • 獨立於 CI 供應商工作,使用者不需要 Docker 或 Kubernetes 外掛
  • 無需 CI 即可工作,即從開發人員的筆記型電腦上
  • 它可以監視本地更改並觸發部署
  • 它允許開發人員使用本地或遠端 Kubernetes 叢集
  • 它可以用於生產部署,使用者可以配置他們更喜歡如何操作,併為每個目標環境提供不同型別的管道
  • 可以替代 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 會造成一定的網路延遲
  • 它透過基於 SSH 的 Sidecar 程序 sshuttle 提供連線
  • 更具侵入性的依賴注入模式,使用 LD_PRELOAD/DYLD_INSERT_LIBRARIES 也可用
  • 它最常用於遠端 Kubernetes 叢集,但也可以用於本地叢集

更多資訊

Ksync

Ksync 在本地機器和 Kubernetes 中執行的容器之間同步應用程式程式碼(和配置),類似於 OpenShift 中 oc rsync 的功能。它旨在透過消除構建和部署步驟來縮短應用程式開發的迭代時間。

影響

  • 它繞過了容器映象構建和版本控制
  • 編譯語言使用者必須在 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 守護程式進行本地映象構建。作為準備,請執行以下操作:

$ 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 相容

stock-con 部署和服務都新增一個 namespace 欄位,值為 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` 目錄中的程式碼,例如透過向 JSON 響應新增一個欄位來更新 `service.js` 中的 `/healthz` 端點程式碼,您應該會看到 Skaffold 注意到更改並建立新映象並部署它。最終螢幕將如下所示:

Skaffold Preview

現在您應該對不同的工具如何讓您在 Kubernetes 上開發應用程式有了一定的瞭解。如果您有興趣瞭解更多工具和/或方法,請檢視以下資源:

至此,我們結束了這篇關於如何在 Kubernetes 上開發應用程式的文章,希望您有所收穫,如果您有任何反饋和/或想指出您認為有用的工具,請透過 Twitter 告訴我們:IlyaMichael