官方文档 ConfigMap
我们经常都需要为我们的应用程序配置一些特殊的数据,比如密钥、Token 、数据库连接地址或者其他私密的信息。你的应用可能会使用一些特定的配置文件进行配置,比如settings.py文件,或者我们可以在应用的业务逻辑中读取环境变量或者某些标志来处理配置信息。我们要做到这个,有好多种方案,比如:
通过env设置不同的环境,使用不同的yaml配置文件。ENV 设置环境变量
当然还有别的方案,但是各种方案都有各自的问题。
而且,还有一个问题就是,如果说我的一个配置,是要多个应用一起使用的,以上除了第三种方案,都没办法进行配置的共享,就是说我如果要改配置的话,那得一个一个手动改。假如我们有 100 个应用,就得改 100 份配置,以此类推……
kubernetes 对这个问题提供了一个很好的解决方案,就是用 ConfigMap 和 Secret。
configMap就是让项目镜像 和 配置、环境变量、配置文件等配置数据 解耦,保证镜像的可移植性
ConfigAPI给我们提供了向容器中注入配置信息的机制
,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。一种是挂载存储卷,一种是传递变量
。ConfigMap被引用之前必须存在,属于名称空间级别,不能跨名称空间使用,内容明文显示。ConfigMap内容修改后,对应的pod必须重启或者重新加载配置(支持热更新的应用,不需要重启)。应用场景:镜像往往是一个应用的基础,还有很多需要自定义的参数或配置,例如资源的消耗、日志的位置级别等等,这些配置可能会有很多,因此不能放入镜像中,Kubernetes中提供了Configmap来实现向容器中提供配置文件或环境变量来实现不同配置,从而实现了镜像配置与镜像本身解耦,使容器应用做到不依赖于环境配置。
向容器传递参数:
Docker | Kubernetes | 描述 |
---|---|---|
ENTRYPOINT | command | 容器中的可执行文件 |
CMD | args | 需要传递给可执行文件的参数 |
Dockerfile中EntryPoint和CMD的区别
Kubernetes如果需要向容器传递参数,可以在Yaml文件中通过command和args或者环境变量的方式实现。(不使用configMap的场景)
apiVersion: v1
kind: Pod
metadata:
name: print-greeting
spec:
containers:
- name: env-print-demo
image: hub.kaikeba.com/java12/bash:v1
env: #添加了一个环境变量
- name: GREETING
value: "Warm greetings to"
- name: HONORIFIC
value: "The Most Honorable"
- name: NAME
value: "Kubernetes"
command: ["echo"] #执行echo命令
args: ["$(GREETING) $(HONORIFIC) $(NAME)"] #命令中传入了这些参数,引用的就是上面env中定义的
# 创建后,命令 echo Warm greetings to The Most Honorable Kubernetes 将在容器中运行,也就是环境变量中的值被传递到了容器中。
# 查看pod就可以看出
kubectl logs podname
等待一会儿时间后,看到STATUS是Completed,Ready是0/1,pod中的容器已经结束了
因为我们yaml文件里就要求容器运行以后只执行一条指令,执行完成后就结束了
现在测试的这种情况是将配置数据和yaml资源文件耦合在一起了,接下来我们使用configMap分离
通过hepl命令可以查看configmap的用法:
[root@k8s-master-155-221 configmap]# kubectl create configmap --help
......
Aliases:
configmap, cm #可以使用cm替代
Examples:
# Create a new configmap named my-config based on folder bar
kubectl create configmap my-config --from-file=path/to/bar #从目录创建 文件名称为键 文件内容为值
# Create a new configmap named my-config with specified keys instead of file basenames on disk
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt #从文件创建 key1为键 文件内容为值
# Create a new configmap named my-config with key1=config1 and key2=config2
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 #直接命令行给定,键为key1 值为config1
# Create a new configmap named my-config from the key=value pairs in the file
kubectl create configmap my-config --from-file=path/to/bar #从文件创建 文件名为键 文件内容为值
# Create a new configmap named my-config from an env file
kubectl create configmap my-config --from-env-file=path/to/bar.env
# 指定目录
ls /docs/user-guide/configmap
# 创建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.propertes
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# 创建configmap ,指令
# game-config-1 :configmap的名称
# --from-file:指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl create configmap game-config-1 --from-file=docs/user-guide/configmap/properties
# 查看configmap文件
kubectl get cm
# 查看详细信息 -o 指定输出格式为yaml
kubectl get cm game-config -o yaml
kubectl describe cm
data就是数据区,存放的就是配置文件,key就是文件名,后面"|"后跟的就是配置文件内容,这个是yaml语法
清空环境
只需要指定为一个文件就可以从单个文件中创建ConfigMap
# 指定创建的文件即可
kubectl create configmap game-config-2 --from-file=/docs/user-guide/configmap/game.properties
#查看
kubectl get cm game-config-2 -o yaml
--from-file
这个参数可以使用多次,可以分别指定game.properties,ui.propertes,效果和指定整个目录是一样的。
# 使用--from-literal 方式直接创建configmap
# Create the ConfigMap
kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
# Get the ConfigMap Details for my-config
kubectl get configmaps my-config -o yaml
使用文字方式创建,利用 --from-literal
参数传递配置信息,该参数可以使用多次。
ConfigMap 是一个 API 对象, 让你可以存储其他对象所需要使用的配置。 和其他 Kubernetes 对象都有一个 spec 不同的是,ConfigMap 使用
data
和binaryData
字段。这些字段能够接收键-值对作为其取值。data
和binaryData
字段都是可选的。data
字段设计用来保存 UTF-8 字节序列,而binaryData
则 被设计用来保存二进制数据。
ConfigMap 的名字必须是一个合法的 DNS 子域名。
data
或binaryData
字段下面的每个键的名称都必须由字母数字字符或者 -、_ 或 . 组成。在data
下保存的键名不可以与在binaryData
下 出现的键名有重叠。
从 v1.19 开始,你可以添加一个 immutable 字段到 ConfigMap 定义中,创建 不可变更的 ConfigMap。
# 直接通过配置文件的方式创建
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:
name: game-config
namespace: default
你可以使用四种方式来使用 ConfigMap 配置 Pod 中的容器:
这些不同的方法适用于不同的数据使用方式。 对前三个方法,kubelet 使用 ConfigMap 中的数据在 Pod 中启动容器。
第四种方法意味着你必须编写代码才能读取 ConfigMap 和它的数据。然而, 由于你是直接使用 Kubernetes API,因此只要 ConfigMap 发生更改,你的 应用就能够通过订阅来获取更新,并且在这样的情况发生的时候做出反应。 通过直接进入 Kubernetes API,这个技术也可以让你能够获取到不同的名字空间 里的 ConfigMap。
先创建两个configMap
# 创建configMap, special.how: very 键名:键值
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
# 创建第二个configMap
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
# 第一种方式: 在pod中使用configmap配置,使用ConfigMap来替代环境变量
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: hub.kaikeba.com/library/myapp:v1
command: ["/bin/sh", "-c", "env"] #容器一但运行会执行命令/bin/sh -c env,会在控制台打印一下
env: # 第一种导入方式:在env中导入
- name: SPECIAL_LEVEL_KEY # name是当前容器环境变量的key
valueFrom: # 通过valueFrom
configMapKeyRef:
name: special-config # name是要引入哪个configMap的name
key: special.how # key是要引入该configMap中的哪个key
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
envFrom: # 第二种导入方式,直接使用envFrom导入
- configMapRef:
name: env-config
restartPolicy: Never
# 查看日志可以发现,环境变量注入到了容器中了,打印env就结束了
kubectl logs test-pod
用作命令行参数,将 ConfigMap 用作命令行参数时,需要先把 ConfigMap 的数据保存在环境变量中,然后通过 $(VAR_NAME) 的方式引用环境变量.
#第二种方式:用ConfigMap设置命令行参数
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: hub.kaikeba.com/java12/myapp:v1
command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] # 命令行中通过${}获取环境变量参数
env:
- name: SPECIAL_LEVEL_KEY
valueFrom: # 通过valueFrom引入
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
restartPolicy: Never
在数据卷里面使用这个ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
,即在 Pod 中将 ConfigMap 当做文件使用。
关于数据卷的详细内容将在下一节详细说
# 第三种方式:通过数据卷挂载ConfigMap
apiVersion: v1
kind: Pod
metadata:
name: test-pod3
spec:
containers:
- name: test-container
image: hub.kaikeba.com/library/myapp:v1
command: [ "/bin/sh", "-c", "sleep 600s" ]
volumeMounts: # 挂载数据卷
- name: config-volume # 指定数据卷名
mountPath: /etc/config # 表示把conifg-volume数据卷挂载到容器的/etc/config目录下
volumes: # 定义数据卷
- name: config-volume #给数据卷起名
configMap: #数据卷挂载configmap
name: special-config #挂载的configmap名字
restartPolicy: Never
登录容器查看/etc/config目录下是否挂载成功
# ConfigMap的热更新
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: hub.kaikeba.com/java12/myapp:v1
ports:
- containerPort: 80
volumeMounts: # 挂载数据卷
- name: config-volume
mountPath: /etc/config # 挂载到容器的/etc/config目录下
volumes:
- name: config-volume
configMap: # 数据卷挂载了上面的ConfigMap
name: log-config
# 修改ConfigMap
kubectl edit configmap log-config
# 修改log-level的值为DEBUG等待大概10秒钟时间,再次查看环境变量的值
修改configMap中数据:
官方文档Secret
Secret对象存储数据的方式是以键值方式存储数据,在Pod资源进行调用Secret的方式是通过环境变量或者存储卷的方式进行访问数据
,解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
另外,Secret对象的数据存储和打印格式为Base64编码的字符串,因此用户在创建Secret对象时,也需要提供该类型的编码格式的数据。在容器中以环境变量或存储卷的方式访问时,会自动解码为明文格式。
需要注意的是,如果是在Master节点上,Secret对象以非加密的格式存储在etcd中,所以需要对etcd的管理和权限进行严格控制。
要使用 Secret,Pod 需要引用 Secret。 Pod 可以用三种方式之一来使用 Secret:
Secret 对象的名称必须是合法的 DNS 子域名。 在为创建 Secret 编写配置文件时,你可以设置 data 与/或 stringData 字段。 data 和 stringData 字段都是可选的。data 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 stringData 字段,其中可以使用任何字符串作为其取值。
在创建 Secret 对象时,你可以使用 Secret 资源的 type 字段,或者与其等价的 kubectl 命令行参数(如果有的话)为其设置类型。 Secret 的类型用来帮助编写程序处理 Secret 数据。
Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。
内置类型 | 用法 |
---|---|
Opaque | 用户定义的任意数据 base64编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为generic; |
kubernetes.io/service-account-token | 服务账号令牌 用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中; |
kubernetes.io/dockercfg | ~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson | ~/.docker/config.json 文件的序列化形式 用来存储私有docker registry的认证信息,类型标识为docker-registry |
kubernetes.io/basic-auth | 用于基本身份认证的凭据 |
kubernetes.io/ssh-auth | 用于 SSH 身份认证的凭据 |
kubernetes.io/tls | 用于 TLS 客户端或者服务器端的数据 用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。 |
bootstrap.kubernetes.io/token | 启动引导令牌数据 |
通过为 Secret 对象的 type 字段设置一个非空的字符串值,你也可以定义并使用自己 Secret 类型。如果 type 值为空字符串,则被视为 Opaque 类型。 Kubernetes 并不对类型的名称作任何限制。不过,如果你要使用内置类型之一, 则你必须满足为该类型所定义的所有要求。
Kubernetes 在创建 Pod 时会自动创建一个服务账号 Secret 并自动修改你的 Pod 以使用该 Secret。该服务账号令牌 Secret 中包含了访问 Kubernetes API 所需要的凭据。
Service Account 用来访问kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中。
Service Account 不需要我们自己去管理的,此证书是由kubernetes自己来进行维护管理的。
# 创建pod
kubectl run my-nginx --image=hub.kaikeba.com/java12/nginx:v1
# 查看证书
kubctl exec -it podName -- sh
# 进入证书目录/run/secrets/kubernetes.io/serviceaccount查看即可
ca.crt
namespace
token
当 Secret 配置文件中未作显式设定时,默认的 Secret 类型是 Opaque。 当你使用 kubectl 来创建一个 Secret 时,你会使用 generic
子命令来标明 要创建的是一个 Opaque 类型 Secret。
Opaque类型的数据一个map类型,要求value是base64编码格式
# base64对用户名,密码加密效果演示
echo -n "admin" | base64
YWRtaW4=
echo -n "abcdefgh" | base64
YWJjZGVmZ2g=
看到多次加密结果都是一样的,破解很容易
# secret.yaml配置文件方式
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: YWJjZGVmZ2g=
username: YWRtaW4=
# 将secret挂载到volume中
apiVersion: v1
kind: Pod
metadata:
name: secret-test
labels:
name: secret-test
spec:
volumes: # 引入一个数据卷
- name: secrets
secret: # 挂载指定的secret
secretName: mysecret
containers:
- image: hub.kaikeba.com/java12/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath: "/etc/secrets" # 容器挂载数据卷,挂载到/etc/secrets目录下
readOnly: true
# 将secret导出到环境变量中
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: secret-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: hub.kaikeba.com/java12/myapp:v1
ports:
- containerPort: 80
env: # 设置环境变量
- name: TEST_USER
valueFrom:
secretKeyRef: # 核心在这里 secretKeyRef
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password