一、概述ConfigMap

  ConfigMap是一种api对象,用来非机密性的数据保存到键值对中。使用时,pods可以将其用作环境变量、命令行参数或存储中的配置文件。

  ConfigMap使环境配置信息和容器镜像解耦,便于应用配置的修改。

ConfigMap并不提供加密或保密的功能。 如果你想存储的数据是机密的,请使用 Secret, 或者使用其他第三方工具来保证你的数据的私密性,而不是用 ConfigMap。

  ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果你需要保存超出此尺寸限制的数据,你可能希望考虑挂载存储卷 或者使用独立的数据库或者文件服务

  ConfigMap 是一个 API 对象, 让你可以存储其他对象所需要使用的配置。 和其他 Kubernetes 对象都有一个 spec 不同的是,ConfigMap 使用 data 和 binaryData 字段。这些字段能够接收键-值对作为其取值。data 和 binaryData 字段都是可选的。data 字段设计用来保存 UTF-8 字符串,而 binaryData 则被设计用来保存二进制数据作为 base64 编码的字串。

  ConfigMap 的名字必须是一个合法的 DNS 子域名。

  data 或 binaryData 字段下面的每个键的名称都必须由字母数字字符或者 -、_ 或 . 组成。在 data 下保存的键名不可以与在 binaryData 下出现的键名有重叠。

  从 v1.19 开始,你可以添加一个 immutable 字段到 ConfigMap 定义中, 创建不可变更的 ConfigMap。

  不可变更的ConfigMap

  FEATURE STATE: ​​Kubernetes v1.21 [stable]​

  Kubernetes 特性 Immutable Secret 和 ConfigMaps 提供了一种将各个 Secret 和 ConfigMap 设置为不可变更的选项。对于大量使用 ConfigMap 的集群 (至少有数万个各不相同的 ConfigMap 给 Pod 挂载)而言,禁止更改 ConfigMap 的数据有以下好处:

  • 保护应用,使之免受意外(不想要的)更新所带来的负面影响。
  • 通过大幅降低对 kube-apiserver 的压力提升集群性能, 这是因为系统会关闭对已标记为不可变更的 ConfigMap 的监视操作。

此功能特性由 ​​ImmutableEphemeralVolumes​​​ 特性门控来控制。 你可以通过将 ​​immutable​​​ 字段设置为 ​​true​​ 创建不可变更的 ConfigMap。 例如:

apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true

  一旦某 ConfigMap 被标记为不可变更,则 无法 逆转这一变化,,也无法更改 ​​data​​​ 或 ​​binaryData​​ 字段的内容。你只能删除并重建 ConfigMap。 因为现有的 Pod 会维护一个已被删除的 ConfigMap 的挂载点,建议重新创建这些 Pods

    静态 Pod 中的 spec 字段不能引用 ConfigMap 或任何其他 API 对象。

二、kubernetes的配置

  1. 在容器命令和参数内
  2. 容器的环境变量
  3. 在只读卷里面添加一个文件,让应用来读取
  4. 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

  一)通过命令参数配置

  在配置文件中定义command和args会覆盖镜像文件中相关的默认设定,这类程序会被直接运行,而不会由shell解释器解释运行,因此与sehll相关的特性均不被支持,如命令行展开符号 {}、重定向等操作。

  Kubernetes配置文件中的command对应于Dockerfile中的ENTRYPOINT,而配置文件的args则对应于Dockerfile中的CMD。在Kubernetes中只给出command字段时,他会覆盖Dockerfile中的ENTRYPOINT和CMD,只给出args字段时,它仅覆盖CMD,而同时给出command和args时,它会对应覆盖ENTRYPOINT和CMD。

  二)利用环境变量配置

  环境变量配置容器化应用时,需要在容器配置段中嵌套使用env字段,它的值是一个由环境变量构建的列表。环境变量由name和value(或valueFrom)字段构成。

  打印环境变量

kubectl exec -it  -n loki promtai-promtail-5lpvt  -- printenv


  三)创建ConfigMap的方法

  1、通过键值对创建ConfigMap

  利用kubectl create configmap命令使用--from-literal选项可在命令行直接给出键值对来创建ConfigMap对象,重复使用此选项则可以传递多个键值对,命令格式如下:

kubectl create configmap configmap_name --from-literal=key-name01=value-1


  2、通过文件创建ConfigMap

  利用kubectl create configmap命令使用--from-file选项可基于文件内容来创建ConfigMap对象,它的命令格式如下:

kubectl create configmap <configmap_name> --from-file=<[key=]source>


  3、通过目录创建ConfigMap

  如果配置文件数量较多时,kubectl还提供了基于目录直接将多个文件分别收纳为键值数据的ConfigMap资源创建方式,将--from-file选项后所跟的路径指向一个目录路径就能把目录下的所有文件一同创建同一个 ConfigMap 资源中,命令格式如下: 

kubectl create configmap <configmap_name> --from-file=<path-to-directory>


  4、通过存储卷将ConfigMap载入Pod

  ​​https://www.jianshu.com/p/4c29ccc6737a​

  若ConfigMap对象中的键值来源于较长的文件内容,那么使用环境变量将其导入会使得变量值占据过多的内存空间而不易清理。此类数据通常用于为容器应用提供配置文件,因此将其内存直接作为文件进行引用方为较好的选择,其实现方式是,在定义Pod资源时,将此类ConfigMap对象配置为ConfigMap类型的存储卷,而后由容器将其挂载至特定的挂载点后直接进行访问。

  挂载整个存储卷

  关联为Pod资源的存储卷时,ConfigMap对象中的每个键都对应地对应为一个文件,键名转为文件名,而值则为相应文件的内容,即便是通过直接创建的键值数据,也一样表现为文件视图。挂载于容器上之后,由键值数据表现出的文件位于挂载点目录中,容器中的进程可直接读取这些文件的内容。

  配置Pod资源时,基于存储卷的方式引用ConfigMap对象的方法非常简单,仅需要指明卷名称及要应用的ConfigMap对象名称即可。

    1)创建配置文件

  创建三个Nginx配置文件,然后将这三个配置文件挂载到Nginx的配置目录中

    2)创建ConfigMap对象

  基于目录创建configMap

kubectl create configmap nginx-configmap --from-file=./data/nginx/conf.d/

  查看configmap

kubectl describe configmap nginx-configmap
    3)创建Pod资源清单来引用ConfigMap对象并将其挂载至相应指定的目录中(configMap引用)


[root@k8s-master configmap]# cat configmaps-env-demo.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
name: demoapp-config
namespace: default
data:
demoapp.port: "8080"
demoapp.host: 0.0.0.0
---
apiVersion: v1
kind: Pod
metadata:
name: configmaps-env-demo
namespace: default
spec:
containers:
- image: ikubernetes/demoapp:v1.0
name: demoapp
env:
- name: PORT
valueFrom:
configMapKeyRef: #引用configMap 键值
name: demoapp-config
key: demoapp.port
optional: false #是否为可有可无项 false 为必选项
- name: HOST
valueFrom:
configMapKeyRef:
name: demoapp-config
key: demoapp.host
optional: true #是否可有可无 ture 非必选项

[root@k8s-master configmap]# kubectl apply -f configmaps-env-demo.yaml
[root@k8s-master configmap]# kubectl get pod
NAME READY STATUS RESTARTS AGE
centos-deployment-66d8cd5f8b-95brg 1/1 Running 0 46h
configmaps-env-demo 1/1 Running 0 118s
my-grafana-7d788c5479-bpztz 1/1 Running 1 46h
volumes-pvc-longhorn-demo 1/1 Running 0 27h
[root@k8s-master comfigmap]# kubectl exec configmaps-env-demo -- netstat -tnl #查看配置是否生效
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN

[root@k8s-master configmap]# cat configmaps-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmaps-volume-demo
namespace: default
spec:
containers:
- image: nginx:alpine
name: nginx-server
volumeMounts:
- name: ngxconfs
mountPath: /etc/nginx/conf.d/
readOnly: true
volumes :
- name: ngxconfs
configMap:
name: nginx-config-files #引用前面定义的configmap
optional: false


[root@k8s-master configmap]# kubectl get pod
NAME READY STATUS RESTARTS AGE
centos-deployment-66d8cd5f8b-95brg 1/1 Running 0 46h
configmaps-env-demo 1/1 Running 0 35m
configmaps-volume-demo 1/1 Running 0 6m8s
my-grafana-7d788c5479-bpztz 1/1 Running 1 46h
volumes-pvc-longhorn-demo 1/1 Running 0 28h


[root@k8s-master configmap]# kubectl exec configmaps-volume-demo -it -- /bin/sh
/ # nginx -T

......
# configuration file /etc/nginx/conf.d/myserver.conf: #看容器配置文件是否加载configmap配置
server {
listen 8080;
server_name www.ik8s.io;

include /etc/nginx/conf.d/myserver-*.cfg;

location / {
root /usr/share/nginx/html;
}
}

# configuration file /etc/nginx/conf.d/myserver-gzip.cfg:
gzip on;
gzip_comp_level 5;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/xml text/javascript;

# configuration file /etc/nginx/conf.d/myserver-status.cfg:
location /nginx-status {
stub_status on;
access_log off;
}

[root@k8s-master configmap]# kubectl get pods configmaps-volume-demo -o go-template={{.status.podIP}}
10.244.1.177
[root@k8s-master configmap]# curl 10.244.1.177:8080 #默认页面
...
<h1>Welcome to nginx!</h1>


[root@k8s-master configmap]# curl -H "Host:www.ik8s.io" 10.244.1.177:8080/nginx-status #自定义页面
Active connections: 1
server accepts handled requests
2 2 2
Reading: 0 Writing: 1 Waiting: 0

  挂载configMap的方法

  • 挂载卷时通过items:参数 指定允许输出到卷的键
[root@k8s-master configmap]# ls demoapp-conf.d/  #3个配置文件
envoy.yaml lds.conf myserver.conf

[root@k8s-master configmap]# cat demoapp-conf.d/envoy.yaml
node:
id: sidecar-proxy
cluster: demoapp-cluster

admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }

dynamic_resources:
lds_config:
path: '/etc/envoy/lds.conf'

static_resources:
clusters:
- name: local_service
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080

[root@k8s-master configmap]# cat demoapp-conf.d/lds.conf
{
"version_info": "0",
"resources": [
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "listener_0",
"address": {
"socket_address": {
"address": "0.0.0.0",
"port_value": 80
}
},
"filter_chains": [
{
"filters": [
{
"name": "envoy.http_connection_manager",
"config": {
"stat_prefix": "ingress_http",
"codec_type": "AUTO",
"route_config": {
"name": "local_route",
"virtual_hosts": [
{
"name": "local_service",
"domains": [
"*"
],
"routes": [
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "local_service"
}
}
]
}
]
},
"http_filters": [
{
"name": "envoy.router"
}
]
}
}
]
}
]
}
]
}


[root@k8s-master configmap]# cat configmaps-volume-demo2.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmaps-volume-demo2
namespace: default
spec:
containers:
- name: proxy
image: envoyproxy/envoy-alpine:v1.14.1
command: ['/bin/sh','-c','envoy -c /etc/envoy/..data/envoy.yaml']
volumeMounts:
- name: appconfs #通过挂载卷引用comfigmap
mountPath: /etc/envoy
readOnly: true
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env: #通过环境变量引用 但这里引用的comfigmap文件中并没有定义
- name: PORT
valueFrom:
configMapKeyRef:
name: demoapp-confs
key: demoapp.port
optional: false
- name: HOST
valueFrom:
configMapKeyRef:
name: demoapp-confs
key: demoapp.host
optional: true
volumes:
- name: appconfs
configMap:
name: demoapp-confs #这里只引用的2个文件
items: #默认只允许哪些键 输出给存储卷
- key: envoy.yaml #挂载的键名
path: envoy.yaml #挂载的文件名 可以和上面不一样
mode: 0644 #挂载后的权限
- key: lds.conf
path: lds.conf
mode: 0644
optional: false

[root@k8s-master configmap]# kubectl create cm demoapp-confs --from-literal=demoapp.host=127.0.0.1 --from-literal=demoapp.port="8080" --from-file=./demoapp-conf.d/ #创建时定义demoapp.host、demoapp.port

[root@k8s-master ~]# kubectl describe cm demoapp-confs
Name: demoapp-confs
Namespace: default
Labels: <none>
Annotations: <none>

Data
====
demoapp.host:
----
127.0.0.1
demoapp.port:
----
8080
envoy.yaml:
----
node:
id: sidecar-proxy
cluster: demoapp-cluster

admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }

dynamic_resources:
lds_config:
path: '/etc/envoy/lds.conf'

static_resources:
clusters:
- name: local_service
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080

lds.conf:
----
{
"version_info": "0",
"resources": [
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "listener_0",
"address": {
"socket_address": {
"address": "0.0.0.0",
"port_value": 80
}
},
"filter_chains": [
{
"filters": [
{
"name": "envoy.http_connection_manager",
"config": {
"stat_prefix": "ingress_http",
"codec_type": "AUTO",
"route_config": {
"name": "local_route",
"virtual_hosts": [
{
"name": "local_service",
"domains": [
"*"
],
"routes": [
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "local_service"
}
}
]
}
]
},
"http_filters": [
{
"name": "envoy.router"
}
]
}
}
]
}
]
}
]
}

Events: <none>

[root@k8s-master configmap]# kubectl apply -f configmaps-volume-demo2.yaml
pod/configmaps-volume-demo2 created

[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
configmaps-volume-demo 1/1 Running 0 6h47m 10.244.1.177 k8s-node1 <none> <none>
configmaps-volume-demo2 2/2 Running 0 35m 10.244.1.182 k8s-node1 <none> <none>
my-grafana-7d788c5479-bpztz 1/1 Running 1 2d5h 10.244.2.120 k8s-node2 <none> <none>
volumes-pvc-longhorn-demo 1/1 Running 0 35h 10.244.2.124 k8s-node2 <none> <none>

[root@k8s-master ~]# kubectl exec configmaps-volume-demo2 -c demo -- netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9901 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 1/python3
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -

[root@k8s-master ~]# kubectl exec configmaps-volume-demo2 -c proxy -- netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9901 0.0.0.0:* LISTEN 1/envoy
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/envoy

[root@k8s-master ~]# kubectl exec configmaps-volume-demo2 -c proxy -- ls /etc/envoy
envoy.yaml
lds.conf


  • 在容器挂载卷时,指定挂载哪些卷

  在容器挂载时指定挂载哪些键

[root@k8s-master configmap]# cat configmaps-volume-demo3.yaml 
apiVersion: v1
kind: Pod
metadata:
name: configmap-volume-demo3
namespace: default
spec:
containers:
- image: nginx:alpine
name: nginx-server
volumeMounts:
- name: ngxconfs
mountPath: /etc/nginx/conf.d/myserver.conf #本机挂载目录
subPath: myserver.conf #挂载configMap中的子项 目录或某个值
readOnly: true
- name: ngxconfs
mountPath: /etc/nginx/conf.d/myserver-gzip.cfg
subPath: myserver-gzip.cfg
readOnly: true
volumes:
- name: ngxconfs
configMap:
name: nginx-config-files #之前示例中已经创建 包含3个DATA数据项

[root@k8s-master configmap]# kubectl apply -f configmaps-volume-demo3.yaml
pod/configmap-volume-demo3 created

[root@k8s-master configmap]# kubectl exec configmap-volume-demo3 -it -- /bin/sh #只引用了其中2项数据
/ # ls /etc/nginx/conf.d/
default.conf myserver-gzip.cfg myserver.conf