K8S相同后端存储在2个K8S集群PVC数据直接拷贝

博客介绍了K8S集群间PVC数据拷贝的操作方法。先将nfs - server的所有目录挂载到集群1本地服务器,核实集群1的PVC数据,查看其在后端存储的名称;接着在集群2创建新的PVC并查看其在后端存储的名称;最后将集群1的PVC数据拷贝到集群2的新PVC中,同时提醒拷贝数据库最好停库操作。

k8s数据通常保存在nfs-server里面,本例子将整个nfs-server的k8s数据挂载在集群1的master机器。
集群1: gz-kubesphere-master01
集群2: gz2-k8s-master01
注意:拷贝数据库,最好停库拷贝,在线拷贝会导致数据不一致。

一、核实集群1的PVC数据

1 挂载nfs-server的所有目录到本地服务器

mount -t nfs 10.186.100.13:/volume2/EHR /mnt

2 进入/mnt即可看到nfs所有数据

cd /mnt
ls -ls
.......
monitoring-elasticsearch-data-elasticsearch-data-1-pvc-c57aac19-e76f-445d-9dbf-f7dc421cca38
monitoring-elasticsearch-master-elasticsearch-master-0-pvc-7b063b9c-124e-432b-a5bc-0f49044d7b8c
monitoring-elasticsearch-master-elasticsearch-master-1-pvc-335bba0b-abaa-4951-bee9-e06e15d3ba94
monitoring-grafana-nfs-pvc-pvc-2a8815df-e94b-492a-87ec-69d0d06baeaa
monitoring-nfs-loki-0-pvc-b7ee4997-e762-484f-9dfd-d102dda57251
monitoring-pvc-backup-mysql-pvc-48a4bb5c-0390-40c0-a397-ea4f777c2940
monitoring-pvc-mysql-0-pvc-98344a63-3801-4050-b851-46b1aafd708d
monitoring-pvc-mysql-1-pvc-aadf0550-689a-4fb8-a26e-8303078cf97b
rds-pvc-backup-mysql-pvc-154e1f91-06fa-4c21-867d-9e59d0ad7f9b
rds-pvc-mysql-0-pvc-f8badc6d-e11c-4c27-8b94-5627df0050bb
rds-pvc-mysql-1-pvc-898d9512-4068-42ab-9a01-4c0b6a905755
usopa-test-pvc-backup-mysql-pvc-4b5125a3-d338-4d1c-8b7d-ce7e56b75183
wangjinxiong
wangjinxiong-gitlab-pvc-config-pvc-41deed8d-b3c0-4f39-b986-e54abacc53ac
wangjinxiong-gitlab-pvc-data-pvc-b4d00659-0408-4f29-8178-2184c876b5d0
wangjinxiong-gitlab-pvc-logs-pvc-428ab448-6729-4b6a-b183-7d1aea6e2948
wangjinxiong-mysql0527-pvc-pvc-888d6778-b035-48d9-81bf-e5e3f4123f68
wangjinxiong-nfs-pvc1-pvc-f1e5ef44-b720-4458-bafc-5df6bc89a42b
wangjinxiong-nfs-server-pvc2-pvc-496a4757-6262-42ae-81db-99dab70cbd07
wangjinxiong-pvc0530-pvc-731be493-61b4-4ca3-a146-361fc3c20d08
work-infinity-prod-pvc-backup-mysql-pvc-c4e42d99-c7e5-47b6-b762-30ec61ddfa44
work-infinity-prod-work-infinity-prod-mysql-0-pvc-09f1410b-f0ea-4608-8d90-bc29c9559682
work-infinity-prod-work-infinity-prod-mysql-1-pvc-2e31d1d1-18e5-4527-bd63-61ef0d6787f7
work-infinity-prod-work-infinity-prod-rabbitmq1-pvc1-pvc-15b48eaa-b20f-4987-9e75-9d5c80fa9040
work-infinity-prod-work-infinity-prod-redis-pvc1-pvc-1c83a3b5-7eab-429a-b39c-021d4a3147aa
work-infinity-test-work-infinity-test-mysql-pvc1-pvc-5962b1b7-1a02-4d4d-bc0c-6a8394278d10
work-infinity-test-work-infinity-test-rabbitmq1-pvc1-pvc-5f76626d-64d8-46ce-b5c2-54e470841613
work-infinity-test-work-infinity-test-redis-pvc1-pvc-5ecd2cb1-29bf-4b2c-b7c0-1b8e42015b4c
xr-dev-mysql-pvc1-pvc-e8ef0d9e-9548-4536-b025-3b49e1e1ca79
xr-dev-redis-data-redis-master-0-pvc-e8790ffd-deb9-44e7-a854-2d620b30d8df
zhangfangrui-pvc-backup-mysql-pvc-48d34e7c-0372-405a-ab50-86d316f42708
zhangfangrui-pvc-mysql-0-pvc-3b515c4e-e360-432b-b283-3f02bb3fb0a1
zhangfangrui-pvc-mysql-1-pvc-1196f1a5-c6f9-4d18-9e7a-4b4bfcc06f0e
zhaodengke-grafana-pvc-16595777-6d34-4ae8-a2d1-a7bdcd88a371
zhaodengke-prometheus-k8s-db-prometheus-k8s-0-pvc-379e5dc7-02a9-4aa4-bb1e-1f73e99ed372

3 查看集群1的pvc,后端存储sc为nfs-synology

[root@gz-kubesphere-master01 mnt]# kubectl get pvc -n it2
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-mysql-0          Bound    pvc-632b8acd-41ba-4231-9fb4-b1a115c44529   20Gi       RWO            nfs-synology   112d

4 查看pvc所在的pv在后端存储的名称

[root@gz-kubesphere-master01 mnt]# kubectl describe pv pvc-632b8acd-41ba-4231-9fb4-b1a115c44529
Name:            pvc-632b8acd-41ba-4231-9fb4-b1a115c44529
Labels:          <none>
Annotations:     pv.kubernetes.io/provisioned-by: nfs-provisioner-01
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    nfs-synology
Status:          Bound
Claim:           it2/pvc-mysql-0
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        20Gi
Node Affinity:   <none>
Message:         
Source:
Type:      NFS (an NFS mount that lasts the lifetime of a pod)
Server:    10.186.100.13
Path:      /volume2/EHR/it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529
ReadOnly:  false
Events:        <none>

以上it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529即为后端的目录名称
进入/mnt查看

[root@gz-kubesphere-master01 mnt]# ls -ls | grep it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529
0 drwxrwxrwx 1     501 root   2972 7月   6 06:45 it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529

源pvc: it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529

二、集群2创建新的PVC

1 在集群2创建一个空pvc

[root@gz2-k8s-master01 /]# kubectl  get pvc -n it2-dev
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-mysql-0          Bound    pvc-481fa4ef-3056-4286-8850-15dc07cceb0c   20Gi       RWO            nfs-synology   17m

2 查看pvc所在的pv在后端存储的名称:

[root@gz2-k8s-master01 /]# kubectl  describe pv pvc-481fa4ef-3056-4286-8850-15dc07cceb0c -n it2-dev 
Name:            pvc-481fa4ef-3056-4286-8850-15dc07cceb0c
Labels:          <none>
Annotations:     pv.kubernetes.io/provisioned-by: nfs-provisioner-01
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    nfs-synology
Status:          Bound
Claim:           it2-dev/pvc-mysql-0
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        20Gi
Node Affinity:   <none>
Message:         
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    10.186.100.13
    Path:      /volume2/EHR/it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c
    ReadOnly:  false
Events:        <none>

it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c即为后端的目录名称
进入/mnt查看

cd /mnt
[root@gz-kubesphere-master01 mnt]# ls -ls | grep it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c
0 drwxrwxrwx 1     501 root    636 7月   6 10:02 it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c

目标pvc: it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c

三、将数据拷贝到新的PVC

cp源目录: 第一步的源pvc
cp目标目录: 第二步的目标pvc

cd /mnt
cp -r it2-pvc-mysql-0-pvc-632b8acd-41ba-4231-9fb4-b1a115c44529/* it2-dev-pvc-mysql-0-pvc-481fa4ef-3056-4286-8850-15dc07cceb0c/
<think>我们正在解决Kubernetes后端服务未正确读取ConfigMap或环境变量配置的问题。根据引用内容,我们有几个关键点需要注意: 1. ConfigMap挂载到Pod中的配置文件更新问题:Kubernetes默认会在一段时间内(由kubelet的--sync-frequency参数控制,默认1分钟)将更新后的ConfigMap内容同步到Pod的挂载点。但是,应用程序可能需要重新加载配置(例如通过发送SIGHUP信号或使用热加载机制)才能生效。 2. 环境变量(ENV)在容器启动时注入,之后不会更新。因此,如果ConfigMap更新,通过环境变量注入的配置不会改变,必须重启Pod。 3. 同一个namespace中的pod的环境变量是不断累加的(这个可能是指从多个ConfigMap或Secret累加环境变量,但同样不会动态更新)。 用户的问题可能是:更新了ConfigMap后,后端服务没有读取到新的配置。 根据以上引用,我们可以总结出以下可能的原因和解决方案: 可能原因: 1. 配置是通过环境变量注入的:环境变量在容器启动时确定,不会更新。 2. 配置是通过volume挂载的,但应用程序没有重新加载配置(即使文件已经更新)。 3. kubelet同步延迟(最多1分钟,默认情况下)。 解决方案: 1. 如果使用环境变量,则必须重启Pod才能更新环境变量。可以考虑使用滚动更新(例如,修改Pod模板的注解来触发重新部署)或先缩容再扩容。 2. 如果使用volume挂载,确保应用程序能够检测文件变化并重新加载配置。如果应用程序不支持,可能需要重启Pod。 3. 为了减少同步延迟,可以调整kubelet的--sync-frequency参数(但不建议,因为会增加资源消耗,尤其在大规模集群中)。 4. 另一种方法是使用子路径(subPath)挂载单个文件,但注意:使用子路径挂载的文件在ConfigMap更新时不会被更新(除非在更新ConfigMap后删除并重新创建Pod,或者使用其他方法)。所以通常建议不使用子路径挂载,而是挂载整个目录。 引用[4]提到,即使挂载的文件更新了,应用程序可能没有重新加载。因此,我们需要确保应用程序有重新加载配置的机制。 另外,引用[3]提到,修改ConfigMap后,可以通过修改Pod的注解来触发重新部署(例如,添加一个时间戳注解),从而强制重新挂载ConfigMap。 步骤总结: 1. 确认配置的加载方式:环境变量还是文件挂载? 2. 如果是环境变量,需要重启Pod(滚动更新、缩容再扩容等)。 3. 如果是文件挂载,检查文件是否已经更新(进入Pod查看文件内容)。 4. 如果文件已经更新,但应用程序未重新加载,需要配置应用程序的热加载功能,或者重启Pod。 5. 如果文件没有更新,检查kubelet同步状态,或者等待最多1分钟(默认)。如果不想等待,可以尝试重启Pod。 另外,引用[2]提到,在SpringBoot项目中,可以通过使用spring-cloud-kubernetes来动态刷新配置(需要应用程序支持)。这需要添加相应的依赖和配置。 因此,具体到后端服务,如果是Java SpringBoot应用,可以考虑使用spring-cloud-kubernetes的@RefreshScope来实现配置刷新(通过访问/actuator/refresh端点)。 但是,如果应用不支持动态刷新,那么只能重启Pod。 操作建议: 1. 检查Pod的配置方式(环境变量还是卷挂载): - 环境变量:重启Pod。 - 卷挂载:检查文件是否更新。 2. 如果文件已更新,应用未重新加载,考虑添加应用的热加载支持,或者重启Pod。 3. 如果文件未更新,等待一段时间(1分钟内)或重启Pod。 强制重新挂载ConfigMap(不重启Pod)的方法:更新ConfigMap后,删除并重新创建Pod(使用滚动更新策略)或者使用以下技巧(通过修改Pod的注解来触发重新部署): kubectl patch deployment <deployment-name> -p '{"spec":{"template":{"metadata":{"annotations":{"version/config":"'$(date +%s)'"}}}}}' 这个命令会更新部署的Pod模板,触发滚动更新,从而重新挂载ConfigMap。 注意:如果使用子路径挂载,则无法通过更新ConfigMap来更新文件(除非重启Pod,且子路径挂载的文件在容器运行期间不会更新)。因此,避免使用子路径挂载需要动态更新的配置文件。 总结排查步骤: 1. 确认ConfigMap已经更新: kubectl get configmap <configmap-name> -o yaml 2. 确认Pod是否使用了该ConfigMap(通过环境变量或卷挂载): kubectl describe pod <pod-name> 3. 如果是环境变量,则重启Pod(例如,通过滚动更新部署)。 4. 如果是卷挂载,进入Pod查看文件内容: kubectl exec -it <pod-name> -- cat /path/to/mounted/config/file 5. 如果文件内容已经更新,但应用程序没有重新加载,则检查应用程序的配置重新加载机制。 6. 如果文件内容没有更新,等待1分钟再检查,或者重启Pod。 7. 如果应用程序不支持热加载,则只能重启Pod来使新配置生效。 8. 对于需要动态更新的场景,考虑使用支持热加载的配置方式(如Spring Cloud Kubernetes)或者使用其他配置中心(如Spring Cloud Config)。 根据引用[4],kubelet同步配置的周期是1分钟,所以如果更新ConfigMap后立即检查,可能还没有同步到Pod,需要等待。 最后,如果用户的问题是关于环境变量的,那么必须重启Pod。 生成相关问题: 1. 如何让Kubernetes中的应用程序动态更新ConfigMap的配置? 2. Kubernetes中ConfigMap通过环境变量和卷挂载有何区别? 3. 如何在不重启Pod的情况下更新挂载的ConfigMap? 4. 如何检查Kubernetes Pod中的环境变量和挂载的配置文件? 5. 在SpringBoot应用中如何集成Kubernetes ConfigMap实现动态配置更新?</think>### Kubernetes 后端服务未读取 ConfigMap 或环境变量配置的排查指南 #### 一、核心问题分析 当 Kubernetes 后端服务未正确读取 ConfigMap 或环境变量时,通常由以下原因导致: 1. **环境变量注入时机问题** Kubernetes 在容器启动时注入环境变量,之后不会更新。若 ConfigMap 更新后未重启 Pod,环境变量值不会刷新[^1]。 *示例*: ```yaml env: - name: APP_CONFIG valueFrom: configMapKeyRef: name: my-config key: config.json ``` 2. **ConfigMap 挂载更新延迟** - 默认情况下,kubelet 每 1 分钟同步一次 ConfigMap(由 `--sync-frequency` 控制)[^4]。 - 即使文件更新,应用程序可能未主动重新加载配置(如 Nginx 需手动触发重载)[^3]。 3. **挂载方式错误** 使用 `subPath` 挂载单个文件时,ConfigMap 更新**不会**同步到容器内[^4]。 4. **配置引用错误** ConfigMap 未正确关联到 Deployment 或 Pod,或键名(Key)拼写错误。 --- #### 二、排查步骤与解决方案 ##### 1. 确认环境变量注入状态 ```bash # 检查 Pod 的环境变量 kubectl exec <pod-name> -- env | grep <变量名> # 查看 ConfigMap 内容 kubectl get configmap <configmap-name> -o yaml ``` **解决方案**: - 若环境变量未更新,需重启 Pod(滚动更新或缩容/扩容)[^1]。 - 避免依赖环境变量传递动态配置,改用卷挂载。 ##### 2. 验证 ConfigMap 挂载 ```bash # 进入容器查看挂载文件内容 kubectl exec -it <pod-name> -- cat /etc/config/<file-name> # 检查文件更新时间 kubectl exec <pod-name> -- ls -l /etc/config/ ``` **解决方案**: - 若文件未更新: - 等待 1 分钟(kubelet 同步周期)[^4]。 - 执行强制同步:删除 Pod 触发重建(需确保副本数 >1)。 - **禁用 `subPath`**: ```yaml volumes: - name: config-volume configMap: name: my-config volumeMounts: - name: config-volume mountPath: /etc/config # 直接挂载目录而非文件 ``` ##### 3. 应用程序重新加载配置 - **手动触发**: ```bash # 例如 Nginx 重载配置 kubectl exec <pod-name> -- nginx -s reload ``` - **自动热更新**: 使用工具如 `Reloader` 监控 ConfigMap 变化并自动重启 Pod: ```bash kubectl apply -f https://github.com/stakater/Reloader/releases/latest/download/reloader.yaml ``` 在 Deployment 添加注解: ```yaml metadata: annotations: reloader.stakater.com/auto: "true" ``` ##### 4. Spring Boot 集成方案 若后端服务为 Spring Boot: 1. 添加依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes-client-config</artifactId> </dependency> ``` 2. 通过 `@RefreshScope` 动态更新配置: ```java @RestController @RefreshScope public class MyController { @Value("${custom.property}") private String value; } ``` 3. 访问端点刷新配置: ```bash curl -X POST http://pod-ip:port/actuator/refresh ``` [^2] --- #### 三、最佳实践 1. **优先使用卷挂载而非环境变量**: 环境变量适合静态配置,卷挂载支持动态更新[^3]。 2. **避免 `subPath` 挂载文件**: 如需挂载单个文件,改用符号链接或启动脚本拷贝文件。 3. **调整同步频率(谨慎操作)**: 修改 kubelet 参数(仅适用于测试环境): ```bash # 编辑 /etc/kubernetes/kubelet.conf syncFrequency: 5s # 降低同步延迟,但增加节点负载[^4] ``` 4. **配置健康检查**: 添加 `readinessProbe` 检测配置加载状态: ```yaml readinessProbe: exec: command: ["/bin/sh", "-c", "test -f /etc/config/validated"] initialDelaySeconds: 5 periodSeconds: 5 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值