Kustomize 簡介
Kubernetes 原生配置管理工具, 它自定義引入了一種無需模板的方式來定製應用程式配置,從而簡化了對現成應用程式的使用。目前,在kubectl
中內建了,透過 apply -k
即可使用。
Kustomize 遍歷 Kubernetes 清單以新增、刪除或更新配置選項,而無需分叉。它既可以作為獨立的二進位制檔案使用,也可以作為kubectl
的原生特性使用。
Kustomize 優勢
- ? 完全宣告式的配置定製方法
- ? 原生構建進
kubectl
中 - ? 管理任意數量的獨特定製的 Kubernetes 配置
- ☸ 作為獨立的二進位制檔案提供,用於擴充套件和整合到其他服務
- ? 定製使用的每個工件都是純 YAML,並且可以被驗證和處理
- ? Kustomize 支援 fork/modify/rebase 工作流
- ? GitOps 工具(如 ArgoCD) 對其的完美支援
Kustomize 可以做什麼
?️ Reference:
?️URL: https://mp.weixin.qq.com/s/gmwkoqZpKbq1hM0B8XxQNw
在 Kubernetes 中我們使用 YAML 檔案來宣告我們的應用應該如何部署到底層的叢集中,這些 YAML 檔案中包含應用定義、治理需要的標籤、日誌、安全上下文定義、資源依賴關係等,當我們應用擴充套件到成百上千個 Pod 以後,管理這些 YAML 檔案就會成為一場噩夢了。
最典型的就是,有很多專案要管理,同時又有多套不同的部署環境:開發環境、測試環境、UAT 環境、生產環境。甚至可能有不同的公有云 Kubernetes 發行版。那麼每一套環境都需要一套各種各樣的 YAML 檔案, 但是它們直接只有部分細節有差異。比如:映象 Tag,服務 Name,Label,有沒有儲存等。
如果全是手動,維護工作量非常巨大,同時也容易出錯。
Kustomize 相比 Helm, 更適合解決這種場景的痛點:有一個基礎(base)的模板管理一個專案的所有基礎 YAML,更多高階的需求透過 overlay 來實現疊加覆蓋。
另外還有一類典型場景,就是融合來自不同使用者的配置資料(例如來自 devops/SRE 和 developers).
同時也可以結合 helm, 進行一些更高階的配置。
今天就以一個典型場景為例:生產環境 Deployment 自動注入商業(如:AppDynamics) 或開源 (SkyWalking/pinpoint) 的開箱即用的 Java Agent.
實戰 - 透過 Kustomize 注入監控 APM Agent
背景概述
以 Java 為例,這裡的 APM Agent 包是商業(如:AppDynamics) 或開源 (SkyWalking/pinpoint) 產品提供的開箱即用的 Agent jar 包。
在 Kubernetes 場景中,出於以下幾點考慮:
- 和應用映象分離;
- 複用
Agent jar 包做成了一個通用映象,透過 init container 方式複製到執行中的應用容器中,並透過配置環境變數進行引數的自動設定。
✍️ 筆者注:
其實商業 APM 都有 Helm 或 Operator 實現自動化安裝配置的功能,但是實際使用中體驗不佳,不太適合我們的實際場景。
透過 Kustomize 注入監控 APM Agent 步驟
步驟簡述如下:(以 AppDynamics Java Agent 為例)
- 獲取原始的 Deployment yaml 檔案(透過
kubectl
和kubectl neat
外掛) - 透過 Kustomize 對每個 Deployment 透過
patches
實現以下步驟:- 注入
initContainers
:appd-agent-attach-java
, 該initContainers
有:volumeMounts
: 把 java agent jar 包掛載到 volume 實現共享;
- 在 Deployment -> 應用自己的 container 中,加入以下引數:
volumeMounts
: 把 java agent jar 包掛載到 volume 實現共享;- 加入各種 AppD Java agent 需要的 env 資訊;
volumes
透過 tmpdir 實現共享。
- 注入
Kustomize 目錄結構
目錄結構如下:
inject-appd-agent/
├── base
│ └── kustomization.yaml
├── overlays
└── prod
├── appd_agent.yaml
└── kustomization.yaml
其中,後續所有需要注入 APM Agent 的應用的 Deployment, 都放在 base
目錄中。
base/kustomization.yaml
resources:
- ./foo-deployment.yml
?注意:
這裡提一句,目前的 resources
是不支援檔案萬用字元 (file glob) 匹配的,具體 issue 可以見這裡:
但是有個臨時解決方案,就是透過執行命令:kustomize edit add resource base/*.yml
執行後會遍歷 file blob, 將結果一個個加到 kustomization.yaml
中。
執行後的檔案可能是這樣:
resources:
- ./foo-deployment.yml
- ./bar-deployment.yml
- ./a-deployment.yml
- ./b-deployment.yml
- ./c-deployment.yml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
overlays/prod/kustomization.yaml
bases:
- ../../base
# patchesStrategicMerge:
# - appd_agent.yaml
patches:
- path: appd_agent.yaml
target:
kind: Deployment
? 注意:
這裡沒用 patchesStrategicMerge
, 而是用了patches
. 目的就是為了批次 patch. 上面 YAML 的意思是,將appd_agent.yaml
應用於所有的 Deployment manifests 中。
overlays/prod/appd_agent.yaml
具體內容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-important
spec:
template:
spec:
containers:
- name: app
volumeMounts:
- mountPath: /opt/appdynamics-java
name: appd-agent-repo-java
env:
- name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
value: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
- name: APPDYNAMICS_CONTROLLER_HOST_NAME
value: 192.168.1.10
- name: APPDYNAMICS_CONTROLLER_PORT
value: '8090'
- name: APPDYNAMICS_CONTROLLER_SSL_ENABLED
value: 'false'
- name: APPDYNAMICS_AGENT_ACCOUNT_NAME
value: my_account
- name: APPDYNAMICS_AGENT_APPLICATION_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: APPDYNAMICS_AGENT_TIER_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: JAVA_TOOL_OPTIONS
value:
' -Dappdynamics.agent.accountAccessKey=$(APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY)
-Dappdynamics.agent.reuse.nodeName=true -Dappdynamics.socket.collection.bci.enable=true
-javaagent:/opt/appdynamics-java/javaagent.jar'
- name: APPDYNAMICS_NETVIZ_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: APPDYNAMICS_NETVIZ_AGENT_PORT
value: '3892'
initContainers:
- command:
- cp
- -r
- /opt/appdynamics/.
- /opt/appdynamics-java
image: appdynamics/appdynamics-java-agent:1.8-21.11.3.33314
imagePullPolicy: IfNotPresent
name: appd-agent-attach-java
resources:
limits:
cpu: 200m
memory: 75M
requests:
cpu: 100m
memory: 50M
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /opt/appdynamics-java
name: appd-agent-repo-java
volumes:
- name: appd-agent-repo-java
上面內容就不詳細說明瞭,具體可以參考這篇文章,瞭解 APM Agent 注入的幾種思路:
? 注意:
實踐中,上面內容有幾點需要注意的:
-
spec/template/spec/containers/name
這裡往往是應用的名字,如foo
, 如果appd_agent.yaml
的內容要正確地 patch, 也需要寫上同樣的 container name; 這對於一個應用來說不是什麼問題,但是對於批次自動化/GitOps 來說,就非常不方便。- 我之前想用 Kustomize 中的
nameReference
來實現,但是沒搞出來,有知道的可以教教我 - ✔️20220706 11:00 update: Kustomize 出於安全考慮, 是嚴格按照
metadata.name
進行 merge 的, 所以透過 Kustomize 無法解決; 但是可以透過yq
(類似jq, 但是針對 yaml)來解決, 示例命令為:i=foo yq -i '.spec.template.spec.containers[0].name="strenv(i)"' appd_agent.yaml
- 我之前想用 Kustomize 中的
-
之前的環境變數,手動部署的時候如這個:
- name: APPDYNAMICS_AGENT_APPLICATION_NAME value: foo
直接寫死,這樣不便於批次自動化/GitOps. 解決辦法就是利用 Kubernetes env 的
valueFrom
能力。改為如下就可以了。valueFrom: fieldRef: fieldPath: metadata.name
-
appd_agent.yaml
的 Deployment name 是無所謂的,因為仍會是被 patch 清單的名字;另外appd_agent.yaml
也不要帶namespace
, 方便批次自動化/GitOps, 可以適應所有 NameSpace.
自動化指令碼
最後,自動化指令碼 demo 如下:(假設指令碼位於 /inject-appd-agent/scripts/
目錄下)
#!/bin/bash
# USAGE:
# bash inject-appd-agent.sh default
# NAMESPACE=default
NAMESPACE=$1
# only get deploy name
deployments=$(kubectl get deploy --no-headers=true -o custom-columns=:.metadata.name -n "${NAMESPACE}")
for i in ${deployments}; do
# get deploy yaml
cd ../base && kubectl get deploy -n "${NAMESPACE}" "${i}" -o yaml | kubectl neat >./"${i}.yml"
# add the deploy yaml to base
kustomize edit add resource ./"${i}.yml"
# change appd_agent.yaml .spec.template.spec.containers[0].name
# = <the deploy name>
cd ../overlays/prod && DEPLOY="${i}" yq -i '.spec.template.spec.containers[0].name = strenv(DEPLOY)' ./appd_agent.yaml
# dry run
# kustomize build . >../../examples/output/"${i}.yml"
# deploy rollout
kubectl apply -k .
# remove the deploy yaml resource from base
cd ../../base && kustomize edit remove resource ./"${i}.yml"
done
# clean up
kustomize edit remove resource ./*.yml
cd ../overlays/prod && yq -i '.spec.template.spec.containers[0].name = "app"' ./appd_agent.yaml
執行上面指令碼,即可實現對所有 Deployment 自動注入 AppD Java Agent, 並 Rollout 生效。
???
?️ Reference
- Kustomize - Kubernetes native configuration management
- K8S 實用工具之四 - kubectl 實用外掛 - 東風微鳴技術部落格 (ewhisper.cn)
三人行, 必有我師; 知識共享, 天下為公. 本文由東風微鳴技術部落格 EWhisper.cn 編寫.