云原生要素-配置分离:ConfigMap&Secret
什么是ConfigMap
ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。
举一个例子更直观的看出ConfigMap是什么:比如我有一个nginx的Pod资源,那么ConfigMap就相当于nginx.conf这个配置文件。
需要注意的是:这个 Pod 和 ConfigMap 必须要在同一个 命名空间 中,不可跨命名空间。
ConfigMap供容器使用的典型用法如下:
- 生成容器内的环境变量。
- 设置容器启动命令的启动参数(需设置为环境变量)。
- 以Volume的形式挂载为容器内部的文件或目录。
ConfigMap与Secret类似,更倾向于前者适用于明文配置,后者适用于密码等配置。
ConfigMap的创建方式
configmap创建语法:
kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none] [options]
基于目录/文件方式创建configmap
- 创建一个用于练习的目录及文件,其中包含两个用于测试的文件
[root@k8s-master01 ~]# mkdir /configmap 您在 /var/spool/mail/root 中有新邮件 [root@k8s-master01 ~]# cd /configmap/ [root@k8s-master01 configmap]# mkdir conf [root@k8s-master01 configmap]# vim conf/test01.conf [root@k8s-master01 configmap]# vim conf/test02.conf 您在 /var/spool/mail/root 中有新邮件 [root@k8s-master01 configmap]# cat conf/test1.conf lives=3 name=haha [root@k8s-master01 configmap]# cat conf/test2.conf color.good=yellow user=mysql
- 创建一个cm(cm为configmap的缩写),与创建其他资源类型一样
[root@k8s-master01 configmap]# kubectl create configmap cmfile --from-file=conf/ [root@k8s-master01 configmap]# kubectl get cm NAME DATA AGE cmfile 2 13s kube-root-ca.crt 1 21d # 可以看到刚才创建的资源已经成功了
- 我们可以查看一下生成的cm的yaml文件
[root@k8s-master01 configmap]# kubectl get cm cmfile -oyaml apiVersion: v1 data: test1.conf: | lives=3 name=haha test2.conf: | color.good=yellow user=mysql kind: ConfigMap metadata: creationTimestamp: "2022-02-23T02:50:40Z" name: cmfile namespace: default resourceVersion: "1050098" uid: 39b904c2-c1a4-442c-a6fe-6a3d89af36ac
- 找到data,可以看到data下内容包含了之前测试创建的两个文件及内容
- 基于文件创建和目录是相似的,只要加上目录下的指定文件即可,比如:
[root@k8s-master01 configmap]# kubectl create cm cmfromfile --from-file=conf/test02.conf
- 有一个不常用的地方,自定义configmap中的名称
[root@k8s-master01 configmap]# vim test03.conf [root@k8s-master01 configmap]# kubectl create cm test03 --from-file=test03-conf=test03.conf configmap/test03 created [root@k8s-master01 configmap]# kubectl get cm test03 -o yaml apiVersion: v1 data: test03-conf: | user=www passwd=123456 kind: ConfigMap metadata: creationTimestamp: "2022-02-20T10:52:11Z" name: test03 namespace: default resourceVersion: "914180" uid: 2f41ffa8-f200-48ee-8e61-729cfdf81b97
- 可以看到上面例子中的test03.conf已经变成test03-conf格式了,这个了解即可。
基于env文件创建configmap
- 其实方式都一样,不细写了,看下创建方式:适用于较多的键值对
[root@k8s-master01 configmap]# kubectl create cm envfile --from-env-file=envfile.conf configmap/envfile created [root@k8s-master01 configmap]# kubectl get cm envfile -o yaml apiVersion: v1 data: age: "25" hehe: haha name: yy kind: ConfigMap metadata: creationTimestamp: "2022-02-23T03:02:58Z" name: envfile namespace: default resourceVersion: "1051876" uid: 27a62b22-cd46-4dbe-bf12-6b34a67befe8 # 可以看到里面的等号换成冒号
基于literal直接创建configmap
- 比如我们只需要一两个或很少的变量,没有写成文件的必要的时候可以用这种方式
[root@k8s-master01 configmap]# kubectl create cm literaltest --from-literal=PORT=8080 --from-literal=PASSWORD=123456
基于yaml文件创建configmap
- 这种就不说了,这是官网上的一个示例,有兴趣可以去看看
- 链接:https://kubernetes.io/zh/docs/concepts/configuration/configmap/
使用valueFrom定义环境变量
适合配置参数比较少的地方
我们先创建一个deploy资源方便测试,–dry-run的作用是只生成yaml文件而不创建资源
kubectl create deployment dp-cm --image=nginx --dry-run=client -o yaml > dp-cm.yaml
- 简单修改一下后剩余的yaml文件
[root@k8s-master01 configmap]# cat dp-cm.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: dp-cm name: dp-cm spec: replicas: 1 selector: matchLabels: app: dp-cm strategy: {} template: metadata: labels: app: dp-cm spec: containers: - image: nginx name: nginx
- 我们分别添加一个传统的环境变量和使用configmap定义一个
spec: containers: - image: nginx name: nginx env: - name: TEST_ENV value: test_env - name: TEST_X valueFrom: configMapKeyRef: name: envfile key: hehe
- env下第一个环境变量是我们按照传统模式定义;第二个是在configmap中取值,先看一下效果
[root@k8s-master01 configmap]# kubectl create -f dp-cm.yaml deployment.apps/dp-cm created [root@k8s-master01 configmap]# kubectl exec dp-cm-f8c48c84c-zvcwt -- env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=dp-cm-f8c48c84c-zvcwt NGINX_VERSION=1.21.6 NJS_VERSION=0.7.2 PKG_RELEASE=1~bullseye TEST_ENV=test_env TEST_X=haha
- 最后两个分别是我们直接定义的变量和引用configmap中的变量
- 如果引用多个变量只需要在后面添加定义即可
- name: TEST_X valueFrom: configMapKeyRef: name: envfile key: hehe - name: TEST_Y valueFrom: configMapKeyRef: name: envfile key: name
注意:如果引用的变量不存在会报错,Pod创建不成功
使用envfrom批量生成环境变量
spec: containers: - image: nginx name: nginx envFrom: - configMapRef: name: envfile
- 更新一下Pod,然后看一下结果
[root@k8s-master01 configmap]# kubectl replace -f dp-cm.yaml deployment.apps/dp-cm replaced [root@k8s-master01 configmap]# kubectl exec dp-cm-8565c44587-x8k62 -- env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=dp-cm-8565c44587-x8k62 NGINX_VERSION=1.21.6 NJS_VERSION=0.7.2 PKG_RELEASE=1~bullseye age=25 hehe=haha name=yy TEST_ENV=test_env
- 可以看到后面三行小写名称的就是我们
envfile
configMap中的内容 - 当一个Pod中变量有直接定义的也有从configMap定义时,我们可以加
prefix
前缀进行区分:
spec: containers: - image: nginx name: nginx envFrom: - configMapRef: name: envfile prefix: fromCm_ env: - name: TEST_ENV value: test_env
以文件形式挂载ConfigMap
- 我们事先创建了一个redis-conf的cm副本,然后挂载到下面文件的Pod中
spec: containers: - image: nginx name: nginx volumeMounts: - name: redisconf mountPath: /etc/config volumes: - name: redisconf configMap: name: redis-conf
- 上面这部分内容中volumes下有两个name,第一个是需要挂载到Pod的名称,第二个是configMap的名称,已经做了区分了。
- 执行yaml文件,进入Pod内部查看一下挂载情况
# 创建Pod [root@k8s-master01 ~]# kubectl create -f dp-cm.yaml # 进入到Pod中查看挂载情况 [root@k8s-master01 ~]# kubectl exec -ti dp-cm-77b4666649-jd4sc -- bash root@dp-cm-77b4666649-jd4sc:/# cd /etc/config/ root@dp-cm-77b4666649-jd4sc:/etc/config# ls redis-conf root@dp-cm-77b4666649-jd4sc:/etc/config# cat redis-conf hehe 123123 # 可以看到我们之前创建的文件已经挂载好了
- 在线编辑cm文件内容,挂载到Pod中的文件也会随着更改
[root@k8s-master01 ~]# kubectl edit cm redis-conf [root@k8s-master01 ~]# kubectl get cm redis-conf -o yaml redis-conf: | hehe 23412423412 [root@k8s-master01 ~]# kubectl exec -ti dp-cm-77b4666649-jd4sc -- bash root@dp-cm-77b4666649-jd4sc:/# cat /etc/config/redis-conf hehe 23412423412 # Pod中的文件也随着修改了
防止覆盖操作
比如我们有一个nginx-conf的configMap要挂载到nginx的/etc/nginx目录下,如果直接操作的话会发生覆盖/etc/nginx下所有内容,导致Pod报错。
所以需要加上subPath
来防止内容会覆盖,如下:
spec: containers: - image: nginx name: nginx volumeMounts: - name: nginxconf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf # 这样只会对这一个文件进行覆盖 volumes: - name: nginxconf configMap: name: nginx-conf
自定义文件名与授权
- 使用
item
自定义文件名:相当于做一个软连接
volumes: - name: redisconf configMap: name: redis-conf items: - key: redis.conf path: redis2.conf
- 使用
defaultMode
给ConfigMap中文件进行权限管理
volumes: - name: redisconf configMap: name: redis-conf items: - key: redis.conf path: redis2.conf mode: 0644 # 具体文件权限,优先级高 defaultMode: 0666 # configMap的默认权限
热更新操作
如果是通过yaml文件创建的,只需要在yaml文件中修改,然后kubectl replace
更新即可
如果是通过命令创建的话:
- 可以把cm导成yaml文件进行修改,然后更新,但是可能会出现错误,不建议。
- 还可以修改创建cm前使用的原始文件,比如
nginx.conf
文件,然后利用--dry-run=client
生成一个yaml文件,然后进行更新。如下:
kubectl create cm nginx-conf --from-file=nginx.conf --dry-run=client -oyaml | kubectl replace -f -
使用限制
- 需要提前创建ConfigMap或者Secret
- 引用的Key必须存在
- envFrom、valueFrom无法热更新操作
- envFrom配置环境变量,如果Key无效,会忽略无效的Key
- 资源需要在同一个命名空间
- subPath也是无法热更新的
内容不可变
ConfigMap或Secret中加入以下内容,执行后不可再修改资源
immutable: ture