5.2 ConfigMap和 Secret
ConfigMap 可以用来存储非机密性的数据到键值对中,这些信息会被存储到 etcd,不会分节点,任何节点都可以使用到。使用时,将其用作环境变量、命令行参数或者存储卷中的配置文件送入到 Pod 中,主要目的是解耦你的应用程序和配置,这样不必维护那些 .json 等配置文件,也可以避免不小心将带有机密信息的配置文件上传到代码仓库中。但是 ConfigMap 中的内容都是非加密的,可以很容易地看到全部信息,如果需要加密,则使用 secret。
ConfigMap
创建 configMap
创建 configMap 的命令格式:
kubectl create configmap <map-name> <data-source>
kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none]
如果忘记了,可以使用
kubect create configmap --help
快速获取文档说明。
如果以文件(--from-file
)形式创建 ConfigMap,则为 key,文件内容为 value,--from-file
也可以指定目录。
如果以键值对(--from-literal
)形式创建 ConfigMap,可直接创建 key=value
。
可以根据文件内容、目录或键值对创建 ConfigMap,ConfigMap 可以指定多个来源。当基于目录创建一个 ConfigMap时,每个文件的基名是该目录中的有效密钥,这些文件将被打包到 ConfigMap中。
这三点都是从哪里生成 k-v 到 ConfigMap,不要纠结于字面。
直接使用键值对创建 ConfigMap:
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
查看 ConfigMap:
root@master:~# kubectl get configmap my-config
Data
====
key1:
----
config1
key2:
----
config2
--from-literal
表示,当前使用键值对赋值的形式创建 ConfigMap。
通过文件内容生成 ConfigMap,文件内容示例:
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
设置文件名称为 c.txt。
文件中的内容使用键值对形式。
创建 ConfigMap:
kubectl create configmap my-config1 --from-file=c.txt
查看 ConfigMap:
root@master:~# kubectl describe configmap my-config1
Data
====
c.txt:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
多个文件:
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
通过目录创建 ConfigMap,创建目录和文件,其目录结构如下:
├── config
│ ├── a.txt
│ └── b.txt
root@master:~# cat config/a.txt a=666 root@master:~# cat config/b.txt b=666
创建 ConfigMap:
kubectl create configmap my-config2 --from-file=config/
查看 ConfigMap:
root@master:~# kubectl describe configmap my-config2
Data
====
a.txt:
----
a=666
b.txt:
----
b=666
注意,通过 文件 或目录创建的 ConfigMap 中,文件名称为 Key,而文件内容为 Value,所以
a=666
是文件的值,里面不能再分为 Key a、Value B,a=666
是一个值。或者改成下面这样会更容易理解:
==== name.txt: ---- 痴者工良 url.txt: ---- k8s.whuanle.cn
下面将介绍怎么使用 ConfigMap。
在环境变量中使用
前面我们已经创建了 my-config、 my-config1、 my-config2 三个配置,我们希望些这配置,能够以环境变量的形式传递到 容器中,那么定义 Pod 时其 YAML 模板如下:
env:
- name:letter
valueFrom:
configMapKeyRef:
name: my-config2
key: a.txt
注:key 为 |
之前的名称,例如 a.txt
,文件名;
或者:
envFrom:
- configMapRef:
name: my-config2
如果要整个 configMap 的内容全部导入,则使用 envFrom,如果要只使用一部分,可以用 valueFrom。
那么我们来真实启动一个 Nginx Pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: myconfig_a
valueFrom:
configMapKeyRef:
name: my-config2
key: a.txt
- name: myconfig_b
valueFrom:
configMapKeyRef:
name: my-config2
key: b.txt
[Info] 提示
如果 ConfigMap 通过文件或目录创建的,那么每个文件的环境变量是打包一起的。所以:
configMapKeyRef: name: my-config2 key: a.txt
a.txt 中的环境变量映射到 myconfig_a。
kubectl apply -f configMapNginx.yaml
打印 Pod 中的环境变量:
root@master:~# kubectl exec nginx -- printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx
myconfig_a=a=666
myconfig_b=b=666
不过这样映射会有的奇怪,因此使用环境变量使用 ConfigMap 时,都是使用 K/V 的数据,而不使用通过文件、目录的数据。
ConfigMap 卷
configMap
卷 提供了向 Pod 注入配置数据的方法。其主要用途是给 Pod 中的容器传递配置,在 Pod 中显示为文件。
Pod 的 YAML 文件示例:
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: configmap-pod
image: busybox
command: ["ls"]
args: ["/etc/config"]
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: my-config
查看此 Pod 的日志:
root@master:~# kubectl logs configmap-pod
key1
key2
key1 文件中存储了 值,ConfigMap my-config 中有
key1=config1
、key2=config2
两个配置,则在 key1文件中,其值为 config1。
但是这样好像没啥意思,既然要映射为文件,应该创建有意思的内容。
下面创建一个 config.json 文件:
{
"name": "痴者工良",
"url": "k8s.whuanle.cn"
}
创建 ConfigMap:
kubectl create configmap my-config3 --from-file=config.json
root@master:~# kubectl describe configmap my-config3
Name: my-config3
config.json:
----
{
"name": "痴者工良",
"url": "k8s.whuanle.cn"
}
映射为 Pod 中的文件:
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: configmap-pod
image: busybox
command: ["cat"]
args: ["/etc/config/config.json"]
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: my-config3
查看容器中被映射的文件:
root@master:~# kubectl logs configmap-pod
{
"name": "痴者工良",
"url": "k8s.whuanle.cn"
}
# cat /etc/config/config.json
[Success] 提示
通过 ConfigMap 卷映射到容器中,如果使用的是 mountPath 挂载到目录,则 ConfigMap 更新内容时,容器中的配置文件内容也会被更新,但是可能需要几分钟。如果挂载的目录是容器中已经存在的,则可能无法同步更新,因此挂载 ConfigMap 到容器中的时,需要使用一个新的目录。
多键值对
前面提到,如果有个 a.txt 文件:
key1=value1
key2=value2
... ...
如果使用 --from-file
等导入 ConfigMap 中,并不会达到我们想要同时导入多个值的效果,导入后会变成 a.txt="key1=value1... ..."
。它更可能使用 JSON、YAML 文件来表达,如:
{
"ConnectString": "mysql=192.168.0.1;user=admin... ..."
}
然后使用 kubectl create configmap test --from-file=sql.config
,然后在 Pod 中使用 sql.config
这个环境变量或卷文件使用 Json 配置。
如果要将 a.txt 中的多行键值对拆分出来,可以使用 --from-env-file
。
当然,这个文件有一定的规则:
- 以 # 开头的行会被忽略;可以使用空行分隔,空行也会被忽略;
- 具有意义的行必须是
{键}={值}
的形式; - 引号不会被特殊处理,即不会被转义或不需要你提前转义。
关于上面这三点,创建 a.txt 示例文件:
enemies=aliens
lives=3
allowed="true"
导入命令格式:
kubectl create configmap my-config3 --from-env-file=a.txt
生成结果:
... ...
data:
allowed: '"true"'
enemies: aliens
lives: "3"
... ...
[Info] 提示
命令中只能出现一个
--from-env-file
,多个--from-env-file
同时使用,只有最后一个有效。
Secret
Secret 卷用来给 Pod 传递敏感信息,例如密码、密钥等。Secret卷实际上不是用于存储的,Secret 中存储的信息,会以环境变量、文件等的形式显示在 Pod 中。在 4.3 章的 Ingress 中,就讲解过使用 Secret 为 Ingress 增加 TLS 加密访问(HTTPS)。
Secret 的信息存储在 etcd 中,但是 Secret 一般情况下也不是加密存储的,关于如何加密 Secret 后面的章节会介绍到。
说明: 使用前你必须在 Kubernetes API 中创建 Secret。
Secret 的类型很多,这里将官方文档中列举的 secret 类型复制一份:
内置类型 | 用法 |
---|---|
Opaque |
用户定义的任意数据 |
kubernetes.io/service-account-token |
服务账号令牌 |
kubernetes.io/dockercfg |
~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson |
~/.docker/config.json 文件的序列化形式 |
kubernetes.io/basic-auth |
用于基本身份认证的凭据 |
kubernetes.io/ssh-auth |
用于 SSH 身份认证的凭据 |
kubernetes.io/tls |
用于 TLS 客户端或者服务器端的数据 |
bootstrap.kubernetes.io/token |
启动引导令牌数据 |
这里只讲解一部分常用的 secret 类型,如需了解更多详细知识,请参考官方文档:https://kubernetes.io/zh/docs/concepts/configuration/secret/
使用 kubectl
命令创建 Secret 时,命令格式如下:
kubectl create secret {类型} {secret名称}
其中,普通类型/Qpaque 类型的类型名称是 generic
,而不是 qpaque
。
使用 kubectl creatte secret generic
命令创建 secret 时,导入键值对的格式跟 ConfigMap 一致,这里就不再多说了,下面介绍一些其他常用的 Secret 类型。
TLS
在 4.3 章的 Ingrss 中,已经聊到过,这里就不再细谈。
通过证书创建 Secret 的命令如下所示:
kubectl create secret tls tls-secret --cert=1_k1.whuanle.cn_bundle.crt --key=2_k1.whuanle.cn.key
使用 YAML 表示:
apiVersion: v1
data:
tls.crt: ...
tls.key: ...
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
Nginx 配置 Https 证书,使用的便是 crt、key 文件,其它类型的证书请读者自行查阅文档。
基本身份认证 Secret
其类型为 kubernetes.io/basic-auth
,它是用来存储账号密码的,spec.data
中必须包含 username 和 password 两个字段,其 YAML 文件示例如下所示:
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin
password: t0p-Secret
如果我们查看数据:
root@master:~# kubectl get secret secret-basic-auth -o yaml
apiVersion: v1
data:
password: dDBwLVNlY3JldA==
username: YWRtaW4=
kind: Secret
... ...
username 和 password 等会被使用 base64 编码,但是并不是加密屏蔽,这些信息可以被直接用 base64 还原。
SSH 身份认证 Secret
其类型是 kubernetes.io/ssh-auth
,用来存储一段 ssh 密钥。
其 YAML 示例如下:
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# 此例中的实际数据被截断
ssh-privatekey: |
MIIEpQIBAAKCAQEAulqb/Y ...
使用 Secret
前面已经介绍过 Ingress 使用 Secret,这里就不再复述。
在 Pod 中使用 Secret 有环境变量和文件两种形式,将 Secret 挂载到 Pod 的目录下,
apiVersion: v1
kind: Pod
metadata:
name: secret1
spec:
containers:
- name: secret1
image: nginx
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: secret-basic-auth
这里使用之前创建的基于身份认证的 Secret,有 username、password 两个字段。
创建 Pod,然后查看映射到 Pod 的文件:
root@master:~# kubectl exec secret1 -- ls /etc/foo
password
username
root@master:~# kubectl exec secret1 -- cat /etc/foo/username
adminroot
@master:~# kubectl exec secret1 -- cat /etc/foo/password
t0p-Secret
可以看到,Secret 中每一个 字段/Key,会生成一个文件名,Value 是文件内容。
如果以环境变量的方式使用 Secret,其 YAML 跟 ConfigMap 类似,文件示例如下:
apiVersion: v1
kind: Pod
metadata:
name: mysecret2
spec:
containers:
- name: mysecret
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: secret-basic-auth
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: secret-basic-auth
key: password
restartPolicy: Never
会将 secret-basic-auth 中的 username 和 password 两个字段映射到 Pod 的
SECRET_USERNAME
、SECRET_PASSWORD
两个环境变量中。
查看 Pod 中的环境变量:
root@master:~# kubectl exec mysecret2 -- env
SECRET_USERNAME=admin
SECRET_PASSWORD=t0p-Secret
同时使用 ConfigMap、Secret
在集群中有 db-config 和 db-secret 两个名为 ConfigMap 和 Secret 的对象,现在需要创建一个名为 mydb 的 Pod,并且使用 mysql:5.7
这个镜像,要求把 db-config 和 db-secret 中的所有键值对以环境变量的形式映射到容器中。
其 YAML 示例如下:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mydb
name: mydb
spec:
containers:
- image: mysql:5.7
name: mydb
envFrom:
- configMapRef:
name: db-config
- secretRef:
name: db-secret
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}