从数据安全的角度来看,应用程序的配置信息可以分为两类:明文配置和机密配置。明文配置是指那些不需要保密的配置,可以随意查询和修改,例如服务端口、运行参数、文件路径等。而机密配置则涉及敏感信息,需要保密,不能随意查看,包括密码、密钥、证书等。
这两类配置信息本质上都是字符串,但由于安全性的要求,在存储和使用方面存在一些差异。因此,Kubernetes定义了两个API对象来分别处理这两类配置信息,即ConfigMap和Secret。
ConfigMap用于保存明文配置。它可以存储任意类型的数据,包括字符串、整数、浮点数、布尔值等。ConfigMap提供了一种将配置数据与应用程序解耦的方式,使得配置可以独立于镜像进行管理和修改。我们可以通过创建ConfigMap对象,并在应用程序的部署清单中引用该对象,将配置数据注入到容器中。应用程序可以通过环境变量或者卷挂载的方式访问ConfigMap中的配置数据,实现动态配置的能力。
而Secret则用于保存机密配置。它与ConfigMap类似,可以存储各种类型的数据,但它会对敏感信息进行加密,以保证数据的安全性。Secret对象可以存储密码、密钥、证书等机密数据,并且可以通过同样的方式将其注入到容器中。应用程序可以通过环境变量或卷挂载的方式访问Secret中的机密配置,确保敏感信息在应用程序中的安全使用。
通过将明文配置存储在ConfigMap中,将机密配置存储在Secret中,Kubernetes提供了一种灵活而安全的方式来管理应用程序的配置信息。这种方式使得配置数据可以独立于镜像进行修改和管理,同时保证了敏感信息的安全性,为应用程序的部署和运维提供了便利和保障。
创建 ConfigMap
定义一个ConfigMap对象的yaml文件:
cat << EOF > cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: info
data:
count: '10'
debug: 'on'
path: '/etc/systemd'
greeting: |
say hello to kubernetes.
EOF
使用 kubectl apply 把这个 YAML 交给 Kubernetes,让它创建 ConfigMap对象:
kubectl apply -f cm.yaml
创建Secret
cat << EOF > se.yaml
apiVersion: v1
kind: Secret
metadata:
name: user
data:
name: cm9vdA== # root
pwd: MTIzNDU2 # 123456
EOF
使用 kubectl apply 把这个 YAML 交给 Kubernetes,让它创建 Secret对象:
kubectl apply -f se.yaml
以环境变量的方式使用 ConfigMap/Secret
cat << EOF > env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- image: busybox
name: busy
imagePullPolicy: IfNotPresent
command:
- /bin/sleep
- '300'
env:
- name: COUNT
valueFrom:
configMapKeyRef:
name: info
key: count
- name: GREETING
valueFrom:
configMapKeyRef:
name: info
key: greeting
- name: USERNAME
valueFrom:
secretKeyRef:
name: user
key: name
- name: PASSWORD
valueFrom:
secretKeyRef:
name: user
key: pwd
EOF
这个 Pod 的名字是“env-pod”,镜像是“busybox”,执行命令 sleep 睡眠 300 秒,我们可以 在这段时间里使用命令 kubectl exec 进入 Pod 观察环境变量。
你需要重点关注的是它的“env”字段,里面定义了 4 个环境变量,COUNT、GREETING、 USERNAME、PASSWORD。 对于明文配置数据, COUNT、GREETING 引用的是 ConfigMap 对象,所以使用字段“configMapKeyRef”,里面的“name”是 ConfigMap 对象的名字,也就是之前我们创建 的“info”,而“key”字段分别是“info”对象里的 count 和 greeting。 同样的对于机密配置数据, USERNAME、PASSWORD 引用的是 Secret 对象,要使用字 段“secretKeyRef”,再用“name”指定 Secret 对象的名字 user,用“key”字段应用它里面的 name 和 pwd 。
用 kubectl apply 创建 Pod,再用 kubectlexec 进入 Pod,验证环境变量是否生效:
kubectl apply -f env-pod.yml
kubectl exec -it env-pod -- sh
echo $COUNT
echo $GREETING
echo $USERNAME $PASSWORD
以 Volume 的方式使用 ConfigMap/Secret
cat << EOF > vol-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: vol-pod
spec:
volumes:
- name: cm-vol
configMap:
name: info
- name: sec-vol
secret:
secretName: user
containers:
- volumeMounts:
- mountPath: /tmp/cm-items
name: cm-vol
- mountPath: /tmp/sec-items
name: sec-vol
image: busybox
name: busy
imagePullPolicy: IfNotPresent
command: ["/bin/sleep", "300"]
EOF
ConfigMap 和 Secret 都变成了目录的形式,而它们里面的 Key-Value 变成了一 个个的文件,而文件名就是 Key。 因为这种形式上的差异,以 Volume 的方式来使用 ConfigMap/Secret,就和环境变量不太一 样。环境变量用法简单,更适合存放简短的字符串,而 Volume 更适合存放大数据量的配置文 件,在 Pod 里加载成文件后让应用直接读取使用。
创建之后,我们还是用 kubectl exec 进入 Pod,看看配置信息被加载成了什么形式:
kubectl apply -f vol-pod.yml
kubectl get pod
kubectl exec -it vol-pod -- sh
ls /tmp/cm-items
ls /tmp/sec-items
cat /tmp/sec-items/pwd