TH小破站

  • 首页
  • 容器
    • 认识Docker
    • DockerFile详解
  • k8s
    • 认识Kubernetes
    • Kubernetes部署--(kubeadm方式)
    • kubeasz部署k8s集群
    • Ansible-binary部署k8s集群-1.31.2
  • Ceph
    • 认识分布式存储
    • CPEH部署
  • CI/CD
    • DevOps认识
    • 部署--Gitlab
  • ELK
    • ELK简介
    • Elasticsearch
    • Kibana部署
    • Logstash
    • ELK--收集 tomcat 日志(实战)
  • HD
    • 认识--大数据
    • Hadoop-单机部署
    • Hadoop-伪分布部署
    • Hadoop-完全分布部署
    • Hadoop-(HA)完全分布部署
    • Ambari自动部署--Hadoop
  • Nginx
    • Nginx功能介绍
    • Nginx安全选项
    • Nginx配置文件简单介绍
    • 网站服务器部署
  • 监控
    • ZABBIX-部署(yum)
    • ZABBIX-编译安装
  • 云计算
    • KVM 概述
    • OpenStack企业级部署(T版)
    • OpenStack之dashboard部署
    • OpenStack-controller的高可用
    • openstack(Caracal版_ubuntu版本)部署
  • 数据库
    • mariadb与mysql
    • mysql主从
    • MySQL--冷备(实战)
    • MySQL--热备(dump表)
    • MySQL--热备(dump库)
    • 数据恢复实战案例
    • Xtrabackup实现MySql8.x全量备份
    • MyCat实现数据库读写分离
    • MHA实现数据库高可用
    • Percona XtraDB(PXC)实现数据库集群高可用
    • 数据库压力测试
    • PostgreSQL 基操
    • PostgreSQL备份恢复
    • PostgreSQL高可用
    • MongDB安装配置基础使用
    • MongoDB实现复制集
    • MongoDB备份还原
  • 自动化
    • ssh远程服务原理及配置
    • Ansible剧本文件应用
    • Ansible管理服务介绍
    • Ansible自动化部署node_exporter(包含升级,回滚)
    • Saltstack-部署安装
  • 脚本
    • 一键查看服务器资源利用率
    • 一键生成SSL证书
    • 保存指定数量的文件/目录
    • 初始化服务器
    • 扫描可用IP
    • 批量分发SSH密钥
    • 监控多主机磁盘脚本
    • 一键安装MySQL8.x脚本
    • Python脚本监控ES集群
    • 资源巡检脚本
    • 查看各用户使用的cpu占比
热衷于分享
架构师成长之路 !!!
  1. 首页
  2. Kubernetes
  3. 正文

Operator开发(secrets资源跨ns同步)

2025年5月25日 824点热度 1人点赞 0条评论

背景

在 Kubernetes 中,Secrets 是被隔离在各自的 Namespace 范围内的资源。默认情况下,一个 Secret 只能被创建它的 Namespace 内的 Pod 或 Deployment 所引用,其他 Namespace 中的应用无法直接访问。

一、安装依赖工具

 # 安装 Go(1.24.1)
 https://studygolang.com/dl/golang/go1.24.1.linux-amd64.tar.gz
 ​
 # 删除旧版 Go 源码和二进制文件
 sudo rm -rf /usr/local/go
 sudo rm -rf /root/go
 ​
 # 下载官方 Go 1.24.1
 wget https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
 ​
 # 安装 Go 到标准路径
 sudo tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
 ​
 # 设置环境变量(写入 .bashrc 或 .zshrc)
 export GOROOT=/usr/local/go
 export PATH=$GOROOT/bin:$PATH
 export GOPROXY=https://goproxy.io,direct
 ​
 # 验证安装
 go version
 # 输出:go version go1.24.1 linux/amd64
 ​
 # 安装 Kubebuilder CLI (kubebuilder 4.6)
 ​
 ​
 wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v4.6.0/kubebuilder_linux_amd64
 chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
 ​
 # 安装 Kustomize(make deploy 会用到)
 go install sigs.k8s.io/kustomize/kustomize/v4@latest
 ​
 # 安装 Docker 与 kubectl(略)

初始化 Kubebuilder 项目

二、创建项目模板

 mkdir secretsync-controller && cd secretsync-controller
 kubebuilder init --domain stangj.com --repo github.com/stangj/secretsync-controller

将自动创建项目结构,包含 Go 模块、Makefile 等文件。


三、创建 CRD API:SecretSync

步骤 3:生成 API 模板

 kubebuilder create api --group sync --version v1 --kind Secretsync

步骤 4:编辑 CRD 结构(api/v1/secretsync_types.go)

 /*
 Copyright 2025.
 ​
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 ​
     http://www.apache.org/licenses/LICENSE-2.0
 ​
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
 ​
 package v1
 ​
 import (
     metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 ​
 // EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
 // NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
 ​
 // SecretsyncSpec defines the desired state of Secretsync.
 type SecretsyncSpec struct {
     // 源命名空间
     SourceNamespace string `json:"sourceNamespace"`
     // 源 Secret 名称
     SourceSecretName string `json:"sourceSecretName"`
     // 目标命名空间选择器:支持 Labels 动态选择
     TargetNamespaceSelector *metav1.LabelSelector `json:"targetNamespaceSelector,omitempty"`
     // 目标 Secret 名称(可选,默认与源同名)
     TargetSecretName string `json:"targetSecretName,omitempty"`
 }
 ​
 // SecretsyncStatus defines the observed state of Secretsync.
 type SecretsyncStatus struct {
     // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
     // Important: Run "make" to regenerate code after modifying this file
     // 已同步命名空间
     SyncedNamespaces []string `json:"syncedNamespaces,omitempty"`
     // 同步失败命名空间
     FailedNamespaces []string `json:"failedNamespaces,omitempty"`
     // 最后同步时间
     LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"`
 }
 ​
 // +kubebuilder:object:root=true
 // +kubebuilder:subresource:status
 ​
 // Secretsync is the Schema for the secretsyncs API.
 type Secretsync struct {
     metav1.TypeMeta   `json:",inline"`
     metav1.ObjectMeta `json:"metadata,omitempty"`
 ​
     Spec   SecretsyncSpec   `json:"spec,omitempty"`
     Status SecretsyncStatus `json:"status,omitempty"`
 }
 ​
 // +kubebuilder:object:root=true
 ​
 // SecretsyncList contains a list of Secretsync.
 type SecretsyncList struct {
     metav1.TypeMeta `json:",inline"`
     metav1.ListMeta `json:"metadata,omitempty"`
     Items           []Secretsync `json:"items"`
 }
 ​
 func init() {
     SchemeBuilder.Register(&Secretsync{}, &SecretsyncList{})
 }

重点字段说明:

  • TargetNamespaceSelector:使用标签选择器动态选择命名空间

  • TargetSecretName:支持定义不同的目标 Secret 名称

  • Status 部分提供状态反馈


四、构建控制器核心逻辑

步骤 4:查看控制器模板

 cat internal/controller/secretsync_controller.go

步骤 6:实现控制器逻辑(controllers/secretsync_controller.go)

 /*
 Copyright 2025.
 ​
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 ​
     http://www.apache.org/licenses/LICENSE-2.0
 ​
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
 ​
 package controller
 ​
 import (
     "context"
     "fmt"
     "reflect"
     "time"
 ​
     "github.com/go-logr/logr"
     "github.com/prometheus/client_golang/prometheus"
     "k8s.io/apimachinery/pkg/api/errors"
     "k8s.io/apimachinery/pkg/labels"
     "k8s.io/apimachinery/pkg/runtime"
     "k8s.io/apimachinery/pkg/types"
     ctrl "sigs.k8s.io/controller-runtime"
     "sigs.k8s.io/controller-runtime/pkg/client"
     "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
     "sigs.k8s.io/controller-runtime/pkg/handler"
     "sigs.k8s.io/controller-runtime/pkg/reconcile"
 ​
     syncv1 "github.com/stangj/secretsync-controller/api/v1"
     corev1 "k8s.io/api/core/v1"
     metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 ​
 type SecretsyncReconciler struct {
     client.Client                 
     Scheme        *runtime.Scheme 
     Log           logr.Logger     
 }
 ​
 // 以下是控制器所需的 RBAC 权限注解
 // +kubebuilder:rbac:groups=sync.example.com,resources=secretsyncs,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=sync.example.com,resources=secretsyncs/status,verbs=get;update;patch
 // +kubebuilder:rbac:groups="",resources=namespaces,verbs=list;watch
 // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
 ​
 var (
     syncTotalCounter = prometheus.NewCounterVec(
         prometheus.CounterOpts{
             Name: "secretsync_total",
             Help: "Total number of sync operations",
         },
         []string{"result"}, // 标签,用于区分成功/失败结果
     )
 ​
     syncLatencySeconds = prometheus.NewHistogram(
         prometheus.HistogramOpts{
             Name: "secretsync_latency_seconds",
             Help: "Time taken for sync",
         },
     )
 ​
     lastSuccessTimeGauge = prometheus.NewGauge(
         prometheus.GaugeOpts{
             Name: "secretsync_last_success_time",
             Help: "Timestamp of last successful sync",
         },
     )
 )
 ​
 func init() {
     prometheus.MustRegister(syncTotalCounter, syncLatencySeconds, lastSuccessTimeGauge)
 }
 ​
 // Reconcile 是控制器的核心方法,实现了 controller-runtime 的 Reconciler 接口
 // 当 Secretsync 资源或相关资源发生变化时被调用
 func (r *SecretsyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
     start := time.Now()
     log := r.Log.WithValues("secretsync", req.NamespacedName)
 ​
     var syncObj syncv1.Secretsync
     if err := r.Get(ctx, req.NamespacedName, &syncObj); err != nil {
         if errors.IsNotFound(err) {
             log.Info("SecretSync CR not found, skip reconciliation")
             syncTotalCounter.WithLabelValues("failure").Inc()
             return ctrl.Result{}, nil
         }
         log.Error(err, "Failed to get SecretSync CR")
         syncTotalCounter.WithLabelValues("failure").Inc()
         return ctrl.Result{}, err
     }
 ​
     if syncObj.Spec.SourceNamespace == "" || syncObj.Spec.SourceSecretName == "" {
         log.Error(nil, "Invalid spec: SourceNamespace or SourceSecretName missing", "spec", syncObj.Spec)
         syncObj.Status.LastSyncTime = &metav1.Time{Time: time.Now()}
         _ = r.Status().Update(ctx, &syncObj)
         syncTotalCounter.WithLabelValues("failure").Inc()
         return ctrl.Result{}, nil
     }
 ​
     srcNamespaceName := types.NamespacedName{
         Namespace: syncObj.Spec.SourceNamespace,
         Name:      syncObj.Spec.SourceSecretName,
     }
     var srcSecret corev1.Secret
     if err := r.Get(ctx, srcNamespaceName, &srcSecret); err != nil {
         log.Error(err, "Failed to get source Secret", "secret", srcNamespaceName)
         syncTotalCounter.WithLabelValues("failure").Inc()
         return ctrl.Result{}, err
     }
 ​
     namespaces, err := r.getMatchingNamespaces(ctx, syncObj.Spec.TargetNamespaceSelector)
     if err != nil {
         log.Error(err, "Failed to list matched namespaces")
         syncTotalCounter.WithLabelValues("failure").Inc()
         return ctrl.Result{}, err
     }
 ​
     // 确定目标 Secret 的名称
     targetSecretName := syncObj.Spec.TargetSecretName
     if targetSecretName == "" {
         targetSecretName = srcSecret.Name
     }
 ​
     var synced []string // 成功同步的命名空间
     var failed []string // 失败的命名空间
 ​
     // 遍历所有目标命名空间,执行同步
     for _, ns := range namespaces {
         if err := r.syncSecret(ctx, &srcSecret, ns, targetSecretName, &syncObj); err != nil {
             log.Error(err, "Failed to sync secret to namespace", "namespace", ns)
             failed = append(failed, ns)
         } else {
             // 同步成功,记录成功的命名空间
             synced = append(synced, ns)
         }
     }
 ​
     // 更新 Secretsync 资源的状态
     now := metav1.Now()
     syncObj.Status.SyncedNamespaces = synced
     syncObj.Status.FailedNamespaces = failed
     syncObj.Status.LastSyncTime = &now
     if err := r.Status().Update(ctx, &syncObj); err != nil {
         log.Error(err, "Failed to update SecretSync status")
         // 状态更新失败不会影响同步操作的返回结果
     }
 ​
     if len(synced) > 0 && len(failed) == 0 {
         syncTotalCounter.WithLabelValues("success").Inc()
         lastSuccessTimeGauge.Set(float64(now.Unix()))
     } else if len(failed) > 0 {
         syncTotalCounter.WithLabelValues("failure").Inc()
     } else {
         syncTotalCounter.WithLabelValues("partial_success").Inc()
     }
 ​
     latency := time.Since(start).Seconds()
     syncLatencySeconds.Observe(latency)
 ​
     if len(failed) > 0 {
         return ctrl.Result{}, fmt.Errorf("some target namespaces failed to sync")
     }
 ​
     return ctrl.Result{}, nil
 }
 ​
 // syncSecret 将单个源 Secret 同步到目标命名空间中
 // 参数:
 // - ctx: 上下文,用于API通信
 // - src: 源 Secret 对象
 // - namespace: 目标命名空间
 // - targetSecretName: 在目标命名空间中创建的 Secret 名称
 // - syncObj: Secretsync 对象,用于设置所有者引用
 func (r *SecretsyncReconciler) syncSecret(
     ctx context.Context,
     src *corev1.Secret,
     namespace, targetSecretName string,
     syncObj *syncv1.Secretsync,
 ) error {
     // 创建目标 Secret 对象
     target := &corev1.Secret{
         ObjectMeta: metav1.ObjectMeta{
             Name:      targetSecretName,
             Namespace: namespace,
         },
         Data: src.Data, // 复制源 Secret 的数据
         Type: src.Type, // 复制源 Secret 的类型
     }
 ​
     controllerutil.SetControllerReference(syncObj, target, r.Scheme)
 ​
     var existing corev1.Secret
     existingKey := types.NamespacedName{Namespace: namespace, Name: targetSecretName}
     err := r.Get(ctx, existingKey, &existing)
 ​
     if err != nil {
         if errors.IsNotFound(err) {
             return r.Create(ctx, target)
         }
         return err
     }
 ​
     if !reflect.DeepEqual(existing.Data, target.Data) || existing.Type != target.Type {
         existing.Data = target.Data
         existing.Type = target.Type
         return r.Update(ctx, &existing)
     }
 ​
     return nil
 }
 ​
 // getMatchingNamespaces 根据标签选择器获取匹配的命名空间列表
 // 参数:
 // - ctx: 上下文,用于API通信
 // - selector: Kubernetes 标签选择器
 // 返回:
 // - 匹配的命名空间名称列表
 // - 错误(如果有)
 func (r *SecretsyncReconciler) getMatchingNamespaces(
     ctx context.Context,
     selector *metav1.LabelSelector,
 ) ([]string, error) {
     if selector == nil {
         return nil, nil
     }
 ​
     selectorLabels, err := metav1.LabelSelectorAsSelector(selector)
     if err != nil {
         return nil, err
     }
 ​
     var nsList corev1.NamespaceList
     if err := r.List(ctx, &nsList, client.MatchingLabelsSelector{Selector: selectorLabels}); err != nil {
         return nil, err
     }
 ​
     var namespaces []string
     for _, ns := range nsList.Items {
         namespaces = append(namespaces, ns.Name)
     }
     return namespaces, nil
 }
 ​
 // enqueueSecrets 是一个 MapFunc,当监视的 Secret 发生变化时
 func (r *SecretsyncReconciler) enqueueSecrets(_ context.Context, obj client.Object) []reconcile.Request {
     ctx := context.TODO()
     // 转换为 Secret 对象
     secret := obj.(*corev1.Secret)
 ​
     var list syncv1.SecretsyncList
     if err := r.List(ctx, &list, &client.ListOptions{}); err != nil {
         r.Log.Error(err, "Failed to list SecretSync CRs")
         return nil
     }
 ​
     var requests []reconcile.Request
     for _, item := range list.Items {
         if item.Spec.SourceNamespace == secret.Namespace && item.Spec.SourceSecretName == secret.Name {
             requests = append(requests, reconcile.Request{
                 NamespacedName: client.ObjectKeyFromObject(&item),
             })
         }
     }
     return requests
 }
 ​
 // enqueueNamespaces 是一个 MapFunc,当监视的 Namespace 发生变化时
 func (r *SecretsyncReconciler) enqueueNamespaces(_ context.Context, obj client.Object) []reconcile.Request {
     ctx := context.TODO()
     // 转换为 Namespace 对象
     ns := obj.(*corev1.Namespace)
 ​
     var list syncv1.SecretsyncList
     if err := r.List(ctx, &list, &client.ListOptions{}); err != nil {
         r.Log.Error(err, "Failed to list SecretSync CRs")
         return nil
     }
 ​
     var requests []reconcile.Request
     for _, item := range list.Items {
         // 跳过没有目标命名空间选择器的 Secretsync
         if item.Spec.TargetNamespaceSelector == nil {
             continue
         }
 ​
         sel, _ := metav1.LabelSelectorAsSelector(item.Spec.TargetNamespaceSelector)
         if sel.Matches(labels.Set(ns.Labels)) {
             requests = append(requests, reconcile.Request{
                 NamespacedName: client.ObjectKeyFromObject(&item),
             })
         }
     }
     return requests
 }
 ​
 // SetupWithManager 设置控制器与管理器的关联
 func (r *SecretsyncReconciler) SetupWithManager(mgr ctrl.Manager) error {
     return ctrl.NewControllerManagedBy(mgr).
         For(&syncv1.Secretsync{}).
         Watches(
             &corev1.Secret{},
             handler.EnqueueRequestsFromMapFunc(r.enqueueSecrets),
         ).
         Watches(
             &corev1.Namespace{},
             handler.EnqueueRequestsFromMapFunc(r.enqueueNamespaces),
         ).
         Complete(r)
 }

测试部署到K8S集群

 生成本地yaml并部署到k8s集群
 # make manifests
 # make install
 # kubectl get crd | grep stangj
 secretsyncs.sync.stangj.com    2025-05-25T08:11:13Z
 本地启动controller
 # go run cmd/main.go
 2025-05-25T17:37:20+08:00   INFO    setup   starting manager
 2025-05-25T17:37:20+08:00   INFO    starting server {"name": "health probe", "addr": "[::]:8081"}
 2025-05-25T17:37:20+08:00   INFO    Starting EventSource    {"controller": "secretsync", "controllerGroup": "sync.stangj.com", "controllerKind": "Secretsync", "source": "kind source: *v1.Namespace"}
 2025-05-25T17:37:20+08:00   INFO    Starting EventSource    {"controller": "secretsync", "controllerGroup": "sync.stangj.com", "controllerKind": "Secretsync", "source": "kind source: *v1.Secretsync"}
 2025-05-25T17:37:20+08:00   INFO    Starting EventSource    {"controller": "secretsync", "controllerGroup": "sync.stangj.com", "controllerKind": "Secretsync", "source": "kind source: *v1.Secret"}
 2025-05-25T17:37:20+08:00   INFO    Starting Controller {"controller": "secretsync", "controllerGroup": "sync.stangj.com", "controllerKind": "Secretsync"}
 2025-05-25T17:37:20+08:00   INFO    Starting workers    {"controller": "secretsync", "controllerGroup": "sync.stangj.com", "controllerKind": "Secretsync", "worker count": 1}
 ....
 编写SecretSync进行同步
 # kubectl create ns cert-sync
 # cat sync-Secret.yaml 
 apiVersion: v1
 kind: Secret
 metadata:
   namespace: cert-sync
   name: tls
 stringData:
   tls.crt: "FAKE-CERT1"
   tls.key: "FAKE-KEY2"
 type: kubernetes.io/tls
 # kubectl apply -f sync-Secret.yaml
 # kubectl get secrets -n cert-sync -oyaml
 apiVersion: v1
 items:
 - apiVersion: v1
   data:
     tls.crt: RkFLRS1DRVJUMQ==
     tls.key: RkFLRS1LRVky
   kind: Secret
   metadata:
     annotations:
       kubectl.kubernetes.io/last-applied-configuration: |
         {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"tls","namespace":"cert-sync"},"stringData":{"tls.crt":"FAKE-CERT1","tls.key":"FAKE-KEY2"},"type":"kubernetes.io/tls"}
     creationTimestamp: "2025-05-25T09:40:02Z"
     name: tls
     namespace: cert-sync
     resourceVersion: "24453"
     uid: d0708bf8-16c7-4de2-82d0-44da794f1a9e
   type: kubernetes.io/tls
 kind: List
 metadata:
   resourceVersion: ""
 ​
 创建数据同步
 创建要同步的名称空间
 # kubectl create ns dest1-sync
 # kubectl create ns dest2-sync
 创建yaml指定同步的名称空间
 # vim sync-dest1.yaml
 apiVersion: sync.stangj.com/v1
 kind: Secretsync
 metadata:
   name: sync-dest1
 spec:
   sourceNamespace: cert-sync
   sourceSecretName: tls
   targetNamespaceSelector:
     matchLabels:
       secret-sync: "enabled"
 # kubectl apply -f sync-dest1.yaml 
 # kubectl get secretsync
 NAME         AGE
 sync-dest1   33s
 给要同步的名称空间打标签 secret-sync: "enabled
 # kubectl label namespaces dest1-sync secret-sync=enabled
 # kubectl get namespaces dest1-sync --show-labels
 NAME         STATUS   AGE    LABELS
 dest1-sync   Active   9m1s   kubernetes.io/metadata.name=dest1-sync,secret-sync=enabled
 查看打上标签的名称空间有没有同步secret
 # kubectl get secrets -n dest1-sync 
 NAME   TYPE                DATA   AGE
 tls    kubernetes.io/tls   2      2m45s
 # kubectl get secrets -n dest1-sync -oyaml 
 apiVersion: v1
 items:
 - apiVersion: v1
   data:
     tls.crt: RkFLRS1DRVJUMQ==
     tls.key: RkFLRS1LRVky
   kind: Secret
   metadata:
     creationTimestamp: "2025-05-25T09:50:52Z"
     name: tls
     namespace: dest1-sync
     resourceVersion: "25461"
     uid: 5abad270-62fa-40a4-afc9-e64003bd8b5b
   type: kubernetes.io/tls
 kind: List
 metadata:
   resourceVersion: ""
 验证修改数据是否可以同步
 # cat sync-Secret.yaml
 apiVersion: v1
 kind: Secret
 metadata:
   namespace: cert-sync
   name: tls
 stringData:
   tls.crt: "FAKE-CERT2"
   tls.key: "FAKE-KEY3"
 type: kubernetes.io/tls
 ​
 # kubectl apply -f sync-Secret.yaml
 # kubectl get secrets -n cert-sync -oyaml 
 apiVersion: v1
 items:
 - apiVersion: v1
   data:
     tls.crt: RkFLRS1DRVJUMg==
     tls.key: RkFLRS1LRVkz
   kind: Secret
   metadata:
     annotations:
       kubectl.kubernetes.io/last-applied-configuration: |
         {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"tls","namespace":"cert-sync"},"stringData":{"tls.crt":"FAKE-CERT2","tls.key":"FAKE-KEY3"},"type":"kubernetes.io/tls"}
     creationTimestamp: "2025-05-25T09:40:02Z"
     name: tls
     namespace: cert-sync
     resourceVersion: "26030"
     uid: d0708bf8-16c7-4de2-82d0-44da794f1a9e
   type: kubernetes.io/tls
 kind: List
 metadata:
   resourceVersion: ""
 ​
 验证同步的名称空间是否已经同步
 # kubectl get secrets -n dest1-sync -oyaml 
 apiVersion: v1
 items:
 - apiVersion: v1
   data:
     tls.crt: RkFLRS1DRVJUMg==
     tls.key: RkFLRS1LRVkz
   kind: Secret
   metadata:
     creationTimestamp: "2025-05-25T09:50:52Z"
     name: tls
     namespace: dest1-sync
     resourceVersion: "26031"
     uid: 5abad270-62fa-40a4-afc9-e64003bd8b5b
   type: kubernetes.io/tls
 kind: List
 metadata:
   resourceVersion: ""
 到这里通过标签的方法已经实现了
 ​
 kubectl delele -f sync-dest1.yaml 就不会在同步了 但是目的名称空间的Secret并没有删除
标签: 暂无
最后更新:2025年5月25日

tanghao946

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复
文章目录
  • 背景
    • 一、安装依赖工具
    • 初始化 Kubebuilder 项目
    • 二、创建项目模板
    • 三、创建 CRD API:SecretSync
      • 步骤 3:生成 API 模板
      • 步骤 4:编辑 CRD 结构(api/v1/secretsync_types.go)
    • 四、构建控制器核心逻辑
      • 步骤 4:查看控制器模板
      • 步骤 6:实现控制器逻辑(controllers/secretsync_controller.go)
      • 测试部署到K8S集群

COPYRIGHT © 2025 TH小破站. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

渝ICP备2023013789号

渝公网安备50011702500926号