ConfigMap和Secret都是k8s中为Pod存放配置的资源,CongiMap与Secrets类似,但通常 ConfifgMap用来存放不敏感的字符串。
ConfigMap机制就相当于一个配置中心,一个ConfigMap资源可以关联给多个Pod。
Pod中关联ConfigMap的方式主要有两种:引入环境变量和挂载存储卷。
注意:
示例
1 | apiVersion: v1 |
ConfigMap具有多种创建方式,yaml文件的方式不再赘述,命令行的创建方式主要有三种,即ConfigMap中键值对的来源有三种:
指定变量创建
1 | # 通过在命令行中指定具体的变量名和变量值,在ConfigMap中创建键值对 |
指定文件创建
1 | # 通过一个具体的文件名来创建ConfigMap,创建后的ConfigMap中key值是文件名,value值是文件中的内容 |
指定目录创建
1 | # 通过一个目录来创建ConfigMap,创建后的ConfigMap中包含多个键值对,key值分别是文件名,value值是各自文件中的内容 |
|
|
用于放在ConfigMap中的key值之后,用于定义含有多行字符串的value值,可以根据需求保留或者除去多行文本后的换行符\n
|
保留换行,行首的缩进和空白会被保留,行尾的会被去掉
|+
表示保留文字块末尾的换行
|-
表示删除文字块末尾的换行
>
表示折叠换行,内容最末尾的换行会保留,但文中部分只有空白行才会被识别为换行,原来的换行符都会被转换成空格。
综合示例
1 | apiVersion: v1 |
apply之后查看
1 | { |
Secret对象的数据存储和打印格式为Base64编码的字符串,因此用户在创建Secret对象时,也需要提供该类型的编码格式的数据。在容器中以环境变量或存储卷的方式访问时,会自动解码为明文格式。
Pod中关联Secret和ConfigMap的方式基本相同,都是环境变量或者挂载存储卷的方式。
Secret有多种类型:Opaque,kubernetes.io/tls,kubernetes.io/dockerconfigjson
Opaque ,读音[əʊˈpeɪk]
,是默认是secret类型,也是最常用的secret类型。
Opaque支持两种数据类型来定义secret中的键值对:data
和 stringData
data
字段的数据必须是经过base64编码的
1 | apiVersion: v1 |
stringData
某些场景下想将非base64编码的字符串放入Secret中,就需要用到stringData字段,字段的数据使用未编码的字符串。
1 | apiVersion: v1 |
创建完成后,config.yaml整体会被base64编码,使用 base64 -d
反解可以查看明文。
dockerconfigjson类型可以用来存储docker registy的认证信息,如果我们在下载镜像时需要登录账号密码,则需要设置它,这时候这个Secret称为 imagePullSecret
,需要在yaml文件中指定 Pod.spec.imagePullSecrets
,然后可以拉取私有仓库的镜像。和普通的secret不同,它不是给Pod用的,不能挂载到Pod内,而是给kubelet拉取镜像使用的。
创建docker仓库的 imagePullSecret
1 | kubectl create secret docker-registry secret名称 --docker-server=仓库域名 --docker-username=用户名 --docker |
扩展:
1 | kubectl create secret generic secret名称 --from-file=.dockerconfigjson=/path/to/config.json --type=kubernetes.io/dockerconfigjson |
上面的/path/to/config.json
是已经存在的docker镜像仓库的认证信息,比如在宿主机上通过docker login
或者nerdctl login
方式登陆了镜像仓库,宿主机上会生成一个docker镜像仓库的dockerconfigjson文件,基于这个文件可以直接生成imagePullSecret。
除了设置 Pod.spec.imagePullSecrets
这种方式来获取私有镜像之外,我们还可以通过在 ServiceAccount 中设置 imagePullSecrets 信息,这样无需额外在yaml文件中指定,可以直接拉取私有镜像
1 | apiVersion: v1 |
这种类型是用于存放证书文件的,专门用于secret通信,一般的场景是在ingress中使用
创建tls类型的secret
1 | kubectl create secret tls secret名称 --key=./nginx.key --cert=./nginx.crt |
在ingress中使用
1 | apiVersion: extensions/v1beta1 |
在 Kubernetes 中,如果 ConfigMap以存储卷的方式挂载到 Pod 内,此时对ConfigMap进行更新或删除重建,那么这些更新是可以被反映到 Pod 内的文件内容中,这也就是我们所说的”热更新”,但这只是ConfigMap的热更新。
此时虽然Pod中的文件内容已经发生了变化,但是运行在Pod中的应用并不一定能感知到配置文件的变化,事实上,很多应用只会在启动时加载一次配置文件,运行后不会再对配置文件做任何检查和重载,所以Pod内的应用并没有实现热更新。
要想实现Pod内应用的热更新,有两种方式,一种方式是在应用容器内添加自定义的脚本,检测配置文件的变更,然后重载对应的服务。另一种方式是 Kubernetes 提供的功能,使用注解搭配sidecar的方式,实现检测ConfigMap更新,重建Pod。
1 | # 下载reloader资源yaml文件,可以把里面的镜像换成自己的,然后部署即可 |
同一命名空间下的资源需要加上一个注解,然后可以实现应用的热更新。
1 | reloader.stakater.com/auto: "true" |
注意:
Pod与Apiserver通讯的时候会用到一种访问凭证,包含了认证相关的密钥和证书等信息,这种访问凭证是绑定在Service Account中的。
在Kubernetes v1.24.0版本之前,每创建一个sa,k8s都会自动为其创建对应的凭据,凭据默认会被创建成secret,而且是固定死的secrets,这种方式存在一些不便之处和安全隐患:
存在泄露风险
传统方式下每个 ServiceAccount 的 Secret 会以文件形式存储在对应的应用节点上,而集群的系统组件在运行过程中也会使用到一些权限很高的 ServiceAccount,其增大了集群管控平面的攻击面,攻击者可以通过获取这些管控组件使用的 ServiceAccount 非法提权。
扩容问题
每个 ServiceAccount 都创建一个 Secret ,在大规模的应用部署下存在弹性和容量风险。
伪装攻击风险
ServiceAccount 中的 JSON Web Token (JWT) 没有绑定 audience 身份,因此所有 ServiceAccount 的使用者都可以彼此扮演,存在伪装攻击的可能。并且 ServiceAccount 中的 JWT 没有设置过期时间,当上述 ServiceAccount 泄露情况发生时,只能通过轮转 ServiceAccount 的签发私钥来进行防范
为了解决上述问题,k8s专门为 ServiceAccount 这种账户提供了 ServiceAccount Token 投影机制即令牌卷投影机制,用于增强 ServiceAccount 的灵活性与安全性,具体做法如下:
1 | 在Kubernetes v1.24.0及更高版本中,创建为 ServiceAccount 后,不再为其创建secret凭证,如果某个pod中引用了该ServiceAccount,k8s 都会自动为该 ServiceAccount 创建一个token然后挂载到 Pod 的`/var/run/secrets/kubernetes.io/serviceaccount` 目录中,该目录下存放有如下文件 |