如何优雅的跨 Namespace 同步 Secret 和 ConfigMap?
关注公众号并添加到“星标⭐”,防止错过消息
后台回复【资料包】获取学习资料
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 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 了。
执行安装:
$ 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: 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
命名空间中的凭证作为同步的来源:
cat <<EOF | kubectl apply -f -
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 必须指定注解:
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: 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 中设置的注解去掉
kubed.appscode.com/sync: "kubesphere.io/devopsproject"
总结
Kubed 可以跨 Kubernetes 命名空间、跨集群同步 ConfigMaps/Secrets。而且暴露了各种监控指标,可以满足大多数配置同步场景。
推荐阅读
开源容器 Podman 常用命令总结!如何将多个 kubeconfig 文件合并为一个?
毫无争议的 GitHub 顶级开源项目排行榜Kruise 轻松让 K8S 应用实现渐进式交付图解 Kubernetes Pod 如何获取 IP 地址使用 Telepresence 轻松在本地调试 k8s 应用程序GitOps 工具选型,33 款工具任你挑!就在刚刚 k8s 1.24 正式发布,来看功能总览Nomad 会替代 Kubernetes 吗?两者如何选择?Docker 入门终极指南,详细版!漫画轻松看懂如何用 Kubernetes 实现 CI/CD阿里开源的低代码引擎,已收获 4.5K 星星新手必须知道的 Kubernetes 架构Kubernetes 架构核心点详细总结!