3. Secret对象详解:类型、创建与查看、注入方式

Secret 在 Kubernetes 里就是用来存放敏感信息的,比如数据库密码、API 、TLS 证书。说白了,它和 ConfigMap 很像,但数据是经过 Base64 编码的,默认不会明文显示。我在生产环境里见过不少人直接把密码写死在镜像里,后来改了一次密码就得重新打包——太痛苦了。

我个人习惯:凡是不该出现在镜像里的敏感信息,都塞进 Secret。接下来我们把它的类型、创建方式、查看方法,还有两种挂载方式(环境变量、卷挂载)一起捋清楚。

Secret 核心流程:创建 → 注入 创建 Secret kubectl create secret generic / tls / docker-registry 或 YAML 声明式 查看 Secret kubectl get secret kubectl describe secret kubectl get secret -o yaml 注入方式 ① 环境变量 ② 卷挂载 (文件/目录) Pod 使用示例 envFrom + secretRef Pod 使用示例 volumes + secret + mount ⚠ 卷挂载方式下,Secret 更新后文件会同步更新(最多10s延迟) 环境变量方式则不会自动同步,需要重启 Pod

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
我个人经验: 90% 的场景用 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

我觉得这种方式更清晰:给环境变量重命名了,也避免了不需要的变量污染环境。

避坑: 环境变量注入的 Secret 是 Pod 启动时一次性读取的。假如你更新了 Secret,Pod 里的环境变量不会自动刷新。必须重启 Pod 才行。如果你需要热更新,请用卷挂载方式。

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 看到只能读挂载的文件
适用场景一次性配置,如连接字符串证书、需要动态更新的配置