Secret 和 ConfigMap 资源对象是命名空间级别的。它们只能被同一命名空间中的 Pod 引用。所以有时候不得不手动为每个命名空间创建它们。
但有很多场景,我们想让它们是全局的,至少可以是跨命名空间共享的 Secret 和 ConfigMap,例如这些场景:
所有命名空间都有相同的私有注册表,避免为每个命名空间创建相同的 SecretKubeshere 中 Devops 项目中的 harbor 凭证、源代码仓库的凭证如何自动化的在跨命名空间,甚至跨 Kubernetes 集群之间“同步”这些配置,有很多方法。本文就此用例讨论,并用凭证在 Kubesphere Devops 项目之间同步做示例。
可选的方案脚本使用 jq实现简单的同步:
代码语言:javascript代码运行次数:0运行复制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 实现简单的同步:
代码语言:javascript代码运行次数:0运行复制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-reflectorC#开发的 Kubernetes 反射器:
https://github.com/EmberStack/kubernetes-reflector
它将存储在 Secret 中的凭据或证书自动传播到所有命名空间并保持同步,修改源会更新所有副本。该扩展允许您通过注释自动复制和保持跨命名空间的 Secret:
在源 Secret 上添加注释:
代码语言:javascript代码运行次数:0运行复制 annotations:
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
这将在所有命名空间中创建密钥的副本。您可以使用以下方法限制创建副本的命名空间:
代码语言:javascript代码运行次数:0运行复制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 仓库和更新仓库:
代码语言:javascript代码运行次数:0运行复制$ helm repo add appscode https://charts.appscode.com/stable/
$ helm repo update
搜索可用的最新安装包:
代码语言:javascript代码运行次数:0运行复制# 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
拉取到本地并解压:
代码语言:javascript代码运行次数:0运行复制helm fetch appscode/kubed --version v0.13.2
tar -zxf kubed-v0.13.2.tgz
cd kubed/
修改 values.yaml:
代码语言:javascript代码运行次数:0运行复制config:
# Set cluster-name to something meaningful to you, say, prod, prod-us-east, qa, etc.
# so that you can distinguish notifications sent by kubed
clusterName: dev
# If set, configmaps and secrets from only this namespace will be synced
configSourceNamespace: ""
# kubeconfig file content for configmap and secret syncer
kubeconfigContent: ""
这里的 config.clusterName 默认为 unicorn,如果不修改,kubed 同步之后的资源对象的 label 上会为 kubed.appscode.com/origin.cluster: unicorn,所以出于规范考虑,建议集群名设置为真实的集群名。如果 kubed 只在本集群内同步,就不需要填写 kubeconfigContent 了。
执行安装:
代码语言:javascript代码运行次数:0运行复制$ 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 启动是否成功:
代码语言:javascript代码运行次数:0运行复制$ 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 规则,创建这个的目的下面会做说明。
代码语言:javascript代码运行次数:0运行复制cat < apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: generation: 10 name: mutate-credential-secret spec: background: true failurePolicy: Fail rules: - exclude: resources: namespaces: - kubesphere-devops-system generate: clone: {} match: resources: kinds: - Secret selector: matchLabels: kubed.appscode.com/origin.namespace: kubesphere-devops-system mutate: patchStrategicMerge: metadata: labels: participant: kyverno finalizers: - finalizers.kubesphere.io/credential type: credential.devops.kubesphere.io/basic-auth name: mutate-credential-secret EOF 可以参考 Kyverno 官方文档 sample-example: https://kyverno.io/docs/writing-policies/match-exclude/#resource-filters 源 Secret我们将kubesphere-devops-system命名空间中的凭证作为同步的来源: 代码语言:javascript代码运行次数:0运行复制cat < kind: Secret apiVersion: v1 metadata: name: common-encode namespace: kubesphere-devops-system labels: app: common-encode annotations: kubed.appscode.com/sync: "kubesphere.io/devopsproject" kubesphere.io/creator: admin kubesphere.io/description: 密码经过UrlEncode data: id: XX== password: XX== username: XX== type: will-be-modify-by-kyverno --- kind: Secret apiVersion: v1 metadata: name: common namespace: kubesphere-devops-system labels: app: common annotations: kubed.appscode.com/sync: "kubesphere.io/devopsproject" kubesphere.io/creator: admin kubesphere.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 必须指定注解: 代码语言:javascript代码运行次数:0运行复制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 不可为: 代码语言:javascript代码运行次数:0运行复制type: credential.devops.kubesphere.io/basic-auth 源 Secret type 可以自定义一个: 代码语言:javascript代码运行次数:0运行复制type: will-be-modify-by-kyverno 通过 kyverno 修改为: 代码语言:javascript代码运行次数:0运行复制type: credential.devops.kubesphere.io/basic-auth 目标命名空间下面这个 Devops 项目作为命名空间: 代码语言:javascript代码运行次数:0运行复制k get ns -l kubesphere.io/devopsproject NAME STATUS AGE test-ns1xxx Active 133d 同步结果创建之后,就在存在 label key为kubesphere.io/devopsproject的 namespace 下创建了同名 Secret: 代码语言:javascript代码运行次数:0运行复制$ 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.clusterkubed.appscode.com/origin.namekubed.appscode.com/origin.namespace和 annotations: kubed.appscode.com/origin代码语言:javascript代码运行次数:0运行复制 apiVersion: v1 data: id: XX== password: XX== username: XX== kind: Secret metadata: annotations: kubed.appscode.com/origin: '{"namespace":"kubesphere-devops-system","name":"common-encode","uid":"a649bc60-0197-4ec2-914b-b6412d2c7d29","resourceVersion":"589340738"}' labels: app: common-encode kubed.appscode.com/origin.cluster: unicorn kubed.appscode.com/origin.name: common-encode kubed.appscode.com/origin.namespace: kubesphere-devops-system name: common-encode namespace: des-ns type: will-be-modify-by-kyverno 而且会将同步源 Secret 中设置的注解去掉 代码语言:javascript代码运行次数:0运行复制kubed.appscode.com/sync: "kubesphere.io/devopsproject" 总结Kubed 可以跨 Kubernetes 命名空间、跨集群同步 ConfigMaps/Secrets。而且暴露了各种监控指标,可以满足大多数配置同步场景。 - END -