Kubernetes(K8s)笔记Day09 下 :加密配置管理中心 Secret 讲解与应用实例
一、Secret 概述
1.1 什么是 Secret?
简单来说,Secret 就是 ConfigMap 的“加密版”——专门用来存敏感数据的
Secret 是 Kubernetes 中用于保存敏感数据的资源对象,如密码、Token、密钥等。它的设计目的与 ConfigMap 类似——将配置与镜像解耦,但专门针对机密性数据。
ConfigMap vs Secret:ConfigMap 存放明文配置(如配置文件),Secret 存放敏感数据(如密码、私钥)。两者功能相似,但 Secret 在存储和传输中做了编码处理。
Secret 可以以Volume 挂载或环境变量的方式被 Pod 使用。
需注意:Secret本质就是“加密版”的ConfigMap,二者在源码层面是同一种数据结构(data 字段)的不同包装,所以在语法上有惊人的相似度,使用方法也几乎完全一致
1.2 Secret 的可选类型
| 类型 | 用途 |
|---|---|
generic(通用) | 最常用,用于存储密码、密钥等普通敏感数据 |
tls | 专门用于存储 TLS 私钥和证书 |
docker-registry | 用于存储私有 Docker 仓库的认证信息 |
kubernetes.io/service-account-token | 由 Kubernetes 自动创建,用于 ServiceAccount 身份认证 |
关于 ServiceAccount 的自动挂载:每个 ServiceAccount 创建时,Kubernetes 会为其自动创建一个对应的 Secret,并挂载到 Pod 的
/run/secrets/kubernetes.io/serviceaccount目录下,用于 Pod 与 API Server 之间的认证通信。
1.3 Secret 的数据编码
Secret 的数据并非加密,而是Base64 编码。Base64 只是将原始数据转换成可打印字符,不属于真正的加密,可以轻松解码回原文。因此:
Secret 只是比 ConfigMap 多了一层编码,并非安全加密。对于极高安全要求的场景,建议配合外部加密工具(如 HashiCorp Vault)使用。
Base64 编码示例:
# 编码[root@hd1 ~]# echo -n 'admin' | base64YWRtaW4=[root@hd1 ~]# echo -n '123456' | base64MTIzNDU2# 解码[root@hd1 ~]# echo MTIzNDU2 | base64 -d123456二、使用 Secret
2.1 通过环境变量引入 Secret(secretKeyRef)
场景:将 Secret 中的某个 key 的值注入为 Pod 容器的环境变量。
语法:kubectl create secret <secret类型> <secret名> --from-literal=<key>=<value>
步骤1:创建 Secret
# 创建一个名为 mysql-password ,类型为 generic 的 Secret,包含 password=heihei66[root@hd1 ~]# kubectl create secret generic mysql-password --from-literal=password=heihei66# 查看 Secret 列表[root@hd1 ~]# kubectl get secretNAME TYPE DATA AGE mysql-password Opaque130s# 查看 Secret 详情(注意:实际值显示为字节数,不展示原文)[root@hd1 ~]# kubectl get secret mysql-password -o yamlapiVersion: v1 data: password:aGVpaGVpNjY=kind: Secret metadata: creationTimestamp:"2026-08-05T12:30:32Z"name: mysql-password namespace: default resourceVersion:"253749"uid: 47ee1b04-9fa9-4741-ba76-454d4271f1a2 type: Opaque[root@hd1 ~]# kubectl describe secret mysql-passwordName: mysql-password Namespace: default Labels:<none>Annotations:<none>Type: Opaque Data====password:8bytes#这里并不会显示出我们的数据信息#验证存入的是base64编码[root@hd1 ~]# kubectl get secret mysql-password -o yamlapiVersion: v1 data: password:aGVpaGVpNjY=#这里就是刚刚存入的数据,并非明文步骤2:创建 Pod 引用该 Secret
[root@hd1 ~]# cat pod-secret.yamlapiVersion:v1kind:Podmetadata:name:pod-secretlabels:app:myappspec:containers:-name:myappimage:mysql:8.0imagePullPolicy:IfNotPresentports:-name:mysqlcontainerPort:3306env:-name:MYSQL_ROOT_PASSWORD# Pod 中的环境变量名,这个环境变量,对于使用官方 MySQL 容器镜像来说是必须的valueFrom:#与 secretKeyRef 作用一致secretKeyRef:name:mysql-password# Secret 名称key:password# 指定Secret 中的 key可以看得出来,secret和ConfigMap的使用方法几乎完全一致
[root@hd1 ~]# kubectl apply -f pod-secret.yaml# 验证:进入 Pod 查看环境变量[root@hd1 ~]# kubectl exec -it pod-secret -- /bin/bash/# printenvMYSQL_ROOT_PASSWORD=heihei662.2 通过 Volume 挂载 Secret
使用yaml文件创建 Secret
方法一:手动创建加密数据
步骤1:手动创建包含 Base64 编码数据的 Secret
[root@hd1 ~]# echo -n 'admin' | base64YWRtaW4=[root@hd1 ~]# echo -n '123456' | base64MTIzNDU2步骤2:编写 Secret YAML 文件
[root@hd1 ~]# vim secret.yamlapiVersion:v1kind:Secretmetadata:name:mysecrettype:Opaquedata:username:YWRtaW4=# base64 编码后的 adminpassword:MTIzNDU2# base64 编码后的 123456方法二:使用stringData:可以让它自动生成
注意,我们使用stringData:可以让它自动生成
[root@hd1 ~]# vim secret.yamlapiVersion:v1kind:Secretmetadata:name:mysecrettype:OpaquestringData:#使用stringData: 直接配置明文即可username:"admin"password:"123456"[root@hd1 ~]# kubectl apply -f secret.yaml[root@hd1 ~]# kubectl get secret mysecret -o yamlapiVersion: v1 data: password: MTIzNDU2 username:YWRtaW4=步骤3:将 Secret 以 Volume 形式挂载到 Pod
[root@hd1 ~]# vim pod_secret_volume.yamlapiVersion:v1kind:Podmetadata:name:pod-secret-volumespec:containers:-name:myappimage:docker.io/library/nginx:latestimagePullPolicy:IfNotPresentvolumeMounts:-name:secret-volumemountPath:/etc/secretreadOnly:truevolumes:-name:secret-volumesecret:#指定类型为secretsecretName:mysecret#secret名称[root@hd1 ~]# kubectl apply -f pod_secret_volume.yaml# 验证:Secret 数据在 Pod 中被解密为明文[root@hd1 ~]# kubectl exec -it pod-secret-volume -- /bin/bashroot@pod-secret-volume:/# ls /etc/secretpassword username#已经翻译成明文root@pod-secret-volume:/# cat /etc/secret/usernameadmin root@pod-secret-volume:/# cat /etc/secret/password123456关键理解:Secret 存储在 etcd 中是 Base64 编码的,但挂载到 Pod 后,kubelet 会自动解码,所以容器内读取到的是明文。
2.3 Docker 私有仓库认证:docker-registry类型
场景:Pod 需要从私有 Docker 仓库拉取镜像时,需要提供仓库认证信息。
步骤1:创建 docker-registry 类型的 Secret
创建一个docker镜像仓库类型的Secret,命名为regcred
格式为:kubectl create secret docker-registry regcred \ --docker-server=<你的镜像仓库服务器> \ --docker-username=<你的用户名> \ --docker-password=<你的密码> \ --docker-email=<你的邮箱地址>
导入我们阿里云容器镜像服务(ACR,Alibaba Cloud Container Registry) 的凭证
#会在当前 Namespace 下创建一个docker-registry类型,名为 regcred 的 Secret[root@h1 ~]# kubectl create secret docker-registry regcred \--docker-server=registry.cn-hangzhou.aliyuncs.com\--docker-username=wmbenet@126.com\--docker-password=123.com.凭证获取步骤:
镜像服务
管理后台
进入镜像仓库
步骤2:在 Pod 中引用该 Secret 拉取私有镜像
[root@h3 ~]# cat pod_secret_docker.yamlapiVersion:v1kind:Podmetadata:name:private-regspec:containers:-name:private-reg-containerimage:<your-private-image># 替换为你的私有镜像地址imagePullSecrets:# 【核心字段】拉取镜像时使用的凭证列表-name:regcred# 引用上一步创建的 Secret注意:
imagePullSecrets字段设置在 Pod 级别,而非容器级别,表示拉取该 Pod 的所有镜像时使用的认证信息。
2.4 TLS 证书与私钥:tls类型
场景:为 Ingress 或服务间通信配置 TLS 证书。
语法:kubectl create secret tls tls-secret \ --cert=path/to/tls.cert \ #证书路径 --key=path/to/tls.key #私钥路径
#生成证书和私钥[root@hd1 ~]# openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout abc.key -out abc.crt#将证书和私钥变成secret[root@hd1 ~]# kubectl create secret tls tls-secret --cert=abc.crt --key=abc.keysecret/tls-secret created这个 Secret 的应用场景示例:
我们创建的这个 tls-secret,最典型的用法是挂载到 Ingress(网关) 上,让集群对外提供 HTTPS 服务
apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:example-ingressspec:tls:-hosts:-www.myapp.comsecretName:tls-secret# 引用你刚才创建的 TLS Secretrules:-host:www.myapp.comhttp:paths:-path:/backend:service:name:my-serviceport:number:80三、综合案例:部署 MySQL 并集成 ConfigMap + Secret
3.1 案例要求
- 用 Deployment 部署一个 MySQL 数据库
- 将
my.cnf做成 ConfigMap,修改端口为33060,传入 Pod 配置文件路径 - 将 MySQL root 密码做成 Secret,以环境变量方式传入 Pod
3.2 实现步骤
步骤1:创建 ConfigMap(MySQL 配置文件)
# mysql-configmap.yamlapiVersion:v1kind:ConfigMapmetadata:name:mysql-configdata:my.cnf:|[mysqld] port=33060 socket=/var/run/mysqld/mysqld.sock这段配置是把mysql的端口改成了33060,并指定了sock文件的路径
[root@hd1 ~]# kubectl apply -f mysql-configmap.yaml步骤2:创建 Secret(MySQL root 密码)
这个就是我们在上文创建的
[root@hd1 ~]# kubectl create secret generic mysql-password --from-literal=password=123456步骤3:创建 PVC(持久化存储)
这里使用的是存储类,还是我们之前创建的那个。忘记的可以回去看:Kubernetes(K8s)笔记Day06: 持久化存储7.4的步骤5和步骤6,把供应商和sc拉起来就行了
# mysql-pvc.yamlapiVersion:v1kind:PersistentVolumeClaimmetadata:name:mysql-pv-claimspec:storageClassName:nfsaccessModes:-ReadWriteOnceresources:requests:storage:2Gi[root@hd1 ~]# kubectl apply -f mysql-pvc.yaml步骤4:创建 Deployment(整合所有配置)
# mysql-deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:mysqlspec:selector:matchLabels:app:mysqlstrategy:type:Recreate# 重建策略:先删旧 Pod,再建新 Pod(不是滚动更新!)template:metadata:labels:app:mysqlspec:containers:-image:mysql:8.0name:mysqlenv:-name:MYSQL_ROOT_PASSWORD#这个是注入mysql密码的标准的变量名称valueFrom:# 从外部资源取值secretKeyRef:#使用secret导入环境变量(依旧是mysql的密码)name:mysql-password#指定导入的secret名称key:password# Secret 中的键名ports:-containerPort:33060name:mysqlvolumeMounts:# 【存储挂载】容器内的挂载点-name:mysql-persistent-storagemountPath:/var/lib/mysql# MySQL 数据目录(存放库表文件)-name:mysql-config-volumemountPath:/etc/my.cnfsubPath:my.cnf#关键点,加上这个,在挂载的时候就不会完全覆盖目标路径,而是把特定文件导入,只替换这一个文件volumes:-name:mysql-persistent-storagepersistentVolumeClaim:claimName:mysql-pv-claim-name:mysql-config-volumeconfigMap:# 使用 ConfigMap 作为配置源name:mysql-config# ConfigMap 名称这个配置文件利用了configmap的特性( secret 也一样),configmap的字段挂载进pod会变成文件,以此挂载用来替换特定的配置文件
[root@hd1 ~]# kubectl apply -f mysql-deployment.yaml3.3 案例总结
这个案例利用ConfigMap 实现配置文件外置(端口修改),利用Secret 实现密码安全注入(环境变量),利用PVC 实现数据持久化(存储保留),利用Deployment 的 Recreate 策略保障单实例存储安全,最终完成了一个“配置可调、密码安全、数据不丢”的标准 MySQL 容器化部署
四、扩展命令:kubectl port-forward
kubectl port-forward能够在本地主机和Kubernetes 集群中的 Pod之间建立端口转发,用于开发和调试场景。
作用:在不修改 Service 暴露配置(如 LoadBalancer 或 NodePort)的情况下,直接从本地访问集群内部的服务或应用。
kubectl delete pod --all
常用命令
# 监听宿主机的回环接口(127.0.0.1)kubectl port-forward<pod-name>8000:8080# 监听宿主机的所有接口(可被外部访问)kubectl port-forward--address0.0.0.0<pod-name>8000:8080示例:如果你在集群中运行了一个 Web 应用(Pod 内监听 8080 端口),想在本机浏览器查看,执行kubectl port-forward <pod-name> 8000:8080后,即可通过http://127.0.0.1:8000访问该应用。
五、核心知识点速查
ConfigMap vs Secret 对比
| 特性 | ConfigMap | Secret |
|---|---|---|
| 用途 | 存储非机密配置数据 | 存储敏感数据(密码、密钥、证书) |
| 数据格式 | 明文 | Base64 编码(非加密,仅编码) |
| 大小限制 | ≤ 1 MiB | ≤ 1 MiB |
| 使用方式 | 环境变量 / Volume | 环境变量 / Volume / imagePullSecrets |
| 热更新 | Volume 方式支持 | Volume 方式支持 |
Secret 使用方式总结
| 使用方式 | 适用场景 | 示例 |
|---|---|---|
环境变量(secretKeyRef) | 将单个 key 注入为环境变量 | MySQL 密码注入为MYSQL_ROOT_PASSWORD |
| Volume 挂载 | 将 Secret 作为文件挂载到目录 | TLS 证书、配置文件挂载 |
| imagePullSecrets | 私有仓库镜像拉取认证 | 从阿里云 ACR 拉取镜像 |
Secret 类型速查
| 类型 | 用途 |
|---|---|
Opaque(通用) | 存储任意敏感数据(密码、API Key) |
kubernetes.io/dockerconfigjson | Docker 私有仓库认证 |
kubernetes.io/tls | TLS 证书和私钥 |
kubernetes.io/service-account-token | ServiceAccount 认证(系统自动创建) |
关键注意事项
| 注意点 | 说明 |
|---|---|
| Base64 不是加密 | Secret 仅做编码,不提供真正的加密保护 |
| 密钥大小限制 | Secret 数据大小 ≤ 1 MiB |
| 命名空间隔离 | Secret 只能被同一命名空间的 Pod 引用 |
| 热更新支持 | Volume 方式支持热更新,环境变量方式不支持 |
