7.配置管理ConfigMap
1.什么是ConfigMap 很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候, 存在要调整配置参数所设置的数值的需求。 ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移
1.什么是ConfigMap 很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候, 存在要调整配置参数所设置的数值的需求。 ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移
很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候, 存在要调整配置参数所设置的数值的需求。 ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性。
我们在部署服务的时候,每个服务都有自己的配置文件
1.如果一台服务器上部署多个服务:nginx、tomcat、apache等,那么这些配置都存在这个节点上。
2.假如一台服务器不能满足线上高并发的要求,需要对服务器扩容,扩容之后的服务器还是需要部署多个服务:nginx、tomcat、apache,新增加的服务器上还是要管理这些服务的配置。
3.如果有一个服务出现问题,需要修改配置文件,每台物理节点上的配置都需要修改,这种方式肯定满足不了线上大批量的配置变更要求。
4.所以,k8s 中引入了 Configmap资源对象,可以当成 volume 挂载到 pod 中,实现统一的配置管理。
5.传统的方式下,当我们需要传一些配置给我们的应用,比如Oracle的IP地址,端口号,用户名密码等配置时,最容易想到的办法就是直接在打包镜像的时候写在应用配置文件里面,但是这种方式的坏处显而易见而且非常明显;我们也可以通过在定义pod模板时,使用env字段定义配置参数,然后容器里面的应用程序就能通过环境变量来读取配置参数,但是这样的话,当配置参数发现变化,就必须修改修改yaml文件的pod模板的env字段的参数,而且还需要重启所有的pod,让容器重新加载新参数才行。
为了解决配置参数存储的问题,也为了解耦应用程序与配置参数,k8s提供了两种资源的对象来专门存储配置参数,即ConfigMap和Secret,前者ConfigMap主要存储不敏感配置信息,后者Secret存储加密的敏感配置信息。


1.Configmap 是 k8s 中的资源, 相当于配置文件,可以有一个或者多个 Configmap; 2.Configmap 可以做成 Volume,k8s pod 启动之后,通过 volume 形式映射到容器内部指定目录上; 3.容器中应用程序按照原有方式读取容器特定目录上的配置文件 4.在容器看来,配置文件就像是打包在容器内部特定目录,整个过程对应用没有任何侵入。
我们首先来看下pod是如何通过env字段传递配置参数,k8s允许pod为每一个容器自定义环境变量集合
环境变量的缺点 如果多个应用使用到的相同的配置,那么就需要在每一个deployment的pod模板中以环境变量的形式定义配置,如果修改某个配置,如Oracle的ip地址,显然就需要修改每一个pod定义,这种做法简直就是灾难,这样也违背了k8s最基本的原则,所以,为了能在多个环境下复用配置,急需将配置从pod定义中解耦出来,k8s提供了ConfigMap资源来完成解耦。
使用 kubectl create configmap 命令基于目录、 文件或者字面值来创建 ConfigMap
$ kubectl create configmap <映射名称> <数据源><映射名称> 是为 ConfigMap 指定的名称,<数据源> 是要从中提取数据的目录、 文件或者字面值。ConfigMap 对象的名称必须是合法的 DNS 子域名.
在基于文件来创建 ConfigMap 时,<数据源> 中的键名默认取自文件的基本名, 而对应的值则默认为文件的内容。
也可以使用kubectl describe 或者 kubectl get 获取有关 ConfigMap 的信息。 创建一个包含简单字面量的ConfigMap,名为my-config1
使用 kubectl create configmap 基于同一目录中的多个文件创建 ConfigMap。 基于目录来创建 ConfigMap 时,kubectl 识别目录下基本名可以作为合法键名的文件, 并将这些文件打包到新的 ConfigMap 中。普通文件之外的所有目录项都会被忽略 (例如:子目录、符号链接、设备、管道等等)。
1.创建本地目录
mkdir -p /root/configure-pod-container/configmap2.将示例文件下载到 configure-pod-container/configmap/ 目录
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties3.创建 configmap
kubectl create configmap game-config --from-file=configure-pod-container/configmap/以上命令将 configure-pod-container/configmap 目录下的所有文件,也就是 game.properties 和 ui.properties 打包到 game-config ConfigMap 中
4.验证
6.导出game-config的yaml文件
使用 kubectl create configmap 基于单个文件或多个文件创建 ConfigMap
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties查看
也可以多次使用 --from-file 参数,从多个数据源创建 ConfigMap
# kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure- \ pod-container/configmap/ui.properties将示例文件下载到 configure-pod-container/configmap/ 目录
# wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties
# wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties查看
创建
从 Kubernetes 1.23 版本开始,kubectl 支持多次指定 --from-env-file 参数来从多个数据源创建 ConfigMap
# kubectl create configmap config-multi-env-files \
–from-env-file=configure-pod-container/configmap/game-env-file.properties \
–from-env-file=configure-pod-container/configmap/ui-env-file.properties 在使用 --from-file 参数时,你可以定义在 ConfigMap 的 data 部分出现键名, 而不是按默认行为使用文件名
# kubectl create configmap game-config-3 --from-file=<我的键名>=<文件路径><我的键名> 是你要在 ConfigMap 中使用的键名,<文件路径> 是你想要键所表示的数据源文件的位置
# kubectl create configmap game-config-3 --from-file=game-special-key=configure-pod-container/configmap/game.properties获得当前ConfigMap 的详情
可以将 kubectl create configmap 与 --from-literal 参数一起使用, 通过命令行定义文字值
# kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm可以传入多个键值对。命令行中提供的每对键值在 ConfigMap 的 data 部分中均表示为单独的条目
自 1.14 开始,kubectl 开始支持 kustomization.yaml。 你还可以基于生成器(Generators)创建 ConfigMap,然后将其应用于 API 服务器上创建对象。 生成器应在目录内的 kustomization.yaml 中指定.
创建包含 ConfigMapGenerator 的 kustomization.yaml 文件
应用(Apply)kustomization 目录创建 ConfigMap 对象
root@k8s-master01:~# kubectl apply -k .
configmap/game-config-4-tbg7c4gc77 created检查 ConfigMap 被创建命令
生成的 ConfigMap 名称具有通过对内容进行散列而附加的后缀, 这样可以确保每次修改内容时都会生成新的 ConfigMap。
在 ConfigMap 生成器中,你可以定义一个非文件名的键名。 例如,从 configure-pod-container/configmap/game.properties 文件生成 ConfigMap, 但使用 game-special-key 作为键名
root@k8s-master01:~# kubectl apply -k .
configmap/game-config-5-tfhf8f4fkf created检查 ConfigMap 被创建命令
要基于字符串 special.type=charm 和 special.how=very 生成 ConfigMap, 可以在 kustomization.yaml 中配置 ConfigMap 生成器
应用(Apply)kustomization 目录创建 ConfigMap 对象
root@k8s-master01:~# kubectl apply -k .
configmap/special-config-2-2b86tk8fhm created检查 ConfigMap 被创建命令
官方文档:https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/
secret是用来存储少量敏感数据的重要资源对象。
一共有三种类型:docker-registry,generic和tls,分别用于存储镜像仓库认证信息,一般信息和证书信息。其中generic类型的最常用,比较典型的就是用来存放数据库的认证信息。
这样的信息可能会被放在 Pod规约中或者镜像中。 使用 Secret就不需要在应用程序代码中包含机密数据,减少暴露风险。 注意
大小限制
每个 Secret 的尺寸最多为 1MiB。
施加这一限制是为了避免用户创建非常大的 Secret, 进而导致 API 服务器和 kubelet 内存耗尽。
不过创建很多小的 Secret 也可能耗尽内存。 你可以使用资源配额来约束每个名字空间中 Secret(或其他资源)的个数。创建 Secret
Secret 对象用来存储敏感数据,如 Pod 用于访问服务的凭据。例如,为访问数据库,你可能需要一个 Secret 来存储所需的用户名及密码。
你可以通过在命令中传递原始数据,或将凭据存储文件中,然后再在命令行中创建 Secret。以下命令 将创建一个存储用户名 admin 和密码 S!B\*d$zDsb= 的 Secret
使用原始数据基于键值对创建
或者基于指定文件创建
或者基于指定目录创建
或者基于环境变量键值对文件
可以将多个环境变量文件写入文件中,直接创建一个ENV的secret
使用 --from-env-file 参数引用
cat env-mysql.txt
---
MYSQL_DATABASE=testdb
MYSQL_ROOT_PASSWORD=123123
解码 Secret
查看你所创建的 Secret 内容
解码 password 数据
root@k8s-master01:~# echo 'UyFCXCpkJHpEc2I9' | base64 --decode
S!B\*d$zDsb=注意:
这是一个出于文档编制目的的示例。实际上,该方法可能会导致包含编码数据的命令存储在 Shell 的历史记录中。任何可以访问你的计算机的人都可以找到该命令并对 Secret 进行解码。 更好的办法是将查看和解码命令一同使用。
编辑 Secret
你可以编辑一个现存的 Secret 对象,除非它是不可改变的。 要想编辑一个 Secret,请执行以下命令:
清理
要想删除一个 Secret,请执行以下命令:
kubectl delete secret db-user-pass用 JSON 或 YAML 格式在一个清单文件中定义 Secret 对象,然后创建该对象。 Secret 资源包含 2 个键值对:data 和 stringData。 data 字段用来存储 base64 编码的任意数据。 提供 stringData 字段是为了方便,它允许 Secret 使用未编码的字符串。 和 的键必须由字母、数字、、 或 组成。
以下示例使用 data 字段在 Secret 中存储两个字符串
将这些字符串转换为 base64
创建清单
创建 Secret 时提供未编码的数据
对于某些场景,你可能希望使用 stringData 字段。 这个字段可以将一个非 base64 编码的字符串直接放入 Secret 中, 当创建或更新该 Secret 时,此字段将被编码。
上述用例的实际场景可能是这样:当你部署应用时,使用 Secret 存储配置文件, 你希望在部署过程中,填入部分内容到该配置文件。
例如,如果你的应用程序使用以下配置文件:
apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"你可以使用以下定义将其存储在 Secret 中
当你检索 Secret 数据时,此命令将返回编码的值,并不是你在 stringData 中提供的纯文本值。
例如,如果你运行以下命令:
如果你在 data 和 stringData 中设置了同一个字段,则使用来自 stringData 中的值。
例如,如果你定义以下 Secret:
所创建的 Secret 对象如下
编辑 Secret
要编辑使用清单创建的 Secret 中的数据,请修改清单中的 data 或 stringData 字段并将此清单文件应用到集群。 你可以编辑现有的 Secret 对象,除非它是不可变的。
例如,如果你想将上一个示例中的密码更改为 birdsarentreal,请执行以下操作:
编码新密码字符串
echo -n 'birdsarentreal' | base64
YmlyZHNhcmVudHJlYWw=使用你的新密码字符串更新 data 字段
将清单应用到你的集群
kubectl apply -f ./secret.yamlKubernetes 更新现有的 Secret 对象。具体而言,kubectl 工具发现存在一个同名的现有 Secret 对象。 kubectl 获取现有对象,计划对其进行更改,并将更改后的 Secret 对象提交到你的集群控制平面。
如果你指定了 kubectl apply --server-side,则 kubectl 使用服务器端应用(Server-Side Apply)
创建 Secret
你可以在 kustomization.yaml 文件中定义 secreteGenerator 字段, 并在定义中引用其它本地文件、.env 文件或文字值生成 Secret。 例如:下面的指令为用户名 admin 和密码 1f2d1e2e67df 创建 Kustomization 文件
在所有情况下,你都不需要对取值作 base64 编码。 YAML 文件的名称必须是 kustomization.yaml 或 kustomization.yml
编辑 Secret
kustomization.yaml 文件中,修改诸如 password 等数据。kubectl apply -k <目录路径>目录:/run/secrets/kubernetes.io/serviceaccount
Opaque类型的数据是一个map类型,要求value是base64编码格式。
创建secret
将secret挂载到volume中
将secret挂载到环境变量中
Secre存储私有docker registry的认证
用来存储私有docker registry的认证信息
另外一种Secret类型就是kubernetes.io/service-account-token,用于被serviceaccount引用。serviceaccout创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了serviceaccount,对应的secret会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中
这里我们使用一个nginx镜像来验证一下,大家想一想为什么不是呀busybox镜像来验证?当然也是可以的,但是我们就不能在command里面来验证了,因为token是需要Pod运行起来过后才会被挂载上去的,直接在command命令中去查看肯定是还没有 token 文件的
生成证书
使用证书
我们一般挂载redis.cfg希望是挂载在/etc下面,但是如果直接挂载的话,会报错,因为k8s会覆盖etc下面的所有文件,而etc下面的文件是属于只读层,所以会报错。
解决方法:使用subpath
最后我们来对比下Secret和ConfigMap这两种资源对象的异同点:
相同点:
key/value的形式
属于某个特定的namespace
可以导出到环境变量
可以通过目录/文件形式挂载
通过 volume 挂载的配置信息均可热更新
不同点:
Secret 可以被 ServerAccount 关联
Secret 可以存储 docker register 的鉴权信息,用在 ImagePullSecret 参数中,用于拉取私有仓库的镜像
Secret 支持 Base64 加密
Secret 分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque 三种类型,而 Configmap 不区分类型
通过文件热更新
kubectl create cm nginx-conf --from-``file``=nginx.conf --dry-run=client -oyaml | kubectl replace -f -通过replace更新
直接更新yaml文件后,执行
kubect replace -f a.yamlimmutable设置成true后,则configmap的数据不可更改。
[root@master configmap]# cat deployment_nginx_env.yaml #创建一个deploy,pod模板中使用环境变量的方式传递数据库配置参数
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx-env
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-env
template:
metadata:
labels:
app: nginx-env
spec:
containers:
- image: nginx:1.7.9
name: nginx-container
env: #定会环境变量
- name: dbtype #定义一个环境变量dbtype
value: "Oracle" #环境变量dbtype的值是Oracle
- name: ip #定义一个环境变量ip
value: "192.168.44.145" #环境变量ip的值是192.168.44.145
- name: port #定义一个环境变量port
value: "1521" #环境变量port的值1521
- name: dbtype_1
value: $(dbtype) #可以通过引用的方式引用前一个环境变量的值,前提是引用的环境变量必须先存在
- name: dbtype_2
value: "$(dbtype)_2" #可以通过引用的方式引用前一个环境变量的值,前提是引用的环境变量必须先存在
ports:
- name: http
containerPort: 80
[root@master configmap]#
[root@master configmap]# kubectl get pods -l app=nginx-env #查看pod,发现pod已经创建成功
NAME READY STATUS RESTARTS AGE
deployment-nginx-env-bdc55ff9b-jd88z 1/1 Running 0 2m21s
deployment-nginx-env-bdc55ff9b-k88hx 1/1 Running 0 2m21s
#查看一下pod
[root@master configmap]# kubectl describe pod deployment-nginx-env-759df5c755-g5ckm
.........
Environment:
dbtype: Oracle
ip: 192.168.44.145
port: 1521
dbtype_1: $(dbtype) #这里不要觉得奇怪,因为yaml文件本身就是这样定义的,等下进到容器里echo $dbtype_1就能看到其值
dbtype_2: $(dbtype)_2
................
#现在查看pod中容器的所有环境变量,直接传递env命令给容器,打印所有的环境变量
[root@master configmap]# kubectl exec -it deployment-nginx-env-759df5c755-g5ckm -c nginx-container -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
dbtype=Oracle
ip=192.168.44.145
port=1521
dbtype_1=Oracle
dbtype_2=Oracle_2
.......
#当然,也可以进入容器查看环境变量
[root@master configmap]# kubectl exec -it deployment-nginx-env-759df5c755-g5ckm -c nginx-container -- bash
root@deployment-nginx-env-5c987dcfb8-5qjrz:/# echo $dbtype; echo $dbtype_1; echo $dbtype_2;echo $ip; echo $port;
Oracle
Oracle
Oracle_2
192.168.44.145
1521
#以上,我们以环境变量的形式来传递配置参数给容器应用程序已经生效了,这样配置参数就能在容器中被应用程序使用环境变量的方式引用了
[root@master ~]# kubectl create configmap my-config1 --from-literal=dbtpye=Oracle --from-literal=ip=192.168.118.129 \
--from-literal=port=1521
configmap/my-config1 created
#以上创建了有3个条目的cm,key的名称和value的都能很清晰的看得出来
[root@master my-config]# kubectl get configmaps my-config1 -o yaml #以yaml格式查看我们创建的ConfigMap
apiVersion: v1
data: #下面这些就是该cm的条目
dbtpye: Oracle #第一个条目名为dbtype,其值为Oracle
ip: 192.168.118.129 #第二个条目名为ip,其值为192.168.118.129
port: "1521" #第三个条目名为port,其值为1521
kind: ConfigMap
metadata:
creationTimestamp: "2023-11-21T07:13:02Z"
name: my-config1
namespace: default
resourceVersion: "4529385"
uid: 917d765d-407f-4bed-8e7b-bf910c44129a# 查看game.properties ui.properties
root@k8s-master01:~/configure-pod-container/configmap# cat game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30root@k8s-master01:~/configure-pod-container/configmap# cat ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
root@k8s-master01:~# kubectl describe configmaps game-config
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
BinaryData
====
Events: <none>
# configure-pod-container/configmap/ 目录中的 game.properties 和 ui.properties 文件出现在 ConfigMap 的 data 部分root@k8s-master01:~# kubectl get configmaps game-config -o yaml
apiVersion: v1
data:
game.properties: |-
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kind: ConfigMap
metadata:
creationTimestamp: "2023-11-21T07:25:57Z"
name: game-config
namespace: default
resourceVersion: "4532563"
uid: e1dd3c81-c5de-4c65-a431-96594327c93aroot@k8s-master01:~# kubectl describe configmaps game-config-2
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none>当 kubectl 基于非 ASCII 或 UTF-8 的输入创建 ConfigMap 时, 该工具将这些输入放入 ConfigMap 的 binaryData 字段,而不是 data 中。 同一个 ConfigMap 中可同时包含文本数据和二进制数据源。 如果你想查看 ConfigMap 中的 binaryData 键(及其值), 可以运行命令 kubectl get configmap -o jsonpath='{.binaryData}' <name>。
使用 --from-env-file 选项从环境文件创建 ConfigMap
Env 文件包含环境变量列表。其中适用以下语法规则:
Env 文件中的每一行必须为 VAR=VAL 格式。
以#开头的行(即注释)将被忽略。
空行将被忽略。
引号不会被特殊处理(即它们将成为 ConfigMap 值的一部分root@k8s-master01:~# cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"
# This comment and the empty line above it are ignoredroot@k8s-master01:~# kubectl create configmap game-config-env-file \
> --from-env-file=configure-pod-container/configmap/game-env-file.properties
configmap/game-config-env-file created
root@k8s-master01:~# kubectl get configmap game-config-env-file -o yaml
apiVersion: v1
data:
allowed: '"true"'
enemies: aliens
lives: "3"
kind: ConfigMap
metadata:
creationTimestamp: "2023-11-21T08:49:50Z"
name: game-config-env-file
namespace: default
resourceVersion: "4552880"
uid: 3bb65f0c-3d01-4f26-ab0c-e4bdf529b3a2root@k8s-master01:~# kubectl get configmaps game-config-3 -o yaml
apiVersion: v1
data:
game-special-key: |-
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
kind: ConfigMap
metadata:
creationTimestamp: "2023-11-21T08:56:39Z"
name: game-config-3
namespace: default
resourceVersion: "4554557"
uid: 72461582-3324-40f2-bfa8-881673879cf8root@k8s-master01:~# kubectl get configmaps special-config -o yaml
apiVersion: v1
data:
special.how: very
special.type: charm
kind: ConfigMap
metadata:
creationTimestamp: "2023-11-21T08:58:42Z"
name: special-config
namespace: default
resourceVersion: "4555037"
uid: 43eeb29c-9fb5-4435-9d63-a4d8be2c4865cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
files:
- configure-pod-container/configmap/game.properties
EOFroot@k8s-master01:~# kubectl describe configmaps game-config-4-tbg7c4gc77
Name: game-config-4-tbg7c4gc77
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none># 创建包含 ConfigMapGenerator 的 kustomization.yaml 文件
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
files:
- game-special-key=configure-pod-container/configmap/game.properties
EOFroot@k8s-master01:~# kubectl describe configmaps game-config-5-tfhf8f4fkf
Name: game-config-5-tfhf8f4fkf
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game-special-key:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none># 创建带有 ConfigMapGenerator 的 kustomization.yaml 文件
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: special-config-2
literals:
- special.how=very
- special.type=charm
EOFroot@k8s-master01:~# kubectl describe configmaps special-config-2-2b86tk8fhm
Name: special-config-2-2b86tk8fhm
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
special.how:
----
very
special.type:
----
charm
BinaryData
====
Events: <none>默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。
任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。 此外,任何有权限在命名空间中创建 Pod 的人都可以使用该访问权限读取该命名空间中的任何 Secret; 这包括间接访问,例如创建 Deployment 的能力。
为了安全地使用 Secret,请至少执行以下步骤:
为 Secret 启用静态加密;
启用或配置 RBAC 规则来限制读取和写入 Secret 的数据(包括通过间接方式)。需要注意的是,被准许创建 Pod 的人也隐式地被授权获取 Secret 内容。
在适当的情况下,还可以使用 RBAC 等机制来限制允许哪些主体创建新 Secret 或替换现有 Secret。
参见 Secret 的信息安全了解详情◆ Opaque:通用型Secret,默认类型;
◆ kubernetes.io/service-account-token:作用于ServiceAccount,包含一个令牌,用于标识API服务账户;
◆ kubernetes.io/dockerconfigjson:下载私有仓库镜像使用的Secret, 和宿主机的/root/.docker/config.json一致,宿主机登录后即可产生该文件;
◆ kubernetes.io/basic-auth:用于使用基本认证(账号密码)的Secret,可以使用Opaque取代;
◆ kubernetes.io/ssh-auth:用于存储ssh密钥的Secret;
◆ kubernetes.io/tls:用于存储HTTPS域名证书文件的Secret,可以被Ingress使用;
◆ bootstrap.kubernetes.io/token:一种简单的 bearer token, 用于创建新集群或将新节点添加到现有集群,在集群安装时可用于自动颁发集群的证书。kubectl create secret generic db-user-pass \
--from-literal=username=admin \
--from-literal=password='S!B\*d$zDsb='
必须使用单引号 '' 转义字符串中的特殊字符,如 $、\、*、=和! 。否则,你的 shell 将会解析这些字符
root@k8s-master01:~# kubectl create secret generic db-user-pass \
> --from-literal=username=admin \
> --from-literal=password='S!B\*d$zDsb='
secret/db-user-pass created
root@k8s-master01:~# kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 29s
查看 Secret 的细节
root@k8s-master01:~# kubectl describe secret db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
username: 5 bytes
password: 12 bytes
kubectl get 和 kubectl describe 命令默认不显示 Secret 的内容。 这是为了防止 Secret 被意外暴露或存储在终端日志中。
1.将凭据保存到文件
echo -n 'admin' > ./username.txt
echo -n 'S!B\*d$zDsb=' > ./password.txt
-n 标志用来确保生成文件的文末没有多余的换行符。这很重要,因为当 kubectl 读取文件并将内容编码为 base64 字符串时,额外的换行符也会被编码。 你不需要对文件中包含的字符串中的特殊字符进行转义
2.在 kubectl 命令中传递文件路径
kubectl create secret generic db-user-pass \
--from-file=./username.txt \
--from-file=./password.txt
默认键名为文件名。你也可以通过 --from-file=[key=]source 设置键名,例如
kubectl create secret generic db-user-pass \
--from-file=username=./username.txt \
--from-file=password=./password.txtroot@k8s-master01:/opt/secret# ls
password.txt username.txt
root@k8s-master01:/opt/secret# kubectl create secret generic secret-dir --from-file=/opt/secret/
root@k8s-master01:/opt/secret# kubectl describe secrets secret-dir
Name: secret-dir
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
root@k8s-master01:/opt/secret# kubectl get secret secret-dir -o jsonpath='{.data}'
{"password.txt":"UyFCXCpkJHpEc2I9","username.txt":"YWRtaW4="}root@k8s-master01:~# kubectl get secret db-user-pass -o jsonpath='{.data}'
{"password":"UyFCXCpkJHpEc2I9","username":"YWRtaW4="}
root@k8s-master01:/opt/secret# kubectl create secret generic env-mysql --from-env-file=./env-mysql.txt
secret/env-mysql created
root@k8s-master01:/opt/secret# kubectl get secret/env-mysql -o yaml
apiVersion: v1
data:
'---': ""
MYSQL_DATABASE: dGVzdGRi
MYSQL_PASSWORD: MTIzNDU2
MYSQL_ROOT_PASSWORD: MTIzMTIz
MYSQL_USER: dGVzdA==
kind: Secret
metadata:
creationTimestamp: "2023-11-24T05:24:17Z"
name: env-mysql
namespace: default
resourceVersion: "5551941"
uid: e1b2420b-faeb-4614-9445-179a3b27294f
type: Opaque
root@k8s-master01:/opt/secret# kubectl describe secret/env-mysql
Name: env-mysql
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
MYSQL_USER: 4 bytes
---: 0 bytes
MYSQL_DATABASE: 6 bytes
MYSQL_PASSWORD: 6 bytes
MYSQL_ROOT_PASSWORD: 6 bytes
kubectl edit secrets <secret-name>
apiVersion: v1
data:
password: UyFCXCpkJHpEc2I9
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2023-11-24T02:05:21Z"
name: db-user-pass
namespace: default
resourceVersion: "5503582"
uid: f3b037b5-caac-49a5-a746-793f49fa1a48
type: Opaque datastringData-_.echo -n 'admin' | base64
echo -n '1f2d1e2e67df' | base64
root@k8s-master01:~# echo -n 'admin' | base64
YWRtaW4=
root@k8s-master01:~# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
Secret 数据的 JSON 和 YAML 序列化结果是以 base64 编码的。 换行符在这些字符串中无效,必须省略。 在 Darwin/macOS 上使用 base64 工具时,用户不应该使用 -b 选项分割长行。 相反地,Linux 用户应该在 base64 地命令中添加 -w 0 选项, 或者在 -w 选项不可用的情况下,输入 base64 | tr -d '\n'。apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
kubectl apply -f ./secret.yamlapiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |
apiUrl: "https://my.api.com/api/v1"
username: <user>
password: <password>
说明:
Secret 的 stringData 字段不能很好地与服务器端应用配合使用root@k8s-master01:~# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"password":"MWYyZDFlMmU2N2Rm","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"type":"Opaque"}
creationTimestamp: "2023-11-24T02:29:08Z"
name: mysecret
namespace: default
resourceVersion: "5509332"
uid: f7500e62-9fec-49f4-87a7-09cafd69794a
type: Opaque
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administratorapiVersion: v1
data:
username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
creationTimestamp: 2018-11-15T20:46:46Z
name: mysecret
namespace: default
resourceVersion: "7579"
uid: 91460ecb-e917-11e8-98f2-025000000001
type: Opaque
YWRtaW5pc3RyYXRvcg== 解码成 administratorapiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: YmlyZHNhcmVudHJlYWw=secretGenerator:
- name: database-creds
literals:
- username=admin
- password=1f2d1e2e67df
将凭据存储在文件中。文件名是 Secret 的 key 值
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
-n 标志确保文件结尾处没有换行符
创建 kustomization.yaml 文件
secretGenerator:
- name: database-creds
files:
- username.txt
- password.txt可以使用 .env 文件在 kustomization.yaml 中定义 secretGenerator。 例如下面的 kustomization.yaml 文件从 .env.secret 文件获取数据
secretGenerator:
- name: db-user-pass
envs:
- .env.secretkubectl apply -k <目录路径>
root@k8s-master01:~# kubectl apply -k .
secret/database-creds-bkbd782d2c created
生成 Secret 时,Secret 的名称最终是由 name 字段和数据的哈希值拼接而成。 这将保证每次修改数据时生成一个新的 Secret。
要验证 Secret 是否已创建并解码 Secret 数据
root@k8s-master01:~# kubectl get -k ./ -o jsonpath='{.data}'
{"password":"MWYyZDFlMmU2N2Rm","username":"YWRtaW4="}
root@k8s-master01:~# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df
root@k8s-master01:~# kubectl get pod -n kuboard
NAME READY STATUS RESTARTS AGE
kuboard-v3-5699db7ffb-r5w98 1/1 Running 0 15d
root@k8s-master01:~# kubectl exec -it -n kuboard kuboard-v3-5699db7ffb-r5w98 -- sh
# cd /run/secrets/kubernetes.io/serviceaccount
# ls
ca.crt namespace token
# cat ca.crt
-----BEGIN CERTIFICATE-----
MIIDmjCCAoKgAwIBAgIUZ10m0R7YrOc37j+UtmDlATGO0M0wDQYJKoZIhvcNAQEL
BQAwZDELMAkGA1UEBhMCQ04xETAPBgNVBAgTCEhhbmdaaG91MQswCQYDVQQHEwJY
UzEMMAoGA1UEChMDazhzMQ8wDQYDVQQLEwZTeXN0ZW0xFjAUBgNVBAMTDWt1YmVy
bmV0ZXMtY2EwIBcNMjMxMTA4MDExNDAwWhgPMjEyMzEwMTUwMTE0MDBaMGQxCzAJ
BgNVBAYTAkNOMREwDwYDVQQIEwhIYW5nWmhvdTELMAkGA1UEBxMCWFMxDDAKBgNV
BAoTA2s4czEPMA0GA1UECxMGU3lzdGVtMRYwFAYDVQQDEw1rdWJlcm5ldGVzLWNh
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvp/8/jSc0PwKPp0Fn0CV
59EmwiCEiFBgoIcPy4EeQHUpcJ25cqMTCVa9UQTiDUd/LMeW8GgeMsyHgTPi7T77
X1q+2G16ZPgC7A7xRlrUqH9KCJ+WqrhVRcCEPvb3xMC5k+GlVIvgwp+twIyxsxQU
hS3jViSYLCxH11GWkxgg3T02i1BtrO+LpqEu+gcK0+JRiApSFTGqKfUVAsHUTKNN
jO6pu3/Oo95U6qe3Vh1SFmystBf3gBmre8qwghKRuCRj7rW2cFFHBmLgDW6UKQ/i
0sj2gOZApEmvDrHgYdCf7OGjgrCkU661mvX6DjJ2ap5qm/DSKC96ZD2VX5UMsJ+E
8QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQUUvX3l1Qz2JSc8q2sgR8slnni3f4wDQYJKoZIhvcNAQELBQADggEBABXt
dbfN9Ks4JeJXq6bRHoCR68rdDAG4Enft3vI2a8vrguwmzTblr/df/yVv6udN0+C2
ooD7OoGe3dQ1WR5UsfV/ptQVrpEQ28reKYokRZdXtkS7tX07LoNc4VZj0CLzIRZv
rhw0veJp2fsAgO2P5hcYPGx6nMO7z8op8ZQykqg6UkxXKF8c9pkiJIbd1AByPOs0
6DdwToo6EsBWB4qr3/sPGcAWxDlq1bIlqCH9tObl0wAiRG9W411r2Cbqv83Pbnbz
NqgaGux5+xX/04w8IUUze4aVcJLEkRLnqhQrK2u6+w9HV9IM3QMO5WU0LGPANiiN
sfNr7QrWqR8cC96vYag=
-----END CERTIFICATE-----
# cat namespace
kuboard#
# cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImZtbC13NmNKZVdNOUZWNXhIM3luZmFIT3E2allkV1psb21aVnZWSndDS3MifQ.eyJhdWQiOlsiYXBpIiwiaXN0aW8tY2EiXSwiZXhwIjoxNzMyMzM4NzczLCJpYXQiOjE3MDA4MDI3NzMsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2YyIsImt1YmVybmV0ZXMuaW8iOnsibmFtZXNwYWNlIjoia3Vib2FyZCIsInBvZCI6eyJuYW1lIjoia3Vib2FyZC12My01Njk5ZGI3ZmZiLXI1dzk4IiwidWlkIjoiMGM1OWExOGItY2UyYy00ODM1LWFiMjQtY2RjMmU5MzI0OWU5In0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiMDQ4YjdlOTQtYzMwNi00NTQ5LWEyYzgtNGY0Y2FjYTExZDA4In0sIndhcm5hZnRlciI6MTcwMDgwNjM4MH0sIm5iZiI6MTcwMDgwMjc3Mywic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1Ym9hcmQ6ZGVmYXVsdCJ9.mVPUclBs4YEbQWjYC2mLD3F5e2vNjTeNe3unrsFRAgSYsQwINVtCH1NvLpPIkwE6gO7lMCVVdrHEhB5mHmh99zKkN6hkqacdyIU_wegFwr1mCNDVPsn1LO_zi6No6HIIizNXJS0GyhUrSzDqLbUFvWcV_PLtmKmKEPpRLMY6IYlp6EhXofXaL9Mz6vDT9m6XUJHyK1oQdZsDc_4quV6YdSA-0eUbvxLq6DF7ox0P2aUTBCdJ2QPQ0lhQ2wUn1s-b1vPrNJ4Qilz1ubjcUbqsl7wK9DUV8fhSzVtDCEO-T7HKpneDfd_UyAcmamDSTElWsR76vgFEG6wm8sZSr9m8uw#
# root@k8s-master01:/opt/secret# echo -n "admin" |base64
YWRtaW4=
root@k8s-master01:/opt/secret# echo -n "12345678" |base64
MTIzNDU2Nzg=
root@k8s-master01:/opt/secret# echo -n "MTIzNDU2Nzg=" |base64 -d
12345678root@k8s-master01:/opt/secret# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MTIzNDU2Nzg=
username: YWRtaW4=
root@k8s-master01:/opt/secret# kubectl create -f secret.yaml
root@k8s-master01:/opt/secret# kubectl get secrets
NAME TYPE DATA AGE
mysecret Opaque 2 24s
root@k8s-master01:/opt/secret# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MTIzNDU2Nzg=
username: YWRtaW4=
root@k8s-master01:/opt/secret# ls
secret-pod.yaml secret.yaml
root@k8s-master01:/opt/secret# cat secret-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-test
labels:
name: secret-test
spec:
volumes: #挂载卷
- name: secrets #挂在卷的名字
secret: #挂在卷的方式(secret)
secretName: mysecret #前文创建的secret的名字
containers:
- image: wangyanglinux/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/secrets"
readOnly: true
root@k8s-master01:/opt/secret#kubectl apply -f secret-pod.yaml
root@k8s-master01:/opt/secret# kubectl get pod
NAME READY STATUS RESTARTS AGE
secret-test 1/1 Running 0 3m27s
root@k8s-master01:/opt/secret# kubectl exec -it secret-test -- sh
/ # cd /etc/secrets/
/etc/secrets # ls
password username
/etc/secrets # cat password
12345678/etc/secrets #
/etc/secrets # cat username root@k8s-master01:/opt/secret# cat pod-delopment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-deployment
spec:
replicas: 2
selector:
matchLabels:
app: pod-deployment
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-deloy
image: wangyanglinux/myapp:v1
ports:
- containerPort: 80
env: #环境变量
- name: TEST_USER #环境变量的名字
valueFrom: # 值的来源
secretKeyRef: #secret的方式
name: mysecret #secret的名字
key: username # secret的键名
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
root@k8s-master01:/opt/secret# kubectl create -f pod-delopment.yaml
deployment.apps/pod-deployment created
root@k8s-master01:/opt/secret# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-deployment-75bdf696cf-fzxtz 1/1 Running 0 21s
pod-deployment-75bdf696cf-mdrf2 1/1 Running 0 21s
secret-test 1/1 Running 0 7m17s
root@k8s-master01:/opt/secret# kubectl exec -it pod
pod-deployment-75bdf696cf-fzxtz pod-deployment-75bdf696cf-mdrf2 pods/
root@k8s-master01:/opt/secret# kubectl exec -it pod-deployment-75bdf696cf-fzxtz -- sh
/ # echo $TEST_USER
admin
/ # echo $TEST_PASSWORD
12345678
创建认证
kubectl create secret docker-registry harbor \
--docker-server=harbor.nbbnai.com \
--docker-username=admin \
--docker-password=Harbor12345
root@k8s-master01:/opt/secret# kubectl get secrets
NAME TYPE DATA AGE
harbor kubernetes.io/dockerconfigjson 1 13m
mysecret Opaque 2 33m
root@k8s-master01:/opt/secret# cat harbor.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: test-docker-registry
spec:
selector:
matchLabels:
app: test-docker-registry
template:
metadata:
labels:
app: test-docker-registry
spec:
imagePullSecrets: # 加上这个就是直接登录到阿里云,下载镜像的认证
- name: harbor # 直接登录到阿里云,与上文创建secret对应
containers:
- name: nginx
imagePullPolicy: Always
image: harbor.nbbnai.com/images/nginx@sha256:d2e65182b5fd330470eca9b8e23e8a1a0d87cc9b820eb1fb3f034bf8248d37ee
root@k8s-master01:/opt/secret# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-deployment-75bdf696cf-fzxtz 1/1 Running 0 21m
pod-deployment-75bdf696cf-mdrf2 1/1 Running 0 21m
secret-test 1/1 Running 0 28m
test-docker-registry-5f5955f679-bwjzj 1/1 Running 0 4sroot@k8s-master01:~# kubectl run secret-pod3 --image nginx:1.7.9
pod/secret-pod3 created
root@k8s-master01:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-deployment-75bdf696cf-fzxtz 1/1 Running 0 18h
pod-deployment-75bdf696cf-mdrf2 1/1 Running 0 18h
secret-pod3 1/1 Running 0 55s
secret-test 1/1 Running 0 18h
test-docker-registry-5f5955f679-bwjzj 1/1 Running 0 18h
root@k8s-master01:~# kubectl exec secret-pod3 ls /run/secrets/kubernetes.io/serviceaccount
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
ca.crt
namespace
token
root@k8s-master01:~# kubectl exec secret-pod3 cat /run/secrets/kubernetes.io/serviceaccount/token
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
eyJhbGciOiJSUzI1NiIsImtpZCI6ImZtbC13NmNKZVdNOUZWNXhIM3luZmFIT3E2allkV1psb21aVnZWSndDS3MifQ.eyJhdWQiOlsiYXBpIiwiaXN0aW8tY2EiXSwiZXhwIjoxNzMyNDE1MzI5LCJpYXQiOjE3MDA4NzkzMjksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2YyIsImt1YmVybmV0ZXMuaW8iOnsibmFtZXNwYWNlIjoiZGVmYXVsdCIsInBvZCI6eyJuYW1lIjoic2VjcmV0LXBvZDMiLCJ1aWQiOiI2NjVhMDQ3Ny1lZDdkLTQ4ZjYtYTdlYS01NmIzMjQ0ODFlOGMifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI5ZGEwYmIyOC02NTZmLTQ2NTgtOGZjYy00ZjZlNGJiNmQ1YTYifSwid2FybmFmdGVyIjoxNzAwODgyOTM2fSwibmJmIjoxNzAwODc5MzI5LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.BdRxCJDUcHXuj1izI8sQaYeIx1lTceOT_XID9wVQgbh0l6MkNOP74_g-blx992RKWV_xISHz29tr5mOaw6uxqb8YSJQJA_KEJNAUoTihkJBVHSTAo3evUH6p5Q7G8tbutsZh4SJBccGR2gSDPN9wT3xYQpRVDQNUIUoZZdQ_Xfja80u_FPLhoC8ydE-rh9ruQFqd7hFlTK-Rnu2n-hgqK7s-2b4HYsq8p6E5p7AOGCs-lKx88lTgCL8iYjef6iM5WQVxPTTrbFXkAHiKt3qbkutUi5gWiLhSDXNBsIwUcRA1FD8e20jbq_wueP6OqNcy0dSmTjvFbvDffttNdzL3zQ#自己生成key和crt文件,一般情况是申请的第三方的
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=test.com"
#生成证书
kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crtapiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-https-test
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: https-test.com
http:
paths:
- backend:
serviceName: nginx-svc
servicePort: 80
tls:
- secretName: nginx-test-tls[root@k8s-master01 ~/k8s/configmap]# cat dp-cm-file.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: dp-cm-file
name: dp-cm-files
spec:
replicas: 1
selector:
matchLabels:
app: pod-cm-file
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: pod-cm-file
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: config
mountPath: /etc/redis.cfg #挂载目录
subPath: redis.cfg #默认是创建目录,设置这个参数后,不创建目录,而是创建文件
volumes:
- name: config
configMap:
name: cmfromfile
defaultMode: 0666 #可以设定文件权限