Secret 和 ConfigMap 資源對象是命名空間級別的。它們只能被同一命名空間中的 Pod 引用。所以有時候不得不手動為每個命名空間創建它們。
但有很多場景,我們想讓它們是全局的,至少可以是跨命名空間共享的 Secret 和 ConfigMap,例如這些場景:
所有命名空間都有相同的私有注冊表,避免為每個命名空間創建相同的 Secret
Kubeshere 中 Devops 項目中的 harbor 憑證、源代碼倉庫的憑證
如何自動化的在跨命名空間,甚至跨 Kubernetes 集群之間“同步”這些配置,有很多方法。本文就此用例討論,并用憑證在 Kubesphere Devops 項目之間同步做示例。
可選的方案
腳本
使用 jq
實現簡單的同步:
kubectl?get?secret?cure-for-covid-19?-n?china?-o?json?\|?jq?'del(.metadata["namespace","creationTimestamp","resourceVersion","selfLink","uid"])'?\|?kubectl?apply?-n?rest-of-world?-f?-
用 sed
實現簡單的同步:
kubectl?get?secret?cure-for-covid-19?-n?china?-o?json?\|?jq?'del(.metadata["namespace","creationTimestamp","resourceVersion","selfLink","uid"])'?\|?kubectl?apply?-n?rest-of-world?-f?-
上面這兩種可定制化不強,還是手動方式。
ClusterSecret
要跨命名空間自動共享或同步 Secret,可以使用 Python 開發的 ClusterSecret Operator:
https://github.com/zakkg3/ClusterSecret
ClusterSecret Operator 通過 ClusterSecret CRD 去管理。確保所有匹配的(包括新創建的) 命名空間都有可用的 Secret。ClusterSecret 上的任何更改都會更新所有相關的 Secret。刪除 ClusterSecret 也會刪除所有克隆的 Secret。
kubernetes-reflector
C#開發的 Kubernetes 反射器:
https://github.com/EmberStack/kubernetes-reflector
它將存儲在 Secret 中的憑據或證書自動傳播到所有命名空間并保持同步,修改源會更新所有副本。該擴展允許您通過注釋自動復制和保持跨命名空間的 Secret:
在源 Secret 上添加注釋:
annotations:reflector.v1.k8s.emberstack.com/reflection-auto-enabled:?"true"
這將在所有命名空間中創建密鑰的副本。您可以使用以下方法限制創建副本的命名空間:
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces:?"namespace-1,namespace-2,namespace-[0-9]*"
不足
Kubernetes-reflector 和 ClusterSecret 已經很強大,但還是美中不足。
ClusterSecret 不支持 ConfigMaps 的同步和跨集群的同步,只是簡單的通過 matchNamespace
和 avoidNamespaces
實現模糊的匹配和不匹配。
Kubernetes-reflector 不支持跨集群同步,也是通過正則表達式實現了目標命名空間的模糊匹配。
就項目的 README
來看,二者都不支持 label 選擇 namespace
,用戶在 Kubesphere 上創建 Devops 項目,不可能永遠遵循模糊匹配表達式。
Config Syncer
以前的名稱為 Kubed:
https://github.com/kubeops/config-syncer
Config Syncer 可以 保持 ConfigMaps 和 Secrets 在命名空間和集群之間同步。使用 Go 語言開發,官方文檔也比較細致。
參考官方文檔安裝:
https://appscode.com/products/kubed/v0.12.0/setup/install/
安裝 config-syncer
添加 Helm 倉庫和更新倉庫:
$?helm?repo?add?appscode?https://charts.appscode.com/stable/
$?helm?repo?update
搜索可用的最新安裝包:
#??helm?search?repo?appscode/kubed?--version?v0.13.2
NAME????????????CHART?VERSION???APP?VERSION?????DESCRIPTION
appscode/kubed??v0.13.2?????????v0.13.2?????????Config?Syncer?by?AppsCode?-?Kubernetes?daemon
拉取到本地并解壓:
helm?fetch??appscode/kubed?--version?v0.13.2
tar?-zxf?kubed-v0.13.2.tgz
cd?kubed/
修改 values.yaml:
config:#?Set?cluster-name?to?something?meaningful?to?you,?say,?prod,?prod-us-east,?qa,?etc.#?so?that?you?can?distinguish?notifications?sent?by?kubedclusterName:?dev#?If?set,?configmaps?and?secrets?from?only?this?namespace?will?be?syncedconfigSourceNamespace:?""#?kubeconfig?file?content?for?configmap?and?secret?syncerkubeconfigContent:?""
這里的 config.clusterName 默認為 unicorn,如果不修改,kubed 同步之后的資源對象的 label 上會為 kubed.appscode.com/origin.cluster: unicorn,所以出于規范考慮,建議集群名設置為真實的集群名。如果 kubed 只在本集群內同步,就不需要填寫 kubeconfigContent 了。
執行安裝:
$?helm?install?config-sync?-f?values.yaml??-n?kubed?--create-namespace?.
NAME:?config-sync
LAST?DEPLOYED:?Fri?May?20?19:43:00?2022
NAMESPACE:?kubed
STATUS:?deployed
REVISION:?1
TEST?SUITE:?None
NOTES:
To?verify?that?Config?Syncer?has?started,?run:kubectl?get?deployment?--namespace?kubed?-l?"app.kubernetes.io/name=kubed,app.kubernetes.io/instance=config-sync"
查看 Pod 啟動是否成功:
$?kubectl?get?pod?--namespace?kubed?-l?"app.kubernetes.io/name=kubed,app.kubernetes.io/instance=config-sync"
NAME?????????????????????????????????READY???STATUS????RESTARTS???AGE
config-sync-kubed-8687c98ffb-ldsvz???1/1?????Running???0??????????3m50s$?kubectl?get?deployment?--namespace?kubed?-l?"app.kubernetes.io/name=kubed,app.kubernetes.io/instance=config-sync"
NAME????????????????READY???UP-TO-DATE???AVAILABLE???AGE
config-sync-kubed???1/1?????1????????????1???????????3m53s
在 Kubesphere 中實踐
Kubeshere Devops 項目中的 harbor 憑證、源代碼倉庫的憑證,有時候每個項目都是一樣的,所以沒必要每次創建 Devops 項目都去手動創建憑證,一切都變的自動化才是正道。
Kyverno 規則
需要提前創建一個 Kyverno 規則,創建這個的目的下面會做說明。
cat?<<EOF?|?kubectl?apply?-f?-
apiVersion:?kyverno.io/v1
kind:?ClusterPolicy
metadata:generation:?10name:?mutate-credential-secret
spec:background:?truefailurePolicy:?Failrules:-?exclude:resources:namespaces:-?kubesphere-devops-systemgenerate:clone:?{}match:resources:kinds:-?Secretselector:matchLabels:kubed.appscode.com/origin.namespace:?kubesphere-devops-systemmutate:patchStrategicMerge:metadata:labels:participant:?kyvernofinalizers:-?finalizers.kubesphere.io/credentialtype:?credential.devops.kubesphere.io/basic-authname:?mutate-credential-secret
EOF
可以參考 Kyverno 官方文檔 sample-example:
https://kyverno.io/docs/writing-policies/match-exclude/#resource-filters
源 Secret
我們將kubesphere-devops-system
命名空間中的憑證作為同步的來源:
cat?<<EOF?|?kubectl?apply?-f?-
kind:?Secret
apiVersion:?v1
metadata:name:?common-encodenamespace:?kubesphere-devops-systemlabels:app:?common-encodeannotations:kubed.appscode.com/sync:?"kubesphere.io/devopsproject"kubesphere.io/creator:?adminkubesphere.io/description:?密碼經過UrlEncode
data:id:?XX==password:?XX==username:?XX==
type:?will-be-modify-by-kyverno
---
kind:?Secret
apiVersion:?v1
metadata:name:?commonnamespace:?kubesphere-devops-systemlabels:app:?commonannotations:kubed.appscode.com/sync:?"kubesphere.io/devopsproject"kubesphere.io/creator:?adminkubesphere.io/description:?公用賬戶
data:password:?XX==username:?XX==
type:?will-be-modify-by-kyverno
EOF
參考 kubed 官方文檔:
https://appscode.com/products/kubed/v0.12.0/guides/config-syncer/intra-cluster/
源 Secret 必須指定注解:
kubed.appscode.com/sync:?"kubesphere.io/devopsproject"
表明目標命名空間中必須包含label key
為kubesphere.io/devopsproject
,Kubesphere
的Devops
項目,默認包含這個label key
。
需要說明的是:
Kubesphere 根據 Secret 的 type 字段前綴有:credential.devops.kubesphere.io/
就會處理。為了避免 kubesphere-devops-system 下的源 Secret 被 ks-controller-manager 同步。所以源 Secret 的 type 不可為:
type:?credential.devops.kubesphere.io/basic-auth
源 Secret type 可以自定義一個:
type:?will-be-modify-by-kyverno
通過 kyverno 修改為:
type:?credential.devops.kubesphere.io/basic-auth
目標命名空間
下面這個 Devops 項目作為命名空間:
k?get?ns?-l?kubesphere.io/devopsproject
NAME???????????????????????STATUS???AGE
test-ns1xxx????????????????Active???133d
同步結果
創建之后,就在存在 label key
為kubesphere.io/devopsproject
的 namespace 下創建了同名 Secret:
$??k?get?secret?-A?|?grep?common
kubesphere-devops-system??????????common??????????????????????????????????????????????????????????will-be-modify-by-kyverno????????????????????2??????29s
kubesphere-devops-system??????????common-encode???????????????????????????????????????????????????will-be-modify-by-kyverno????????????????????3??????13m
test-ns1xxx???????????????????????common??????????????????????????????????????????????????????????credential.devops.kubesphere.io/basic-auth???2??????28s
test-ns1xxx???????????????????????common-encode???????????????????????????????????????????????????credential.devops.kubesphere.io/basic-auth???3??????13m
同步之后,kubed 會加一些 labels:
kubed.appscode.com/origin.cluster
kubed.appscode.com/origin.name
kubed.appscode.com/origin.namespace
和 annotations:
kubed.appscode.com/origin
apiVersion:?v1data:id:?XX==password:?XX==username:?XX==kind:?Secretmetadata:annotations:kubed.appscode.com/origin:?'{"namespace":"kubesphere-devops-system","name":"common-encode","uid":"a649bc60-0197-4ec2-914b-b6412d2c7d29","resourceVersion":"589340738"}'labels:app:?common-encodekubed.appscode.com/origin.cluster:?unicornkubed.appscode.com/origin.name:?common-encodekubed.appscode.com/origin.namespace:?kubesphere-devops-systemname:?common-encodenamespace:?des-nstype:?will-be-modify-by-kyverno
而且會將同步源 Secret 中設置的注解去掉
kubed.appscode.com/sync:?"kubesphere.io/devopsproject"
總結
Kubed 可以跨 Kubernetes 命名空間、跨集群同步 ConfigMaps/Secrets。而且暴露了各種監控指標,可以滿足大多數配置同步場景。
- END -
?點個在看集群永保穩定👇