1.背景
在Kubernetes v1.14版本的發布說明中,kustomize 成為了 kubectl 內置的子命令,並說明了 kustomize 使用 Kubernetes 原生概念幫助用戶創作並復用聲明式配置。
那么,kustomize 出現的原因是什么?在kustomize的github issue中找到了 kustomize 啟發來自一篇Kubernetes聲明性應用程序管理,這篇文章內容很多,主要提出了Kubernetes應用的配置規范,聲明式配置的優點以及參數化定制配置的缺陷以及一些改進方案。
在kustomize出現之前,Kubernetes管理應用的方式主要是通過Helm或者上層Paas 來完成。這些工具通常通過特定領域配置語言(DSL,如Go template、jsonnet) 來維護並管理應用,並且需要參數化模板方式(如 helm) 來自定義配置,這需要學習復雜的DSL語法及容易出錯。
2.kustomize是什么?
來看看官網的描述:
Kubernetes native configuration management
Kustomize introduces a template-free way to customize application configuration that simplifies the use of off-the-shelf applications. Now, built into kubectl as apply -k.
根據官網的描述:kustomize 是 kubernetes 原生的配置管理,以無模板方式來定制應用的配置。kustomize使用k8s原生概念幫助創建並復用資源配置(YAML),允許用戶以一個應用描述文件(YAML 文件)為基礎(Base YAML),然后通過 Overlay 的方式生成最終部署應用所需的描述文件。
3.kustomize解決了什么痛點?
一般應用都會存在多套部署環境:開發環境、測試環境、生產環境,多套環境意味着存在多套K8S應用資源YAML。而這么多套YAML之間只存在微小配置差異,比如鏡像版本不同、Label不同等,而這些不同環境下的YAML 經常會因為人為疏忽導致配置錯誤。再者,多套環境的YAML維護通常是通過把一個環境下的YAML拷貝出來然后對差異的地方進行修改。一些類似Helm等應用管理工具需要額外學習DSL語法。總結以上,在k8s環境下存在多套環境的應用,經常遇到以下幾個問題:
- 如何管理不同環境或不同團隊的應用的Kubernetes YAML資源
- 如何以某種方式管理不同環境的微小差異,使得資源配置可以復用,減少copy and change的工作量
- 如何簡化維護應用的流程,不需要額外學習模板語法
Kustomize通過以下幾種方式解決了上述問題:
- kustomize通過Base & Overlays方式(下文會說明)方式維護不同環境的應用配置
- kustomize使用patch方式復用Base配置,並在Overlay描述與Base應用配置的差異部分來實現資源復用
- kustomize管理的都是Kubernetes原生YAML文件,不需要學習額外的DSL語法
4.kustomize術語
在 kustomize 項目的文檔中,經常會出現一些專業術語,這里總結一下常見的術語,方便后面講解
- kustomization
術語kustomization指的是kustomization.yaml文件,或者指的是包含 kustomization.yaml文件的目錄以及它里面引用的所有相關文件路徑
- base
base指的是一個kustomization , 任何的kustomization 包括overlay(后面提到),都可以作為另一個kustomization的base(簡單理解為基礎目錄)。base中描述了共享的內容,如資源和常見的資源配置
- overlay
overlay是一個kustomization, 它修改(並因此依賴於)另外一個kustomization. overlay中的kustomization指的是一些其它的kustomization, 稱為其base.沒有base, overlay無法使用,並且一個overlay可以用作另一個overlay的base(基礎)。簡而言之,overlay聲明了與base之間的差異。通過overlay來維護基於base的不同variants(變體),例如開發、QA 和生產環境的不同variants
- variant
variant是在集群中將overlay應用於base的結果。例如開發和生產環境都修改了一些共同base以創建不同的variant。這些variant使用相同的總體資源,並與簡單的方式變化,例如deployment的副本數、ConfigMap使用的數據源等。簡而言之,variant是含有同一組base的不同kustomization
- resource
在kustomize的上下文中,resource是描述k8s API對象的YAML或JSON文件的相對路徑。即是指向一個聲明了kubernetes API對象的YAML文件
- patch
修改文件的一般說明。文件路徑,指向一個聲明了kubernetes API patch的YAML文件
5.kustomize 官方示例
現在通過官方的示例來演示一下kustomize應該怎么用,以及相應的一些規范。如果你沒有使用Kubernetes v1.14 版本,參考官方安裝教程進行安裝kustomize,或者直接下載 v1.14 版本kubectl二進制,通過kubectl -k命令使用kustomize。
官方更多實例地址: https://github.com/kubernetes-sigs/kustomize/tree/master/examples
官方配置項地址: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
5.1 ldap示例
1.新建一個Base目錄
首先創建工作目錄以及定義工作目錄變量等信息
DEMO_HOME=/test/ldap BASE=$DEMO_HOME/base mkdir -p $BASE CONTENT="https://raw.githubusercontent.com\ /kubernetes-sigs/kustomize\ /master/examples/ldap" curl -s -o "$BASE/#1" "$CONTENT/base\ /{deployment.yaml,kustomization.yaml,service.yaml,env.startup.txt}"
具體的代碼文件見以下,或者直接clonegit倉庫代碼。
#deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ldap labels: app: ldap spec: replicas: 1 selector: matchLabels: app: ldap template: metadata: labels: app: ldap spec: containers: - name: ldap image: osixia/openldap:1.1.11 args: ["--copy-service"] volumeMounts: - name: ldap-data mountPath: /var/lib/ldap - name: ldap-config mountPath: /etc/ldap/slapd.d - name: ldap-certs mountPath: /container/service/slapd/assets/certs - name: configmap-volume mountPath: /container/environment/01-custom - name: container-run mountPath: /container/run ports: - containerPort: 389 name: openldap volumes: - name: ldap-data emptyDir: {} - name: ldap-config emptyDir: {} - name: ldap-certs emptyDir: {} - name: "configmap-volume" configMap: name: "ldap-configmap" - name: container-run emptyDir: {} #service.yaml apiVersion: v1 kind: Service metadata: labels: app: ldap name: ldap-service spec: ports: - port: 389 selector: app: ldap #kustomization.yaml resources: - deployment.yaml - service.yaml configMapGenerator: - name: ldap-configmap files: - env.startup.txt #env.startup.txt # This is the default image startup configuration file # this file define environment variables used during the container **first start** in **startup files**. # This file is deleted right after startup files are processed for the first time, # after that all these values will not be available in the container environment. # This helps to keep your container configuration secret. # more information : https://github.com/osixia/docker-light-baseimage # Required and used for new ldap server only LDAP_ORGANISATION: Example Inc. LDAP_DOMAIN: example.org LDAP_BASE_DN: #if empty automatically set from LDAP_DOMAIN LDAP_ADMIN_PASSWORD: admin LDAP_CONFIG_PASSWORD: config LDAP_READONLY_USER: false LDAP_READONLY_USER_USERNAME: readonly LDAP_READONLY_USER_PASSWORD: readonly LDAP_RFC2307BIS_SCHEMA: false # Backend LDAP_BACKEND: hdb # Tls LDAP_TLS: true LDAP_TLS_CRT_FILENAME: ldap.crt LDAP_TLS_KEY_FILENAME: ldap.key LDAP_TLS_CA_CRT_FILENAME: ca.crt LDAP_TLS_ENFORCE: false LDAP_TLS_CIPHER_SUITE: SECURE256:+SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2:-RSA:-DHE-DSS:-CAMELLIA-128-CBC:-CAMELLIA-256-CBC LDAP_TLS_VERIFY_CLIENT: demand # Replication LDAP_REPLICATION: false # variables $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD, $LDAP_CONFIG_PASSWORD # are automaticaly replaced at run time # if you want to add replication to an existing ldap # adapt LDAP_REPLICATION_CONFIG_SYNCPROV and LDAP_REPLICATION_DB_SYNCPROV to your configuration # avoid using $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD and $LDAP_CONFIG_PASSWORD variables LDAP_REPLICATION_CONFIG_SYNCPROV: binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="60 +" timeout=1 starttls=critical LDAP_REPLICATION_DB_SYNCPROV: binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical LDAP_REPLICATION_HOSTS: - ldap://ldap.example.org # The order must be the same on all ldap servers - ldap://ldap2.example.org # Do not change the ldap config # - If set to true with an existing database, config will remain unchanged. Image tls and replication config will not be run. # The container can be started with LDAP_ADMIN_PASSWORD and LDAP_CONFIG_PASSWORD empty or filled with fake data. # - If set to true when bootstrapping a new database, bootstap ldif and schema will not be added and tls and replication config will not be run. KEEP_EXISTING_CONFIG: false # Remove config after setup LDAP_REMOVE_CONFIG_AFTER_SETUP: true # ssl-helper environment variables prefix LDAP_SSL_HELPER_PREFIX: ldap # ssl-helper first search config from LDAP_SSL_HELPER_* variables, before SSL_HELPER_* variables.
ldap代碼准備完成后文件結構如下:
ldap
└── base
├── deployment.yaml
├── env.startup.txt
├── kustomization.yaml
└── service.yaml
接下來看看kustomization.yaml配置文件中包含什么內容:
resources: - deployment.yaml - service.yaml configMapGenerator: - name: ldap-configmap files: - env.startup.txt
這個文件聲明了這些YAML資源(deployments、services、configmap 等)以及要應用於它們的一些自定義,如添加一個通用的標簽。kustomization還提供namePrefix、commonAnnoations、images等配置項.
這時候,可以通過kustomize build命令來看完整的配置:
$ kustomize build $BASE # build 出來的 YAML 太長就不貼處理了 $ kustomize build $BASE | kubectl apply -f - # 這種方式直接部署在集群中 $ kubectl apply -k # 1.14 版本可以直接使用該命令部署應用於集群中
2.創建Overlays
創建一個staging和production overlay,目錄樹結構如下所示:
OVERLAYS=$DEMO_HOME/overlays mkdir -p $OVERLAYS/staging mkdir -p $OVERLAYS/production
創建完成后目錄樹格式如下:
ldap
├── base
│ ├── deployment.yaml
│ ├── env.startup.txt
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── production
└── staging
演示環境 kustomization
下載staging customization and patch
curl -s -o "$OVERLAYS/staging/#1" "$CONTENT/overlays/staging\ /{config.env,deployment.yaml,kustomization.yaml}"
Staging下所有代碼如下
#文件路徑: $OVERLAYS/staging/kustomization.yaml resources: - ../../base patchesStrategicMerge: - deployment.yaml namePrefix: staging- configMapGenerator: - name: env-config files: - config.env #文件路徑:$OVERLAYS/staging/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ldap spec: replicas: 2 #config.env DB_USERNAME=admin DB_PASSWORD=somepw
下面簡單簡述以下每個文件的作用
Staging添加configMap
#文件路徑: $OVERLAYS/staging/kustomization.yaml resources: - ../../base patchesStrategicMerge: - deployment.yaml namePrefix: staging- configMapGenerator: - name: env-config files: - config.env
已經增加2個副本
#文件路徑:$OVERLAYS/staging/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ldap spec: replicas: 2
生產環境Kustomization
下載 production customization and patch
curl -s -o "$OVERLAYS/production/#1" "$CONTENT/overlays/production\ /{deployment.yaml,kustomization.yaml}"
下面也簡述以下各文件代碼的作用,可以看到生產環境增加了6個副本以及gce磁盤
#文件路徑:$OVERLAYS/production/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ldap spec: replicas: 6 template: spec: volumes: - name: ldap-data emptyDir: null gcePersistentDisk: pdName: ldap-persistent-storage #文件路徑:$OVERLAYS/production/kustomization.yaml resources: - ../../base patchesStrategicMerge: - deployment.yaml namePrefix: production-
3.配置區別對比
目錄下現在包含:
-
- a base directory - 對原始配置進行稍微定制的克隆
- an overlays directory,包含在集群中創建不同的登台和生產變體所需的kustomizations和補丁。
查看一下最終結構目錄
tree $DEMO_HOME /test/ldap ├── base │ ├── deployment.yaml │ ├── env.startup.txt │ ├── kustomization.yaml │ └── service.yaml └── overlays ├── production │ ├── deployment.yaml │ └── kustomization.yaml └── staging ├── config.env ├── deployment.yaml └── kustomization.yaml
直接比較輸出,看看staging和production有何不同:
diff \ <(kustomize build $OVERLAYS/staging) \ <(kustomize build $OVERLAYS/production) |\ more
差異如下
3,11d2 < config.env: | < DB_USERNAME=admin < DB_PASSWORD=somepw < kind: ConfigMap < metadata: < name: staging-env-config-42m8gk5kg2 < --- < apiVersion: v1 < data: 76c67 < name: staging-ldap-configmap-4d7m6k5b42 --- > name: production-ldap-configmap-4d7m6k5b42 83c74 < name: staging-ldap-service --- > name: production-ldap-service 95c86 < name: staging-ldap --- > name: production-ldap 97c88 < replicas: 2 --- > replicas: 6 126c117,118 < - emptyDir: {} --- > - gcePersistentDisk: > pdName: ldap-persistent-storage 133c125 < name: staging-ldap-configmap-4d7m6k5b42 --- > name: production-ldap-configmap-4d7m6k5b42
4.部署不同環境
需要在生產環境部署應用,通過下面命令
$ kustomize build $OVERLAYS/staging | kubectl apply -f - # 或者 kubectl apply -k
需要在演示環境部署應用,通過下面命令
$ kustomize build $OVERLAYS/production | kubectl apply -f - # 或者 kubectl apply -k
5.2 helloWorld示例
1.新建一個Base目錄
首先創建工作目錄以及定義工作目錄變量等信息
DEMO_HOME=/test/hello BASE=$DEMO_HOME/base mkdir -p $BASE curl -s -o "$BASE/#1.yaml" "https://raw.githubusercontent.com\ /kubernetes-sigs/kustomize\ /master/examples/helloWorld\ /{configMap,deployment,kustomization,service}.yaml"
具體的代碼文件見以下,或者直接clonegit倉庫代碼。
#configMap.yaml apiVersion: v1 kind: ConfigMap metadata: name: the-map data: altGreeting: "Good Morning!" enableRisky: "false" #deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: the-deployment spec: replicas: 3 selector: matchLabels: deployment: hello template: metadata: labels: deployment: hello spec: containers: - name: the-container image: monopole/hello:1 command: ["/hello", "--port=8080", "--enableRiskyFeature=$(ENABLE_RISKY)"] ports: - containerPort: 8080 env: - name: ALT_GREETING valueFrom: configMapKeyRef: name: the-map key: altGreeting - name: ENABLE_RISKY valueFrom: configMapKeyRef: name: the-map key: enableRisky #service.yaml kind: Service apiVersion: v1 metadata: name: the-service spec: selector: deployment: hello type: LoadBalancer ports: - protocol: TCP port: 8666 targetPort: 8080 #kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization metadata: name: arbitrary # Example configuration for the webserver # at https://github.com/monopole/hello commonLabels: app: hello resources: - deployment.yaml - service.yaml - configMap.yaml
這里使用官網的helloWorld的YAML資源文件作為示例,代碼准備完成后文件結構如下:
hello
└── base
├── configMap.yaml
├── deployment.yaml
├── kustomization.yaml
└── service.yaml
接下來看看kustomization.yaml配置文件中包含什么內容:
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization metadata: name: arbitrary # Example configuration for the webserver # at https://github.com/monopole/hello commonLabels: app: hello resources: - deployment.yaml - service.yaml - configMap.yaml
這個文件聲明了這些YAML資源(deployments、services、configmap 等)以及要應用於它們的一些自定義,如添加一個通用的標簽。kustomization還提供namePrefix、commonAnnoations、images等配置項,全部配置在github的示例中。
這時候,可以通過kustomize build命令來看完整的配置:
$ kustomize build $BASE # build 出來的 YAML 太長就不貼處理了 $ kustomize build $BASE | kubectl apply -f - # 這種方式直接部署在集群中 $ kubectl apply -k # 1.14 版本可以直接使用該命令部署應用於集群中
build出來的YAML每個資源對象上都會存在通用的標簽app:hello
2.創建Overlays
創建一個staging和production overlay,目錄樹結構如下所示:
OVERLAYS=$DEMO_HOME/overlays mkdir -p $OVERLAYS/staging mkdir -p $OVERLAYS/production
創建完成后目錄樹格式如下:
hello
├── base
│ ├── configMap.yaml
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── production
└── staging
演示環境 kustomization
在staging kustomization文件中,定義一個新的名稱前輟以及一些不同的標簽
#文件路徑: $OVERLAYS/staging/kustomization.yaml cat <<'EOF' > $OVERLAYS/staging/kustomization.yaml namePrefix: staging- #定義的 yaml 文件中為名稱添加前綴 commonLabels: #為資源添加標簽和選擇器。如果資源上已存在標簽鍵,則該值將被覆蓋。 variant: staging org: acmeCorporation commonAnnotations: #為資源添加注釋。如果資源上已存在注釋鍵,則該值將被覆蓋。 note: Hello, I am staging! bases: - ../../base patchesStrategicMerge: #補丁文件來源,若有相同配置,就覆蓋 - map.yaml EOF
演示環境 patch
添加一個ConfigMap自定義把base中的ConfigMap中的 "Good Morning!" 變成" Have a pineapple!"
#文件路徑: $OVERLAYS/staging/map.yaml cat <<EOF >$OVERLAYS/staging/map.yaml apiVersion: v1 kind: ConfigMap metadata: name: the-map data: altGreeting: "Have a pineapple!" enableRisky: "true" EOF
生產環境 kustoimzation
在生產環境目錄下,創建一個kustomization.yaml文件,定義不同的名稱及標簽
#文件路徑:$OVERLAYS/production/kustomization.yaml cat <<EOF >$OVERLAYS/production/kustomization.yaml namePrefix: production- commonLabels: variant: production org: acmeCorporation commonAnnotations: note: Hello, I am production! bases: - ../../base patchesStrategicMerge: - deployment.yaml EOF
生產環境 patch
創建一個生產環境的 patch, 定義增加副本數量
#文件路徑:$OVERLAYS/production/deployment.yaml cat <<EOF >$OVERLAYS/production/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: the-deployment spec: replicas: 10 EOF
3.配置區別對比
目錄下現在包含:
-
- a base directory - 對原始配置進行稍微定制的克隆
- an overlays directory,包含在集群中創建不同的登台和生產變體所需的kustomizations和補丁。
查看一下最終結構目錄
tree $DEMO_HOME
hello
├── base
│ ├── configMap.yaml
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── production
│ ├── deployment.yaml
│ └── kustomization.yaml
└── staging
├── kustomization.yaml
└── map.yaml
直接比較輸出,看看staging和production有何不同:
diff \ <(kustomize build demo/overlays/staging) \ <(kustomize build demo/overlays/production) |\ more
差異如下
< altGreeting: Have a pineapple! < enableRisky: "true" --- > altGreeting: Good Morning! > enableRisky: "false" 8c8 < note: Hello, I am staging! --- > note: Hello, I am production! 11c11 < variant: staging --- > variant: production 13c13 (...truncated)
4.部署不同環境
需要在生產環境部署應用,通過下面命令
$ kustomize build demo/overlays/production | kubectl apply -f - # 或者 kubectl apply -k
需要在演示環境部署應用,通過下面命令
$ kustomize build demo/overlays/staging | kubectl apply -f - # 或者 kubectl apply -k
6.workflows工作流
kustomize將對Kubernetes應用的管理轉換成對Kubernetes manifests YAML文件的管理,而對應用的修改也通過YAML文件來修改。這種修改變更操作可以通過Git版本控制工具進行管理維護, 因此用戶可以使用Git風格的流程來管理應用。workflows是使用並配置應用所使用的一系列Git風格流程步驟。官網提供了兩種方式,一種是定制配置,另一種是現成配置
1.定制配置
在這個工作流中,所有的配置(YAML 文件)都屬於用戶所有。

通過上面兩種工作流方式,可以實現自定義管理應用的聲明式資源文件,或者基於別人的應用聲明式資源進行自定義修改
# 定制工作流步驟如下: 1、創建一個目錄用於版本管理 git init ~/ldap 2、創建一個 base mkdir -p ~/ldap/base # 在這個目錄中創建並提交 kustomization.yaml 文件和一組資源,例如 deployment、service 3、創建 overlays mkdir -p ~/ldap/overlays/staging mkdir -p ~/ldap/overlays/production 4、生成 variants kustomize build ~/ldap/overlays/staging | kubectl apply -f - kustomize build ~/ldap/overlays/production | kubectl apply -f - kubectl v1.14 版使用下面: kubectl apply -k ~/ldap/overlays/staging kubectl apply -k ~/ldap/overlays/production
2.現成配置
在這個工作流方式中,可從別人的repo中fork kustomize配置,並根據自己的需求來配置

# 現成配置工作流步驟如下: 1、通過 fork 方式獲得現成配置 2、clone 作為你的 base mkdir ~/ldap git clone https://github.com/$USER/ldap ~/ldap/base cd ~/ldap/base git remote add upstream git@github.com:$USER/ldap 3、創建並填充 overlays mkdir -p ~/ldap/overlays/staging mkdir -p ~/ldap/overlays/production 4、生成 variants kustomize build ~/ldap/overlays/staging | kubectl apply -f - kustomize build ~/ldap/overlays/production | kubectl apply -f - 5、(可選)更新上游配置,用戶可以定期更新他的 base, 以更新上游所做的修改 cd ~/ldap/base git fetch upstream git rebase upstream/master
通過上面兩種工作流方式,可以實現自定義管理應用的聲明式資源文件,或者基於別人的應用聲明式資源進行自定義修改
7.kustomize vs Helm
通過上面對kustomize的講解,可能已經有人注意到它與Helm有一定的相似。先來看看Helm的定位:Kubernetes的包管理工具,而kustomize的定位是:Kubernetes原生配置管理。兩者定位領域有很大不同,Helm通過將應用抽象成Chart來管理, 專注於應用的操作、復雜性管理等, 而kustomize關注於k8s API對象的管理。下面列舉了一些它們之間的區別(不是特別全面):
- Helm 提供應用描述文件模板(Go template),在部署時通過字符替換方式渲染成YAML,對應用描述文件具有侵入性。Kustomize 使用原生k8s對象,無需模板參數化,無需侵入應用描述文件(YAML), 通過overlay選擇相應patch生成最終YAML
- Helm 專注於應用的復雜性及生命周期管理(包括 install、upgrade、rollback),kustomize 通過管理應用的描述文件來間接管理應用
- Helm 使用Chart來管理應用,Chart相對固定、穩定,相當於靜態管理,更適合對外交付使用,而kustomize管理的是正在變更的應用,可以fork一個新版本,創建新的overlay將應用部署在新的環境,相當於動態管理,適合於DevOps流程
- Helm 通過Chart方式打包並管理應用版本,kustomize通過overlay方式管理應用不同的變體,通過Git來版本管理
- Helm 在v3 版本前有 Helm 和 Tiller 兩組件,需要一定配置,而kustomize只有一個二進制,開箱即用
總的來說,Helm有自己一套體系來管理應用,而 kustomize 更輕量級,融Kubernetes的設計理念,通過原生 k8s API 對象來管理應用
8.總結
Kustomize給Kubernetes的用戶提供一種可以重復使用配置的聲明式應用管理,從而在配置工作中用戶只需要管理和維護Kubernetes的原生API對象,而不需要使用復雜的模版。同時,使用kustomzie可以僅通過Kubernetes聲明式 API 資源文件管理任何數量的kubernetes 定制配置,可以通過fork/modify/rebase 這樣的工作流來管理海量的應用描述文件。
