查看原文
其他

如何优雅的跨 Namespace 同步 Secret 和 ConfigMap?

Andy 进击云原生 2022-11-10

关注公众号并添加到“星标⭐”,防止错过消息

后台回复【资料包】获取学习资料


Secret 和 ConfigMap 资源对象是命名空间级别的。它们只能被同一命名空间中的 Pod 引用。所以有时候不得不手动为每个命名空间创建它们。

但有很多场景,我们想让它们是全局的,至少可以是跨命名空间共享的 Secret 和 ConfigMap,例如这些场景:

  1. 所有命名空间都有相同的私有注册表,避免为每个命名空间创建相同的 Secret
  2. 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 的同步和跨集群的同步,只是简单的通过 matchNamespaceavoidNamespaces 实现模糊的匹配和不匹配。

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 keykubesphere.io/devopsprojectKubesphereDevops项目,默认包含这个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 keykubesphere.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。而且暴露了各种监控指标,可以满足大多数配置同步场景。


- END -



后台回复“加群”,带你进入高手交流群


推荐阅读
开源容器 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 架构核心点详细总结!


全网粉丝20W的头部大号,专注云原生、Golang、Linux实用脚本,效率工具,免费CSDN下载,回复【go】获取近 6 万 Star 的资源回复【1024】获取全种类IT资料,回复【红包封面】获取超好看封面,回复【加群】进入高手如云技术交流群

分享、点赞和在看
支持我们分享更多好文章,谢谢!
                
 点个在看集群永保稳定👇

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存