当前位置: 首页 > ai >正文

k8sday14数据存储(2/2)

目录

三、配置存储

1、ConfigMap(cm)

1.1创建方式

①、命令行直接给键值

②、从文件/目录导入

③、YAML 声明(最直观,可版本控制)

1.2使用(消费)方式

①、作为环境变量

②、作为卷挂载

③、作为命令行参数

1.3热更新

①、配置文件

②、测试热更新

③、实操画面

④、故障排查

Ⅰ、确认 ConfigMap 已经生效

Ⅱ、确认卷挂载方式

1.4不可改变状态

2、Secret

2.1核心特性

2.2常见类型

2.3创建方式

①、命令行给键值

②、从文件/目录导入

③、YAML声明

2.4使用(消费)方式

①、作为环境变量

②、作为卷挂载

2.5热更新

①、配置文件

②、测试热更新

③、实操画面

2.6查看和管理

2.7不可改变状态


按照生命周期,我们大致可以将数据存储分为两类:注入和共享

①、注入:把数据“塞进”容器——生命周期跟 Pod 走

注入型数据:

  • ConfigMap

  • Secret

  • Downward API

②、共享:把数据“挂出来”让多个 Pod/节点同时用——生命周期独立于 Pod

共享型数据:

  • emptyDir

  • hostPath

  • PV(PVC)

  • NFS

三、配置存储

1、ConfigMap(cm)

1.1创建方式
①、命令行直接给键值
  # 定义一个叫 app-cfg 的 ConfigMap# 内含两个键值对:APP_NAME=myapp、LOG_LEVEL=infokubectl create configmap app-cfg \--from-literal=APP_NAME=myapp \--from-literal=LOG_LEVEL=info

适用于键值对较简短,数量较少

②、从文件/目录导入
  # 把 nginx.conf 文件导入挂成 key=nginx.conf# 即 nginx.conf 内部所有全变为值导入,文件名做 key,内容做 valuekubectl create configmap nginx-cfg \--from-file=nginx.conf​# 整个目录导入,文件名做 key,内容做 valuekubectl create configmap redis-cfg \--from-file=./redis.d/

适用于键值对较多,将所有要注入的键值对编辑进同一个文件,再将文件导入即可

③、YAML 声明(最直观,可版本控制)
  apiVersion: v1kind: ConfigMap         # 声明资源类型是 ConfigMapmetadata:               # 元数据name: game-config     # 自定义的 ConfigMap名称data:                   # 定义数据段(键值对)# 简单键值enemy_speed: "10"# 多行文本game.properties: |enemies=alienslives=3
1.2使用(消费)方式

注意:Pod “消费” ConfigMap 是在你的 ConfigMap 已经创建好,存在的前提下

①、作为环境变量
  apiVersion: v1kind: Podmetadata:name: mypodspec:containers:- name: mycontainerimage: busybox:1.36.1  # 方式 A:单个键值的注入env:- name: APP_NAME          # 容器内部变量名valueFrom:              # 值的来源configMapKeyRef:name: my-configmap  # 已创建的 ConfigMap 的名字key: app_name       # ConfigMap 中的键# 即在当前命名空间找一个名为 my-configmap 的 ConfigMap,找出其中名为 app_name 的键,将其对应的值注入容器给容器内变量 APP_NAME# 方式 B:一次性导入整个 ConfigMapenvFrom:- configMapRef:name: my-configmap     # 已创建的 ConfigMap 的名字# 把 app-cfg 的所有键值对一次性注入容器,变量名 = 键名,变量值 = 键值restartPolicy: Never         # 重启策略设为永不重启,方便测试
②、作为卷挂载
  apiVersion: v1kind: Podmetadata:name: mypodspec:containers:- name: mycontainerimage: busybox:1.36.1 volumeMounts:- name: config-volume     # 必须与下面 volumes.name 一致,建立“卷 → 容器”映射mountPath: /etc/config  # 挂载到容器内的路径,原有目录内容会被完全隐藏volumes:- name: config-volume         # 必须与上面 volumeMounts.name 一致,建立“卷 → 容器”映射configMap:name: my-configmap        # 引用 ConfigMap# optional: 可指定特定键或文件权限items:  - key: config-file      # 获取 ConfigMap 里叫 config-file 的那一条path: custom-name.confmode: 0644           # 文件权限,默认为 0644;若要可执行,可改成 0755# 最终容器 /etc/config/custom-name.conf 内容就是config-file 的内容restartPolicy: Never         # 重启策略设为永不重启,方便测试
③、作为命令行参数
  apiVersion: v1kind: Podmetadata:name: mypodspec:containers:- name: mycontainerimage: busybox:1.36.1 env:- name: APP_NAME         # 容器内部变量名valueFrom:             # 值的来源configMapKeyRef:name: my-configmap # 已创建的 ConfigMap 的名字key: app_name      # ConfigMap 中的键command: ["/bin/sh", "-c", "echo $(APP_NAME)"] # 容器启动后立即打印APP_NAME的值# 即在当前命名空间找一个名为 my-configmap 的 ConfigMap,找出其中名为 app_name 的键,将其对应的值注入容器给容器内的变量 APP_NAMErestartPolicy: Never         # 重启策略设为永不重启,方便测试
1.3热更新

“环境变量注入”和“subPath 挂载”这两种方式 都不能实现 ConfigMap/Secret 的热更新;其余(非 subPath 的卷挂载)在 kubelet 默认机制下可以热更新,但存在 10-60 秒的延迟。

①、配置文件
  # nginx-cm.yaml# 1) 创建 ConfigMap:里面是 nginx.conf 的 server 块apiVersion: v1kind: ConfigMapmetadata:name: nginx-cm             # ConfigMap 名称data:nginx.conf: |server {listen 8080;location / {root   /usr/share/nginx/html;index  index.html;}}​---# 2) 创建 Deployment:通过卷挂载方式把 nginx.conf 挂进去apiVersion: apps/v1               # Deployment 的API的版本kind: Deployment                  # 声明资源类型是 Deploymentmetadata:name: hot-reload-deploynamespace: default              # 目标命名空间​spec:replicas: 2                     # 期望的 Pod 副本数selector:                       # 选择器,告诉 Deployment 它要管理哪些 PodmatchLabels:                  # 按照标签匹配app: nginx                  # 必须与下方 Pod 模板的 template.metadata.labels 一致template:                       # Pod 模板,通过这个模板创建副本metadata:                     # Pod 的元信息labels:app: nginx                # Pod 标签,必须与上方的 selector.matchLabels 一致spec:containers:- name: nginximage: nginx:1.24.0ports:- containerPort: 8080volumeMounts:- name: conf-vol        # 与 volumes.name 对应mountPath: /etc/nginx/conf.d/default.conf  # 容器内目标文件# 注意:这里用的是 subPath 挂单个文件,永远不会热更新,建议修改为:# mountPath: /etc/nginx/conf.d   # 不再用 subPath# 这是我做完测试才明白的后来加上的subPath: nginx.conf   # 只挂 ConfigMap 里的 nginx.conf 键volumes:- name: conf-volconfigMap:name: nginx-cmdefaultMode: 0644       # 文件权限
②、测试热更新
  # 测试步骤:# 1. 应用文件创建 Pod 和 ConfigMapkubectl apply -f nginx-cm.yaml​# 2. 验证是否创建成功kubectl get pod kubectl get deploy hot-reload-deploy -o wide​# 3. 编辑 ConfigMap,把其中的listen 8080 改成 8081kubectl edit cm nginx-cm​# 4. 使配置生效# Nginx(包括容器里的 Nginx)不会在配置文件变化后自动 reload;# 必须显式给它发 HUP 信号(nginx -s reload)或重启进程(打补丁),使配置文件生效# 方案一:使用reloader# (注意Reloader 是一个外部控制器,必须事先部署在集群中,否则这个注解不会生效)# 打补丁,给 Deployment 加 1 行注解即可kubectl patch deployment  hot-reload-deploy -p '{"metadata":{"annotations":{"configmap.reloader.stakater.com/reload":"nginx-cm"}}}'# 或直接在创建yaml文件的时候加上metadata:annotations:configmap.reloader.stakater.com/reload: "nginx-cm"# 方案二:deployment的滚动更新# 修改一个无关紧要的注解来触发滚动更新kubectl annotate pod <你自己的pod名> force-reload="$(date +%s)" --overwritekubectl rollout restart deploy hot-reload-deploy​# 5. 进入容器查看目标文件kubectl exec hot-reload-pod -- cat /etc/nginx/conf.d/default.conf# 能看到端口已变成 8081,无需重启 Pod
③、实操画面

④、故障排查

在做上面热更新测试的时候,最多遇到的就是即使我修改了 ConfigMap 配置文件,再次进入目标文件发现仍然没有进行热更新,大致有两个问题:

  1. kubelet 还没把新的 ConfigMap 同步进 Pod 的卷目录;

  2. subPath 的文件不会随 ConfigMap 更新而更新 ——这是 K8s 官方已知的限制。

    以下给出排除步骤:

Ⅰ、确认 ConfigMap 已经生效
  kubectl get cm <你自己创建的ConfigMap名称> -o yaml | grep 8081​# 预计输出(如果你是改为了8081)# listen 8081;# 如果没有输出,说明kubelet 还没把新的 ConfigMap 同步进 Pod 的卷目录,需等待一会
Ⅱ、确认卷挂载方式
  • 如果你用的是 subPath 挂单个文件,那么 永远不会热更新,如以上我们挂载路径用的是 /etc/nginx/conf.d/default.conf(由 subPath 挂出的单个文件)

解决方案:

  • 安装reloader,进行打补丁

  # 安装reloaderkubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml​# 打补丁,给 Deployment 加 1 行注解即可kubectl patch deployment  hot-reload-deploy -p '{"metadata":{"annotations":{"configmap.reloader.stakater.com/reload":"nginx-cm"}}}'# 或直接在创建yaml文件的时候加上metadata:annotations:configmap.reloader.stakater.com/reload: "nginx-cm"
  • 直接重建 Deployment(一次性)

  kubectl rollout restart deployment nginx-deploy
  • 触发滚动更新

  # 修改一个无关紧要的注解来触发滚动更新kubectl annotate pod <你自己的pod名> force-reload="$(date +%s)" --overwritekubectl rollout restart deploy hot-reload-deploy
  • 去掉 subPath,改用卷目录挂载(较麻烦)

  # nginx-deploy.yaml 片段volumeMounts:- name: confmountPath: /etc/nginx/conf.d   # 不再用 subPathvolumes:- name: confconfigMap:name: nginx-cm
1.4不可改变状态

禁止ConfigMap被修改的好处:

  • 防止非预期的更新或变化导致应用程序关闭,避免恶意修改

  • 通过设置为不可改变状态,停止kube-apiserver对ConfigMap的监视,降低kube-apiserver的负载压力,提升集群性能

设置为不可改变状态方法:在创建ConfigMap的yaml配置文件中加入immutable: true即可。

注意:一旦 ConfigMap 被标记为 immutable: true该字段就是不可变的Kubernetes 不允许将 immutable: true 改为 false 或直接删除该字段。因此,没有办法“就地”把同一个 ConfigMap 改回可修改状态

如果你想修改其文件,只能删除标记了immutable: true的集群,重新创建并应用。

2、Secret

注意:Secret只是一种较ConfigMap而言,复杂一点的加密,不可将其当作加密十分重要数据的唯一手段。

2.1核心特性

加密存储:Secret 的数据默认以 Base64 编码存储(非加密,仅编码),但可以结合 Kubernetes etcd 加密或第三方工具(如 HashiCorp Vault)实现真正加密。

与 ConfigMap 的区别:

  • ConfigMap:存储非敏感配置(如环境变量、配置文件)。

  • Secret:专用于敏感数据,但本质上仍然是 Base64 编码的键值对。

常用于:

  • 数据库密码、API 密钥。

  • TLS 证书(tls 类型 Secret)。

  • Docker 镜像仓库认证(docker-registry 类型 Secret)

给出 ConfigMap 和 Secret 的描述区别,二者内部我都创建了username(admin)和passward(S!B*d$zDsb=),配置文件和对比结果均给出:

  # 创建一个名为cmtest的 ConfigMap kubectl create configmap cmtest \--from-literal=username=admin \--from-literal=passward='S!B*d$zDsb='# 创建一个名为secrettest的 Secret kubectl create secret generic secrettest \--from-literal=username=admin \--from-literal=password='S!B\*d$zDsb='# 查看二者信息kubectl describe configmap cmtest kubectl describe secret secrettest

当然要想获得Secret的passward和username并不困难,只需获取其配置文件,再基于base64解码即可,所以说不可将Secret作为唯一手段去加密你的重要文件,它只是比ConfigMap好一点

2.2常见类型

Kubernetes 支持多种类型的 Secret:

类型用途
Opaque(默认)存储任意用户定义的敏感数据(如用户名、密码)。
kubernetes.io/tls存储 TLS 证书和私钥(用于 HTTPS)。
kubernetes.io/dockerconfigjson存储 Docker 镜像仓库的认证信息(用于拉取私有镜像)。
kubernetes.io/basic-auth存储基本认证所需的用户名和密码。
2.3创建方式

总体来说,Secret的创建方式和ConfigMap的创建方式类似

①、命令行给键值
  # 从键值对创建kubectl create secret generic my-secret \--from-literal=username=admin \--from-literal=passward='S!B\*d$zDsb='
②、从文件/目录导入
  # 从文件创建(如证书、配置文件)kubectl create secret generic ssl-cert \--from-file=./ssl.crt \--from-file=./ssl.key
③、YAML声明
  apiVersion: v1kind: Secretmetadata:name: my-secrettype: Opaque  # 默认类型data:username: YWRtaW4=  # echo -n "admin" | base64password: UyFCX2QkekRzYj0=  # echo -n "S!B\*d$zDsb=" | base64

注意:当使用Secret时,你填写进入的value需要提前对你本身的value进行base64的编码,将编码后得到的结果赋给键,才可以使用。

如你要输入的username是admin, 你需要先对admin进行base64编码,得到YWRtaW4,再将YWRtaW4赋给username,如果直接将admin赋给username会得到乱码

2.4使用(消费)方式
①、作为环境变量
  apiVersion: v1kind: Podmetadata:name: my-podspec:containers:- name: my-containerimage: nginx:1.24.0env:                        # 环境变量- name: DB_USERNAME         # 容器内已有的变量valueFrom:                # 值来源secretKeyRef:name: my-secret       # 已创建的 Secret 的名称key: username         # 已创建的 Secret 中的键- name: DB_PASSWORD         # 容器内已有的变量valueFrom:                # 值来源secretKeyRef:name: my-secret       # 已创建的 Secret 的名称key: password         # 已创建的 Secret 中的键# 即将名字为 my-secret 的已创建的 Secret 中的键 username 和 password 所对应的值注入容器,赋给容器内的 DB_USERNAME 和 DB_PASSWORD 这两个变量   
②、作为卷挂载
  apiVersion: v1kind: Podmetadata:name: secret-volume-podspec:containers:- name: nginximage: nginx:1.24.0volumeMounts:- name: secret-volume           # 必须与下面 volumes.name 一致,建立“卷 → 容器”映射mountPath: "/etc/secrets"     # 把下面定义的卷 secret-volume 挂载到容器内路径 /etc/secretsreadOnly: true                # 只读权限volumes:- name: secret-volume             # 定义一个名为 secret-volume 的卷secret:secretName: my-secret         # 数据卷的数据来源是一个名叫my-secret的 Secret# /etc/secrets/username   # 内容为 Secret 中 username 键对应的明文# /etc/secrets/password   # 内容为 Secret 中 password 键对应的明文
2.5热更新

“环境变量注入”和“subPath 挂载”这两种方式 都不能实现 ConfigMap/Secret 的热更新;其余(非 subPath 的卷挂载)在 kubelet 默认机制下可以热更新,但存在 10-60 秒的延迟。

①、配置文件

给出我的一个实现热更新的配置文件

  # nginx-secret.yaml# 1) 创建 Secret:里面包含一个password(abcdefg)和username(admin)apiVersion: v1kind: Secretmetadata:name: my-secrettype: Opaque  # 默认类型data:username: YWRtaW4=      # echo -n "admin" | base64password: YWJjZGVmZw==  # echo -n "abcdefg" | base64​---# 2) 创建 Deployment:通过卷挂载方式把 Secret 挂载到容器内apiVersion: apps/v1               # Deployment 的API的版本kind: Deployment                  # 声明资源类型是 Deploymentmetadata:name: hot-reload-deploynamespace: default              # 目标命名空间spec:replicas: 2                     # 期望的 Pod 副本数selector:                       # 选择器,告诉 Deployment 它要管理哪些 PodmatchLabels:                  # 按照标签匹配app: nginx                  # 必须与下方 Pod 模板的 template.metadata.labels 一致template:                       # Pod 模板,通过这个模板创建副本metadata:                     # Pod 的元信息labels:app: nginx                # Pod 标签,必须与上方的 selector.matchLabels 一致spec:containers:- name: nginximage: nginx:1.24.0volumeMounts:- name: secret-volume           # 必须与下面 volumes.name 一致,建立“卷 → 容器”映射mountPath: "/etc/secrets"     # 把下面定义的卷 secret-volume 挂载到容器内路径 /etc/secretsreadOnly: true                # 只读权限volumes:- name: secret-volume             # 定义一个名为 secret-volume 的卷secret:secretName: my-secret         # 数据卷的数据来源是一个名叫my-secret的 Secret# /etc/secrets/username   # 内容为 Secret 中 username 键对应的明文# /etc/secrets/password   # 内容为 Secret 中 password 键对应的明文
②、测试热更新
  # 进入并编辑secret的yaml文件kubectl edit secret my-secret​# 得到要修改的base64的值echo -n "<你要修改的值>" | base64​# 保存后触发 Pod 重启kubectl rollout restart deploy hot-reload-deploy
③、实操画面

2.6查看和管理
  # 查看所有 Secretkubectl get secrets​# 查看某个 Secret 的详细信息kubectl describe secret my-secret​# 解码 Secret 内容(Base64)kubectl get secret my-secret -o jsonpath='{.data.password}' | base64 --decode​# 删除 Secretkubectl delete secret my-secret
2.7不可改变状态

Secret和ConfigMap都有immutable的标记

禁止Secret被修改的好处:

  • 防止非预期的更新或变化导致应用程序关闭,避免恶意修改

  • 通过设置为不可改变状态,停止kube-apiserver对Secret的监视,降低kube-apiserver的负载压力,提升集群性能

设置为不可改变状态方法:在创建Secret的yaml配置文件中加入immutable: true即可。

注意:一旦 Secret 被标记为 immutable: true该字段就是不可变的Kubernetes 不允许将 immutable: true 改为 false 或直接删除该字段。因此,没有办法“就地”把同一个 Secret 改回可修改状态

如果你想修改其文件,只能删除标记了immutable: true的集群,重新创建并应用。

http://www.xdnf.cn/news/18384.html

相关文章:

  • RSS与今日头条技术对比分析
  • 代码随想录刷题Day40
  • Linux 软件包安装和管理的相关操作及使用总结(未完成)
  • 漏洞分析 | Kafka Connect 任意文件读取漏洞(CVE-2025-27817)
  • 如何使用AI大语言模型解决生活中的实际小事情?
  • 【Protues仿真】基于AT89C52单片机的LCD液晶显示屏显示控制
  • 如何在 Axios 中处理多个 baseURL 而不造成混乱
  • portainer-ce汉化版下载
  • 从零开始的云计算生活——第四十九天,长路漫漫,kubernetes模块之持久化存储
  • 拆解本地组策略编辑器 (gpedit.msc) 的界面和功能
  • Kafka消息丢失的场景有哪些
  • ThingsBoard运行linux应用版本
  • FPGA设计中的信号完整性量化与优化:探索高速数字系统的关键路径
  • CVPR 2025 | 哈工大港大DeCLIP:解耦CLIP注意力实现开放词汇感知!
  • 车载中控:汽车的数字大脑与交互核心
  • 【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机驱动
  • CISP-PTE之路--14文
  • JavaEE 初阶第二十期:网络编程“通关记”(二)
  • 数字隔离器:新能源系统的安全与效能革命
  • 【GM3568JHF】FPGA+ARM异构开发板 测试命令
  • 从零搭建 React 工程化项目
  • 深入解析鸿蒙 ArkTS 中的 @Local 装饰器
  • 【解决办法】wps的word文档编辑时字体的下方出现灰色的底色如何删除
  • CAM可视化卷积神经网络
  • 深度学习:入门简介
  • AI推理革命:从Sequential Thinking到Agentic AI的演进之路——揭秘大语言模型思维进化的四重奏
  • 上海人工智能实验室开源基于Intern-S1同等技术的轻量化开源多模态推理模型
  • logback-spring.xml 文件
  • 车载 GPS 与手机导航的终极对决:谁在复杂路况下更胜一筹?
  • UE5 将纯蓝图项目转为 C++ 项目