转载:ConfigMap
一、ConfigMap介绍
-
ConfigMap是一种API对象,用来将非机密性的数据保存到键值对中。使用时,Pod可以将其用作环境变量、命令行参数或存储卷中的配置文件。
-
ConfigMap将你的环境配置信息和容器镜像解耦,便于应用配置的修改。
-
注意:ConfigMap并不提供保密或加密功能。如果你想存储的数据是机密性的,请使用Secret,或者使用其他第三方工具来保存你的数据的私密性,而不是用ConfigMap。
1.1、使用ConfigMap动机
-
使用ConfigMap来讲你的配置数据和应用程序代码分开。
-
比如,假设你正在开发一个应用,它可以在你自己的电脑上(用于开发)和在云上(用于实际流量)运行。你的代码里有一段是用于查看环境变量
DATABASE_HOST
,在本地运行时,你将这个变量设置为localhost
,在云上,你将其设置为引用Kubernetes集群中的公开数据库组件的服务。 -
这让你可以获取在云中运行的容器镜像,并且如果有需要的话,在本地调试完全相同的代码。
-
说明:ConfigMap在设计上不是用来存储大量的数据的。在ConfigMap中保存的数据不可超过1M。如果你需要保存超出尺寸限制的数据,你可能希望考虑挂载存储卷或者使用独立的数据库或文件服务。
1.2、ConfigMap对象
-
ConfigMap是一个让你可以额存储其他对象所需使用的配置的API对象。和其他Kubernetes对象都有一个
spec
不同的是,ConfigMap使用data
和binaryData
字段。这些字段能够结构键-值对作为其取值。data
和binaryData
字段都是可选的。data
字段设计用来保存UTF-8字符串,而binartyData
则被设计用来保存二进制数据作为base64编码的字符串。 -
ConfigMap的名字必须是一个合法的DNS子域名。
-
data
或binaryData
字段下面的每个键的名称都必须又字母数字字符或者-
、_
或.
组成。在data
下保存的键名不可以与在binaryData
下出现的键名有重叠。 -
从v1.19开始,你可以添加一个
immutable
字段到ConfigMap定义中,创建不可更得ConfigMap。
1.3、ConfigMap和Pod
-
你可以写一个引用ConfigMap得Pod的
spec
,并根据ConfigMap中的数据在该Pod中配置容器。这个Pod和ConfigMap必须要在同一个名称空间中(名称空间是Kubernetes用来支持隔离的单个集群中的资源组的一种抽象)。 -
说明:静态Pod中的spec字段不能引用ConfigMap或任何其他API对象。
二、示例
2.1、ConfigMap示例
-
这是一个ConfigMap的示例,它的一些键只有一个值,其他的键的值看起来像是配置的片段格式。
[root@master ~]# vim configmap.yaml
apiVersion: "v1"
kind: ConfigMap
metadata:
name: game-demo
data:
# 简单键值对:适用于简单的配置项,易于访问和修改。
# 每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 多行文件:适用于需要存储复杂的内容的配置项,比如配置文件,便于整体管理
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
# 应用ConfigMap资源
[root@master ~]# kubectl apply -f configmap.yaml
# 查看ConfigMap的详细信息
[root@master ~]# kubectl describe configmap game-demo
Name: game-demo
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
user-interface.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
game.properties:
----
enemy.types=aliens,monsters
player.maximum-lives=5
player_initial_lives:
----
3
ui_properties_file_name:
----
user-interface.properties
BinaryData
====
Events: <none>
2.2、Pod引用ConfigMap
-
你可以使用四种方式使用ConfigMap配置Pod中的容器:
-
1、在容器命令和参数内
-
2、在容器的环境变量
-
3、在只读卷里面添加一个文件,让应用来读取
-
4、编写代码在Pod中运行,使用Kubernetes API来读取ConfigMap
-
-
这些不同的方法适用于不同的数据使用方式。对于前三个方法,kubelet使用ConfigMap中的数据在Pod中启动容器。
-
第四种方法意味着你必须要编写代码才能读取ConfigMap和它的数据。然而,由于你是直接使用Kubernetes API,因此只要ConfigMap发生更改,你的应用就能够通过订阅来获取更新,并且在这样的情况发生的时候做出反应。通过直接进入kubernetes API,这个技术也可以让你能够获取到不同的名称空间里的ConfigMap。
-
下面是一个Pod引用ConfigMap的示例,它通过使用
game-demo
中的值来配置一个Pod:
[root@master ~]# vim pod-configmap.yaml
apiVersion: "v1"
kind: Pod
metadata:
name: configmap-demp-pod
spec:
containers:
- name: demo
image: alpine:latest
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
env:
# 定义环境变量
- name: PLAYER_INITIAL_LIVES # 请注意这里的变量是容器中的变量名称,和ConfigMap中的变量是不一样的
valueFrom:
configMapKeyRef:
name: game-demo # 这个值来自这个ConfigMap
key: player_initial_lives # 需要取值的键,会把这个键的值赋予给新变量
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# 你可以在Pod级别设置卷,然后将其挂载到Pod内的容器中
- name: config
# 定义这个卷的取值将会从ConfigMap中获取
configMap:
# 提供你要想挂载的ConfigMap的名字
name: game-demo
# 来自ConfigMap的一组键,将被创建为文件挂载到Pod中,并且文件名是path字段指定的
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
# 备注:volumes中定义的items字段可以更精准的控制configmap中的哪些键值被变换为文件挂载到容器中。如果不指定items那么将把configmap中的所有键都转换为文件挂载到容器中
# 应用资源清单
[root@master ~]# kubectl apply -f pod-configmap.yaml
-
ConofigMap不会区分单行属性值和多行类似文件的值,重要的是Pod和其他对象如何使用这些值。
-
上面的例子定义了一个卷并将它作为
/config
文件夹挂载到demo
容器内,创建两个文件,/config/game.properties
和/config/user-interface.properties
,尽管ConfigMap中包含了四个键,这是因为Pod定义中在volumes
节指定了一个items
数组。如果你完全忽略items
数组,则ConfigMap中的每个键都会变成一个与该键同名的文件,因此你会得到四个文件。
2.3、验证Pod引入ConfigMap(变量)
[root@master ~]# kubectl exec -it configmap-demp-pod -- sh
/ # echo $PLAYER_INITIAL_LIVES
3
/ # echo $UI_PROPERTIES_FILE_NAME
user-interface.properties
2.3、验证Pod引入ConfigMap(文件)
[root@master ~]# kubectl exec -it configmap-demp-pod -- sh
/ # ls /config/
game.properties user-interface.properties
/ # cat /config/game.properties
enemy.types=aliens,monsters
player.maximum-lives=5
/ # cat /config/user-interface.properties
color.good=purple
color.bad=yellow
allow.textmode=true
三、使用ConfigMap
-
ConfigMap可以作为数据卷挂载。ConfigMap也可以被系统的其他组件使用,而不一定直接暴露给Pod。例如,ConfigMap可以保存系统中其他组件要使用的配置数据。
-
CinfigMap最常见的用法就是同一个名称空间里某个Pod(如控制器)中运行的容器执行配置,你也可以单独使用ConfigMap来调整其行为的插件(扩展Kubernetes功能的资源)或者operator(一种用于管理自定义资源的专用控制器)
3.1、在Pod中将ConfigMap当作文件使用
-
要在一个Pod(如其他控制器如Deployment)的存储卷中使用ConfigMap:
-
1、创建一个ConfigMap对象或者使用现有的ConfigMap对象。多个Pod可以引用同一个ConfigMap。
-
2、修改Pod定义,在
spec.volumes[]
下添加一个卷。为该卷设置任意名称,之后将spec.volumes[].configMap.name
字段设置为对你的ConfigMap对象的引用。 -
3、为每个需要该ConfigMap的容器添加一个
.spec.containers[].volumeMounts[]
。设置.spec.containers[].volumeMounts[].readOnly=true
并将.spec.containers[].volumeMounts[].mountPath
设置为一个未使用的目录名,ConfigMap的内容将出现在该目录中 -
4、更改你的镜像或命令行,以便程序能够从该目录中查找文件。ConfigMap中的每个
data
键会变成mountPath
下面的一个文件名。
-
-
下面是一个将ConfigMap以卷的形式进行挂载的Pod示例。
[root@master ~]# vim pod-1.yaml
apiVersion: "v1"
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: alpine:latest
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
# 注意:如果是以这种情况挂载到Pod中,那么将会把这个ConfigMap里面所有的键全部转换为与键名相同名字的文件挂载到Pod中
name: game-demo
# 应用资源清单
[root@master ~]# kubectl apply -f pod-1.yaml
# 验证
# 通过查看我们可以得知,如果再不指定itmes数组的情况下,会把configmap中的所有键转为文件挂载容器中
[root@master ~]# kubectl exec -it mypod -- ls /etc/foo
game.properties ui_properties_file_name
player_initial_lives user-interface.properties
-
如果Pod中有多个容器,则每个容器都需要自己的
volumeMounts
块,但针对每个ConfigMap,你只需要设置一个spec.volumes
块,一个Pod多个容器类似于下面的示例
[root@master ~]# cat pod-1.yaml
apiVersion: "v1"
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod1
image: alpine:latest
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
- name: mypod2
image: alpine:latest
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
# 注意:如果是以这种情况挂载到Pod中,那么将会把这个ConfigMap里面所有的键全部转换为与键名相同名字的文件挂载到Pod中
name: game-demo
[root@master ~]# kubectl apply -f pod-1.yaml
[root@master ~]# kubectl exec -it mypod -c mypod1 -- ls /etc/foo
game.properties ui_properties_file_name
player_initial_lives user-interface.properties
[root@master ~]# kubectl exec -it mypod -c mypod2 -- ls /etc/foo
game.properties ui_properties_file_name
player_initial_lives user-interface.properties
3.2、在Pod中使用ConfigMap作为环境变量使用
-
使用configmap在Pod中设置环境变量
-
1、对于Pod规约中的每个容器,为要使用的每个ConfigMap键添加一个环境变量到
env[].valueFrom.configMapKeyRef
字段 -
2、修改你的镜像或命令行,以便程序查找指定变量中的值。
-
-
下面是一个将ConfigMap定义为Pod的环境变量的示例
[root@master ~]# vim pod-2.yaml
apiVersion: "v1"
kind: Pod
metadata:
name: env-configmap
spec:
containers:
- name: envars-test-container
image: alpine:latest
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
env:
- name: CONFIGMAP_USERNAME # 新变量的变量名
valueFrom:
configMapKeyRef:
name: game-demo # 要进行取值的configmap名称
key: game.properties # 要进行取值的键名
# 需要注意的是,Pod中环境变量名称允许的字符范围是有限的。如果某些变量名不满足这些规则,则即使Pod可以被启动,你的容器也无法访问这些环境变量
# 应用资源清单
[root@master ~]# kubectl apply -f pod-2.yaml
# 验证
[root@master ~]# kubectl exec -it env-configmap -- sh
/ # echo $CONFIGMAP_USERNAME
enemy.types=aliens,monsters player.maximum-lives=5
3.3、被挂载的ConfigMap内容会被自动更新
-
当卷中使用的ConfigMap被更新时,所投射的键最终也会被更新。kubelet组件会在每次周期性同步时检查所有挂载的ConfigMap是否为最新。不过,kubelet使用的时其本地高速缓存来获得ConfigMap的当前值
-
以环境变量方式使用的ConfigMap数据不会被自动更新。更新这些数据需要重新启动Pod。
3.5、不可变更的ConfigMap
-
Kubernetes特性Immutable Secret和ConfigMap提供了一种将各个Secret和configMap设置为不可变更的选项。对于大量使用ConfigMap的集群(至少有数万个各不相同的ConfigMap给Pod挂载)而言,禁止更新ConfigMap的数据有以下好处:
-
保护应用,使之免受意外(不想要的)更新所带来的负面影响。
-
通过大幅降低对kube-apserser的压力提升集群性能,这是因为系统会关闭对已标记为不可变更的ConfigMap的监视操作。
-
-
你可以通过将
immutable
字段设置为true
创建不可变更的ConfigMap
[root@master ~]# vim configmap.yaml
apiVersion: "v1"
kind: ConfigMap
metadata:
name: game-demo
data:
# 简单键值对:适用于简单的配置项,易于访问和修改。
# 每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 多行文件:适用于需要存储复杂的内容的配置项,比如配置文件,便于整体管理
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
immutable: true
# 应用资源清单
[root@master ~]# kubectl apply -f configmap.yaml
# 验证
# 以下我把player_initial_lives变量的值改为10查看效果
player_initial_lives: "10"
# 可以看出设置为了不可变更的configmap之后,里面的内容是不允许更改的
[root@master ~]# kubectl apply -f configmap.yaml
The ConfigMap "game-demo" is invalid: data: Forbidden: field is immutable when `immutable` is set
-
一旦某ConfigMap被标记为不可表更,则无法逆转这一变化,也无法更改
data
或binaryData
·字段的内容。你只能删除并重建ConfigMap。因为现有的Pod会维护一个已被删除的ConfigMap的挂载点,建议重新创建这些Pod
四、Secret
Secret
是 Kubernetes 中用来存储敏感信息的资源对象,比如密码、OAuth 令牌和 SSH 密钥。与 ConfigMap
类似,Secret
也可以被挂载到 Pod 中,但它们被设计为比 ConfigMap
更安全,因为它们默认是加密存储的。
定义
Secret
是 Kubernetes API 的一部分,它提供了一种安全的方式来存储和管理敏感数据。与 ConfigMap
不同,Secret
被设计为存储敏感信息,并在 API 服务器上进行加密存储。
存储结构
Secret
也使用键值对来存储数据,但这些数据在存储时会被自动加密,以确保安全性。
使用场景
-
密码:数据库密码、服务账户密码等。
-
API 密钥:用于访问外部服务的密钥。
-
TLS/SSL 证书:用于服务端加密的证书和私钥。
创建和更新
Secret
可以通过多种方式创建和更新:
-
使用
kubectl
命令行工具。 -
通过 Kubernetes 的 YAML 或 JSON 配置文件。
-
从文件或字面量值创建。
挂载方式
Secret
同样可以以两种方式挂载到 Pod 中:
-
Volume 挂载:将
Secret
作为卷挂载到 Pod 中,容器可以访问挂载的文件。 -
环境变量:将
Secret
中的键值对作为环境变量注入到容器中。
特点
-
安全性:
Secret
数据在 API 服务器上进行加密存储,提供比ConfigMap
更高的安全级别。 -
自动旋转:Kubernetes 支持自动旋转
Secret
,以提高安全性。 -
访问控制:可以对
Secret
设置访问控制,限制哪些用户或服务可以访问这些敏感数据。
示例
创建一个包含密码的 Secret
:
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
password: cGFzc3dvcmQ=
在这个示例中,password
的值是使用 Base64 编码的。在 Pod 中使用这个 Secret
作为环境变量:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: my-image
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
restartPolicy: Never
注意事项
-
Secret
应该只包含敏感信息,避免存储非敏感数据。 -
尽管
Secret
数据在 API 服务器上是加密的,但一旦挂载到 Pod 中,它们将以明文形式存在,因此需要确保 Pod 的安全性。 -
Secret
对象在 Kubernetes 集群中是持久的,但它们存储的数据不是跨集群持久的。
通过使用 Secret
,你可以确保应用程序的敏感数据得到妥善保护,同时保持应用程序的灵活性和可维护性。
五、区别和使用建议
-
数据敏感性:
ConfigMap
适用于非敏感数据,而Secret
适用于敏感数据。 -
数据加密:
Secret
存储的数据默认是加密的,而ConfigMap
不是。 -
使用方式:两者都可以被挂载到 Pod 作为文件或环境变量,但
Secret
通常用于存储需要严格保密的信息。
在实际使用中,根据数据的敏感性选择合适的资源对象是非常重要的。对于不包含敏感信息的配置数据,使用 ConfigMap
就足够了;而对于包含敏感信息的数据,使用 Secret
可以提供额外的安全性。