3. Secret对象详解:类型、创建与查看、注入方式
Secret 在 Kubernetes 里就是用来存放敏感信息的,比如数据库密码、API 、TLS 证书。说白了,它和 ConfigMap 很像,但数据是经过 Base64 编码的,默认不会明文显示。我在生产环境里见过不少人直接把密码写死在镜像里,后来改了一次密码就得重新打包——太痛苦了。
我个人习惯:凡是不该出现在镜像里的敏感信息,都塞进 Secret。接下来我们把它的类型、创建方式、查看方法,还有两种挂载方式(环境变量、卷挂载)一起捋清楚。
3.1 Secret 的四种主要类型
Kubernetes 内置了几种 Secret 类型,我平时用得最多的是 Opaque。刚接触时容易糊涂:为什么同一个 Secret 还能分类型?
| 类型 | 用途 | 典型场景 |
|---|---|---|
Opaque | 通用型,任意键值对 | 数据库密码、 |
kubernetes.io/service-account- | 存放 ServiceAccount 的 | 自动创建,给 Pod 访问 API Server 用 |
kubernetes.io/dockercfg(或 kubernetes.io/dockerconfigjson) | 存放 Docker 镜像仓库认证信息 | 私有仓库拉镜像 |
kubernetes.io/tls | 存放 TLS 证书和私钥 | Ingress 证书、双向 TLS |
Opaque 就够了。如果你需要给 Pod 挂载一个 ServiceAccount,系统会自动生成对应的 service-account- Secret,你不需要手动管。
3.2 创建与查看 Secret
命令行创建很方便。我习惯先写一个 YAML 文件,方便版本管理。
3.2.1 使用 kubectl 创建
# 从字面量创建(最常用)
kubectl create secret generic db-cred \
--from-literal=username=admin \
--from-literal=password='P@ssw0rd!'
# 从文件创建(适合证书、ssh key)
kubectl create secret generic my-ssh-key \
--from-file=id_rsa=~/.ssh/id_rsa \
--from-file=id_rsa.pub
# 创建 TLS Secret
kubectl create secret tls my-tls \
--cert=path/to/tls.crt \
--key=path/to/tls.key
# 创建 Docker 镜像仓库认证
kubectl create secret docker-registry my-regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=my@email.com
3.2.2 使用 YAML 声明式创建
声明式方式可以把 Secret 放进 Git 仓库管理。注意:value 需要预先做 Base64 编码。
apiVersion: v1
kind: Secret
metadata:
name: db-cred
type: Opaque
data:
username: YWRtaW4= # admin
password: UEBzc3cwcmQh # P@ssw0rd!
kubectl apply -f 会把明文密码留在历史记录里。我建议用 kubectl create secret ... --dry-run=client -o yaml > secret.yaml 来生成,然后再 apply。
3.2.3 查看 Secret
# 列出所有 Secret
kubectl get secret
# 查看详情(不显示数据内容)
kubectl describe secret db-cred
# 查看完整数据(Base64 编码显示)
kubectl get secret db-cred -o yaml
# 解码查看实际值
kubectl get secret db-cred -o jsonpath='{.data.password}' | base64 --decode
其实 Base64 只是编码不是加密,拿到 yaml 的人随时可以解码。所以 Secret 的访问权限一定要通过 RBAC 严格控制。
3.3 环境变量注入方式
把 Secret 的值变成 Pod 里的环境变量,有两种写法:一种是把所有键值一股脑塞进去,另一种是挑单个字段。
3.3.1 批量注入(envFrom)
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: nginx
envFrom:
- secretRef:
name: db-cred # Secret 的所有 key 都变成环境变量
这样做很方便,但有一个坑:如果 Secret 中有 key 名的字符不合法(比如连字符),会被自动转换为下划线。我之前查问题查了半天才发现这个细节。
3.3.2 单个注入(valueFrom + secretKeyRef)
spec:
containers:
- name: app
image: nginx
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-cred
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-cred
key: password
我觉得这种方式更清晰:给环境变量重命名了,也避免了不需要的变量污染环境。
3.4 卷挂载方式
这是我最推荐的方式,特别适合需要热更新场景——比如证书轮换、配置动态刷新。
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/credentials
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-cred
挂载之后,Secret 里的每个 key 会变成文件名,value 变成文件内容:
# 在 Pod 里查看
$ ls /etc/credentials/
username password
$ cat /etc/credentials/username
admin
$ cat /etc/credentials/password
P@ssw0rd!
3.4.1 subPath 挂载单个文件
有时候你不想把整个 Secret 目录挂进去,只想挂一个 key 到已有目录里:
volumeMounts:
- name: secret-volume
mountPath: /etc/nginx/ssl/server.crt
subPath: tls.crt
readOnly: true
subPath 时,Secret 更新后 Pod 不会自动刷新文件内容!你只能手动重启 Pod 或删除 Pod 重建。想要热更新就必须挂载整个目录,不能只用 subPath。
3.5 卷挂载的动态更新原理
Kubelet 会定期(大约10秒)检查 Secret 是否有变化。如果更新了,它会更新 Pod 内的符号链接,让挂载文件内容实时变化。应用如果监听文件内容变化(比如重新加载证书),就能实现无中断更新。
我在生产环境里配合 cert-manager 做证书自动轮换,就是利用这个特性——证书到期前更新 Secret,Pod 里的 Nginx 检测到文件变更就 reload,整个流程不需要手动介入。
| 特性 | 环境变量 | 卷挂载 |
|---|---|---|
| 热更新 | ❌ 需要重启 Pod | ✅ 文件自动同步(10s内) |
| 管理便捷性 | ⭐ 简单,代码直接读取 | ⭐⭐ 需要处理文件IO |
| 敏感信息暴露 | 可通过 kubectl exec env 看到 | 只能读挂载的文件 |
| 适用场景 | 一次性配置,如连接字符串 | 证书、需要动态更新的配置 |