Kubernetes資源編排系列之三: Kustomize篇

語言: CN / TW / HK

作者 艄公(楊京華) 雪堯(郭耀星)

這是我們的《Kubernetes資源編排系列》的第三篇——Kustomize篇,在上篇(《Kubernetes資源編排系列之二: Helm篇》,可從文末鏈接直達)我們見識到了Helm強大的管理能力,但是Helm對於服務的定製僅限於預置變量,那麼如果需要更多更靈活的YAML定製,有什麼辦法嗎?於是本篇我們來介紹一下Kustomize。

Kustomize是什麼

Kustomize是一套採用合併思想,對Kubernetes原生配置進行管理的工具,使用無模板的方案定義應用配置。允許用户使用一系列的描述文件為基礎,然後通過overlay的方式生成最終部署應用所需的描述文件。

Kustomize通過Base&Overlays方式維護不同環境的應用配置,在Overlay中描述差異來實現資源複用,管理的是Kubernetes原生YAML文件,不需要學習額外的 DSL 語法。

Kustomize是怎麼做的

Kustomize的文件結構如下:

app
├── base
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays
    ├── production
    │   └── kustomization.yaml
    ├── staging
    │   └── kustomization.yaml
    └── production-large
        └── kustomization.yaml

app/base/kustomization.yaml聲明資源及要應用於它們的一些自定義,如添加一個通用的標籤,其內容如下。kustomization 還提供了namePrefix、commonAnnoations、images 等配置項

commonLabels:
  name: app
resources:
- deployment.yaml
- service.yaml

可以通過 kustomize build 命令來看完整的配置,build出來的每個資源對象上都會存在通用的標籤name: app。

kustomize build app/base  # 構建
kustomize build app/base | kubectl apply -f -  # 構建並部署
kubectl apply -k app/base # 1.14及更新的版本可以使用該命令直接部署

app/overlays/staging/kustomization.yaml中可以為演示環境定義不同的名稱前輟、標籤,通過patch的方案將副本數設置為1

bases:
- ../../base
commonLabels:
  env: staging
namePrefix: staging-
patches:
  - target:
      kind: Deployment
      name: app
    patch: |
      [
        {"op":"replace","path":"/spec/replicas","value":1}
      ]

app/overlays/production/kustomization.yaml中可以為生產環境定義不同的名稱前輟、標籤,通過patch的方案將副本數設置為2

bases:
- ../../base
commonLabels:
  env: production
namePrefix: production-
patches:
  - target:
      kind: Deployment
      name: app
    patch: |
      [
        {"op":"replace","path":"/spec/replicas","value":2}
      ]

app/overlays/production-large/kustomization.yaml中可以繼承生產環境的定義,同時將副本數設置為10支撐大規模場景需求。

bases:
- ../production
patches:
  - target:
      kind: Deployment
      name: app
    patch: |
      [
        {"op":"replace","path":"/spec/replicas","value":10}
      ]

通過不同的部署路徑,指定不同的環境部署

kustomize build app/overlays/production | kubectl apply -f -
kustomize build app/overlays/staging | kubectl apply -f -
kustomize build app/overlays/production-large | kubectl apply -f -

通過上面的例子我們可以看出,通過kustomization.yaml來聲明繼承和patch,可以為各種場景構造不同的YAML輸出,同時保持底座YAML不變化。

Kustomize的特點

Kustomize 的 Overlay 可以在 Base 的基礎上,通過對 resource / generator / transformer 等的定義,形成新的應用定義,不管是 Base 還是 Overlay,都可以通過 kustomize build 生成有效的 YAML

  • 功能簡單清晰,kubectl 直接內部支持
  • 不考慮派生,僅僅作為組件的 YAML組織方式也很有幫助
  • 也有自己的插件系統,例如可以用簡單的 YAML 定義,使用文件生成 ConfigMap / Secret 等
  • 允許注入 K8S 運行時數據

Kustomize和Helm的對比

Kustomize 相對於 Helm 而言,更加的輕量,只有一個 CLI 工具。也集成到了 kubectl 自身,使用及配置成本接近於 0。Kustomize 放棄了對模板的要求,改為參考 Docker 鏡像的形式,通過 Base + Overlay 的方式對應用的原始 YAML 進行派生。

  • Base YAML 管控:Helm 最大的特點是定製僅限於預先存在的配置選項。不僅如此,Chart 作者還必須用有點麻煩的模板化方式實現這些定製選項。這個時候 Kustomize 不受限制的 Overlay 會更加靈活,想怎麼覆蓋就怎麼覆蓋。所以 Helm 對 Base YAML 強管控;而Kustomize 雖然也有 Base,但 Overlay 的存在讓這個限制幾乎不存在。
  • 模板語法層面:Kustomize 相較於 Helm 去掉了模板語法,入門門檻更低,更易使用。當然如果玩的高階,兩者都要學習很多東西。
  • 部署層面:雖然 Kustomize 最為輕量,但因為 Helm3 取消了 Tiller 依賴,所以差別也不是很大,兩者都是二進制命令工具生成YAML後直接下發。
  • 工作流程上:
    • Helm: 定義 Chart -> 填充 -> 運行。在 Chart 中沒有定義的內容是無法更改的
    • Kustomize: Base 和 Overlay 都是可以獨立運作的,增加新對象,或者對編寫 Base 時未預料到的內容進行變更,都非常簡單

基於上述工作流程的對比,如果是要公開發佈一個複雜的組件,編寫一個複雜而設計良好的 Helm Chart 可以給用户很大幫助。用户在缺失了自由性之下,僅僅通過 values.yaml 的閲讀和配置就可以對這種複雜的部署產生一個較為深入的認知。

如果是常見的業務應用,雖然不同的部署之間差異不大(比如日常預發生產),但是因為快速迭代及需求變化,未必可以一開始就做好相關的變化限制,用 Kustomize 是更好的選擇。

對於承載應用 (Application) 這個概念而言,Kustomize 和 Helm 的短板是一致的,都沒有進一步提供包之間的依賴處理、外部資源申請及維護、變量間傳遞等能力。

對於承載組件 (Component) 這個概念而言,Kustomize 和 Helm 類似,都是合適的工具。雖然 Helm 和 Kustomize 在自身的能力和流程上有着很多區別,但最終流程都是:開發者(一堆 YAML) -> 合適的參數映射及渲染方式 -> 使用者(填參/覆蓋) -> apply 到目標 K8S 中。蘿蔔青菜,各有所愛。

SREWorks的Kustomize組件實踐

在SREWorks的appmanager中,將Kustomize與Helm並列放在一起成為一種組件類型,當前這種組件類型還未內置到出廠組件中,後續會上架到雲端市場,供用户插拔安裝。

- revisionName: "CHART|sreworks@[email protected]|_"
  parameterValues:
    - name: Map
      value:
        clusterId: "{{ Global.clusterId }}"
        product: es
        userID: "{{ Global.uid }}"
        vpcID: "{{ Global.vpcID }}"
        vswitchID: "{{ Global.vswitchID }}"
        namespaceRegexes: "^(essen|es)$"
- revisionName: KUSTOMIZE|[email protected]@test|_
  parameterValues:
    - name: kubeconfig
      value: "{{ Global.kubeconfig }}"
      toFieldPaths:
        - spec.base64Kubeconfig
    - name: path
      value: "./"
      toFieldPaths:
        - spec.path
  dependencies:
    - component: "CHART|sreworks@[email protected]"
- revisionName: "STATUS|KUSTOMIZE@esonack-cluster-baselines|_"
  dependencies:
    - component: KUSTOMIZE|[email protected]@test
  parameterValues:
    - name: kubeconfig
      value: "{{ Global.kubeconfig }}"
      toFieldPaths:
        - spec.base64Kubeconfig
    - name: options
      value:
        groups:
          - namespace: sreworks-system
            labels:
              app: sreworks
            resources:
              - v1/pods
      toFieldPaths:
        - spec.options

如上面所示,在appmanager中的OAM YAML中,插入Helm和Kustomize兩種組件,並且設置依賴關係,在Helm組件下發完成後,再進行Kustomize組件的下發;在Kustomize組件下發完成後,對核心Pod進行狀態探測,待Pod正常之後才算作部署完成。

總結

Kustomize 是一個通用工具,它的作用是對Kubernetes 資源進行定製後產生新的 YAML 文件,並保持原始的 YAML 文件不變。從這個意義上來説,你可以把 Kustomize 看成是 Kubernetes YAML 文件的轉換工具,類似 XML 和 XSLT 的關係。

Kustomize 的一個重要特徵是不使用模板,而是直接工作在原始的 YAML 文件上。這一點與 Helm 是不同的。不使用模板好處在於簡單易懂,不需要掌握複雜的模板語法,而Helm的YAML文件基本都被預置變量摳得毫無可讀性。

Kustomize 的另外一個優勢是集成在 kubectl 中,這就意味着不需要安裝額外的工具就可以進行定製。需要注意的是,由於實現上的原因,kubectl 自帶的 kustomize 的版本比較低,目前仍然需要安裝單獨的 Kustomize 工具。這個問題要到 1.20 版本才會解決。

後續文章我們會分享更多的Kubernetes組件和應用管理工具,均會發布在我們的公眾號“阿里智能運維”上,請大家持續關注~也歡迎大家在公眾號後台留言想了解的內容和感興趣的相關話題,與SREWorks團隊進行交流。