写在开头:
最近因为业务上的需求涉及到k8s原生对象Secret的开发,之前有浅尝辄止地了解过一些Secret的知识点,但还没有真正开发过secret,所以此次把一些之前未注意到的小细节在这里给记了下来。
Secret简介
- Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。
- Secret中保存的信息可以在Pod的Spec或者镜像中使用,且Secret的生命周期独立于使用它们的Pod。
- 默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。 任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。
data和stringData的区别
- 在Secret中存储内容时,可以设置成
data
或者stringData
字段,它们的区别是,data
字段中所有键值都必须是base64
编码的字符串,而stringData
则可以使用任何字符串。 data
和stringData
中的键名只能包含字母、数字、-
、_
或.
字符,且stringData
字段中的所有键值对都会在内部被合并到data
字段中。- 如果某个主键同时出现在
data
和stringData
字段中,stringData
所指定的键值具有高优先级。
secret大小限制
- 每个secret的大小最大为1MiB。
Secret的使用方式
secret有三种使用方式,分别是:
- 作为挂载到一个或多个容器上的卷 中的文件。
- 作为容器的环境变量。
- 由 kubelet 在为 Pod 拉取镜像时使用。
- Kubernetes 会检查 Secret 的卷数据源,确保所指定的对象引用确实指向类型为 Secret 的对象。因此,如果 Pod 依赖于某 Secret,该 Secret 必须先于 Pod 被创建。
- 如果 Secret 内容无法取回(可能因为 Secret 尚不存在或者临时性地出现 API 服务器网络连接问题),kubelet 会周期性地重试 Pod 运行操作。kubelet 也会为该 Pod 报告 Event 事件,给出读取 Secret 时遇到的问题细节。
- 如果 Pod 引用了 Secret 中的特定主键,而虽然 Secret 本身存在,对应的主键不存在, Pod 启动也会失败。
- 无法在静态pod中使用ConfigMap或者Secret。
方式1: 以文件的形式挂载到pod中
- 当卷中包含来自 Secret 的数据,而对应的 Secret 被更新,Kubernetes 会跟踪到这一操作并更新卷中的数据。更新的方式是保证最终一致性。
- 对于以 subPath 形式挂载 Secret 卷的容器而言, 它们无法收到自动的 Secret 更新。
将secret直接挂载进pod中
- 创建一个 Secret 或者使用已有的 Secret。多个 Pod 可以引用同一个 Secret。
- 更改 Pod 定义,在
.spec.volumes[]
下添加一个卷。根据需要为卷设置其名称, 并将.spec.volumes[].secret.secretName
字段设置为 Secret 对象的名称。 - 为每个需要该 Secret 的容器添加
.spec.containers[].volumeMounts[]
。 并将.spec.containers[].volumeMounts[].readOnly
设置为true
, 将.spec.containers[].volumeMounts[].mountPath
设置为希望 Secret 被放置的、目前尚未被使用的路径名。 - 更改你的镜像或命令行,以便程序读取所设置的目录下的文件。Secret 的
data
映射中的每个主键都成为mountPath
下面的文件名。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
optional: false # 默认设置,意味着 "mysecret" 必须已经存在
将secret的键投射到特定的目录中
mysecret
中的键 username
会出现在容器中的路径为 /etc/foo/my-group/my-username
, 而不是 /etc/foo/username
。Secret 对象的 password
键不会被投射。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
-
如果使用了
.spec.volumes[].secret.items
,则只有items
中指定了的主键会被投射。 如果要使用 Secret 中的所有主键,则需要将它们全部枚举到items
字段中。 -
如果你显式地列举了主键,则所列举的主键都必须在对应的 Secret 中存在。 否则所在的卷不会被创建。
方式2: 以环境变量的方式使用Secret
- 创建 Secret(或者使用现有 Secret)。多个 Pod 可以引用同一个 Secret。
- 更改 Pod 定义,在要使用 Secret 键值的每个容器中添加与所使用的主键对应的环境变量。 读取 Secret 主键的环境变量应该在
env[].valueFrom.secretKeyRef
中填写 Secret 的名称和主键名称。 - 更改你的镜像或命令行,以便程序读取环境变量中保存的值。
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
optional: false # 此值为默认值;意味着 "mysecret"
# 必须存在且包含名为 "username" 的主键
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
optional: false # 此值为默认值;意味着 "mysecret"
# 必须存在且包含名为 "password" 的主键
restartPolicy: Never
- 对于通过
envFrom
字段来填充环境变量的 Secret 而言, 如果其中包含的主键不能被当做合法的环境变量名,这些主键会被忽略掉。 Pod 仍然可以启动。 - 如果容器已经在通过环境变量来使用 Secret,Secret 更新在容器内是看不到的, 除非容器被重启。
容器镜像拉取Secret
imagePullSecrets
字段是一个列表,包含对同一名字空间中 Secret 的引用。 你可以使用 imagePullSecrets
将包含 Docker(或其他)镜像仓库密码的 Secret 传递给 kubelet。kubelet 使用此信息来替 Pod 拉取私有镜像。
Secret的类型
secret的类型主要有以下这些:
内置类型 | 用法 |
---|---|
Opaque | 用户定义的任意数据 |
kubernetes.io/service-account-token | 服务账号令牌 |
kubernetes.io/dockercfg | ~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson | ~/.docker/config.json 文件的序列化形式 |
kubernetes.io/basic-auth | 用于基本身份认证的凭据 |
kubernetes.io/ssh-auth | 用于 SSH 身份认证的凭据 |
kubernetes.io/tls | 用于 TLS 客户端或者服务器端的数据 |
bootstrap.kubernetes.io/token | 启动引导令牌数据 |
通过为 Secret 对象的 type
字段设置一个非空的字符串值,你也可以定义并使用自己 Secret 类型(如果 type
值为空字符串,则被视为 Opaque
类型)。
Docker配置Secret
apiVersion: v1
kind: Secret
metadata:
name: secret-dockercfg
type: kubernetes.io/dockercfg
data:
.dockercfg: |
"<base64 encoded ~/.dockercfg file>"
basic-auth认证secret
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # kubernetes.io/basic-auth 类型的必需字段
password: t0p-Secret # kubernetes.io/basic-auth 类型的必需字段
ssh身份认证secret
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# 此例中的实际数据被截断
ssh-privatekey: |
MIIEpQIBAAKCAQEAulqb/Y ...
tls证书密钥secret
apiVersion: v1
kind: Secret
metadata:
name: secret-tls
type: kubernetes.io/tls
data:
# 此例中的数据被截断
tls.crt: |
MIIC2DCCAcCgAwIBAgIBATANBgkqh ...
tls.key: |
MIIEpgIBAAKCAQEA7yn3bRHQ5FHMQ ...