一、简介
ConfigMap对像是一系列配置的集合,k8s会将这一集合注入到对应的Pod对像中,并为容器成功启动使用。注入的方式一般有两种,一种是挂载存储卷,一种是传递变量。ConfigMap被引用之前必须存在,属于名称空间级别,不能跨名称空间使用,内容明文显示。ConfigMap内容修改后,对应的pod必须重启或者重新加载配置。
Secret类似于ConfigMap,是用Base64加密,密文显示,一般存放敏感数据。一般有两种创建方式,一种是使用kubectl create创建,一种是用Secret配置文件。
使用场景
我们经常都需要为我们的应用程序配置一些特殊的数据,比如密钥、Token 、数据库连接地址或者其他私密的信息。你的应用可能会使用一些特定的配置文件进行配置,比如settings.py文件,或者我们可以在应用的业务逻辑中读取环境变量或者某些标志来处理配置信息。
我们要做到这个,有好多种方案,比如:
1.我们可以直接在打包镜像的时候写在应用配置文件里面,但是这种方式的坏处显而易见而且非常明显。
2.我们可以在配置文件里面通过 env 环境变量传入,但是这样的话我们要修改 env 就必须去修改 yaml 文件,而且需要重启所有的 container 才行。
3.我们可以在应用启动的时候去数据库或者某个特定的地方拿,没问题!但是第一,实现起来麻烦;第二,如果配置的地方变了怎么办?
当然还有别的方案,但是各种方案都有各自的问题。
而且,还有一个问题就是,如果说我的一个配置,是要多个应用一起使用的,以上除了第三种方案,都没办法进行配置的共享,就是说我如果要改配置的话,那得一个一个手动改。假如我们有 100 个应用,就得改 100 份配置,以此类推……
kubernetes 对这个问题提供了一个很好的解决方案,就是用 ConfigMap 和 Secret。
二、ConfigMap创建及使用
1.查看命令帮助
[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.en #不知道,没用过
2.ConfigMap主要有以下几种方式创建
通过literal方式创建ConfigMap
[root@k8s-master-155-221 ~]# mkdir manifests [root@k8s-master-155-221 ~]# cd manifests/ [root@k8s-master-155-221 ~]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.qiangungun.com #命令行给定 nginx_port为键 80为值 configmap/nginx-config created [root@k8s-master-155-221 ~]# kubectl describe cm nginx-config Name: nginx-config Namespace: default Labels: <none> Annotations: <none> Data ==== sever_name: #键 ---- myapp.qiangungun.com #值 nginx_port: #键 ---- 80 #值 Events: <none> [root@k8s-master-155-221 ~]# kubectl get cm nginx-config -o yaml apiVersion: v1 data: nginx_port: "8088" #键:值 server_name: myapp.qiangungun.com #键:值对 kind: ConfigMap metadata: ......
通过file的方式创建
[root@k8s-master-155-221 manifests]# mkdir configmap [root@k8s-master-155-221 manifests]# cd configmap/ [root@k8s-master-155-221 configmap]# vim www.conf server{ server_name myapp.magedu.com; listen 80; root /data/web/html; } [root@k8s-master-155-221 configmap]# kubectl create configmap www --from-file=./www.conf #直接以文件名称为键,文件内容为值,也可以使用--from-file=key=/path/to/file自定义键 configmap/www created [root@k8s-master-155-221 configmap]# kubectl get configmaps www NAME DATA AGE www 1 23s [root@k8s-master-155-221 configmap]# kubectl get configmaps www -o yaml #或者使用describe命令查看 apiVersion: v1 data: www.conf: | server{ server_name myapp.magedu.com; listen 80; root /data/web/html; } kind: ConfigMap metadata: creationTimestamp: "2020-01-13T14:21:13Z" name: www namespace: default resourceVersion: "7809631" selfLink: /api/v1/namespaces/default/configmaps/www uid: f3dd1cd4-360f-11ea-87ad-525400512eca
通过YAML文件创建
[root@k8s-master-155-221 configmap]# vim my-configmap.yml apiVersion: v1 kind: ConfigMap metadata: name: customer1 data: key1: value1 key2: value2 [root@k8s-master-155-221 configmap]# kubectl apply -f my-configmap.yml configmap/customer1 created [root@k8s-master-155-221 configmap]# kubectl describe cm customer1 Name: customer1 Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","data":{"key1":"value1","key2":"value2"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"customer1","namespace"... Data ==== key1: ---- value1 key2: ---- value2 Events: <none>
3.使用ConfigMap主要有以下几种方式:
ENV注入:
[root@k8s-master-155-221 configmap]# vim pod-configmap.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-1 namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: httpd containerPort: 80 env: - name: NGINX_SERVER_PORT #pod中显示的变量名称 valueFrom: configMapKeyRef: key: nginx_port #引用的configmap中的键名称 name: nginx-config #引用的configmap的名称 optional: true #该选项是否是必须的(true表示必须存在,否则pod无法启动) - name: NGINX_SERVER_NAME valueFrom: configMapKeyRef: key: server_name name: nginx-config optional: true [root@k8s-master-155-221 configmap]# kubectl apply -f pod-configmap.yaml pod/pod-cm-1 created [root@k8s-master-155-221 configmap]# kubectl get pods |grep pod-cm-1 pod-cm-1 1/1 Running 0 3m11s [root@k8s-master-155-221 configmap]# kubectl get pods |grep pod-cm-1 pod-cm-1 1/1 Running 0 13s [root@k8s-master-155-221 configmap]# kubectl exec -it pod-cm-1 -- /bin/sh / # env|grep NGINX_SERVER_PORT NGINX_SERVER_PORT=80 / # env|grep NGINX_SERVER_NAME NGINX_SERVER_NAME=myapp.qiangungun.com / # env|grep NGINX_SERVER_PORT #稍等片刻,等下面的修改完成后操作,端口没有改变,即使用环境变量的方式注入配置只会在pod启动时有效 NGINX_SERVER_PORT=80
#另起一个会话,修改当前使用的ConfigMap
[root@k8s-master-155-221 ~]# kubectl edit configmap nginx-config # Please edit the object below. Lines beginning with a '#' will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # apiVersion: v1 data: nginx_port: "8080" #修改端口为8080 server_name: myapp.qiangungun.com kind: ConfigMap metadata: ...... [root@k8s-master-155-221 ~]# kubectl describe cm nginx-config Name: nginx-config Namespace: default Labels: <none> Annotations: <none> Data ==== nginx_port: ---- 8080 server_name: ---- myapp.qiangungun.com Events: <none>
VOLUME挂载
root@k8s-master-155-221 configmap]# kubectl delete pod pod-cm-1 pod "pod-cm-1" deleted [root@k8s-master-155-221 configmap]# cp pod-configmap.yaml pod-configmap-2.yaml [root@k8s-master-155-221 configmap]# vim pod-configmap-2.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-2 namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: httpd containerPort: 80 volumeMounts: - name: nginx-conf mountPath: /etc/nginx/config.d/ readOnly: true #是否允许pod去修改 volumes: - name: nginx-conf configMap: name: nginx-config [root@k8s-master-155-221 configmap]# kubectl apply -f pod-configmap-2.yaml pod/pod-cm-2 created [root@k8s-master-155-221 configmap]# kubectl exec -it pod-cm-2 -- /bin/sh / # ls /etc/nginx/config.d/nginx_port /etc/nginx/config.d/nginx_port / # cat /etc/nginx/config.d/nginx_port #注意,是8080,因为之前已经改过一次了 8080/ # / # cat /etc/nginx/config.d/server_name myapp.qiangungun.com/ # / # cat /etc/nginx/config.d/nginx_port #等下面的修改完成后操作,稍等30秒左右,端口发生改变,及以文件挂载的方式可以同步改变 8088/ #
#另起一个会话,修改当前使用的ConfigMap
[root@k8s-master-155-221 ~]# kubectl edit configmap nginx-config nginx_port: "8088" #修改端口由8080改为8088 / # cd /etc/nginx/config.d/ /etc/nginx/config.d # ls -l #挂载的方式实质是一种映射关系 total 0 lrwxrwxrwx 1 root root 17 Jan 13 15:23 nginx_port -> ..data/nginx_port lrwxrwxrwx 1 root root 18 Jan 13 15:23 server_name -> ..data/server_name
4.实际示例
[root@k8s-master-155-221 configmap]# vim pod-configmap-3.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-3 namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: httpd containerPort: 80 volumeMounts: - name: nginx-conf mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: nginx-conf configMap: name: www [root@k8s-master-155-221 configmap]# kubectl apply -f pod-configmap-3.yaml pod/pod-cm-3 created [root@k8s-master-155-221 configmap]# kubectl exec -it pod-cm-3 -- /bin/sh / # cd /etc/nginx/conf.d/ /etc/nginx/conf.d # ls www.conf #文件名称即www configmap中的键 /etc/nginx/conf.d # cat www.conf #文件内容为www.conf的值 server{ server_name myapp.magedu.com; listen 80; root /data/web/html; } /etc/nginx/conf.d # nginx -T #查看载入的配置 ...... # configuration file /etc/nginx/conf.d/www.conf: server{ server_name myapp.magedu.com; listen 80; root /data/web/html; } /etc/nginx/conf.d # mkdir -p /data/web/html /etc/nginx/conf.d # echo "<h1>Nginx Server configured by CM</h1>" > /data/web/html/index.html
在集群任意节点上
[root@k8s-master-155-221 configmap]# kubectl get pods -o wide|grep pod-cm-3 pod-cm-3 1/1 Running 0 5m13s 172.17.248.4 172.16.155.224 <none> <none> [root@k8s-master-155-221 configmap]# echo "172.17.248.4 myapp.magedu.com" >> /etc/hosts [root@k8s-master-155-221 configmap]# curl myapp.magedu.com Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> [root@k8s-master-155-221 configmap]# kubectl edit cm www apiVersion: v1 data: www.conf: | server{ server_name myapp.magedu.com; listen 8080; root /data/web/html; } kind: ConfigMap metadata: creationTimestamp: "2020-01-13T14:21:13Z" name: www namespace: default resourceVersion: "7809631" selfLink: /api/v1/namespaces/default/configmaps/www uid: f3dd1cd4-360f-11ea-87ad-525400512eca
pod中查看
/etc/nginx/conf.d # cat www.conf #等上面的修改完成后操作,稍等30秒左右,端口发生改变 server_name myapp.magedu.com; listen 8080; root /data/web/html; } /etc/nginx/conf.d # netstat -tnl #配置虽然改变,但是服务监听端口不会发生改变,需要通过某种方式重载服务 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
三、Secret创建及使用
通过上面的部分,我们可以看到 ConfigMap 是用来做一些配置信息的,那么如果我们有一些机密信息比如说密钥、密码之类的信息,应该存在哪里呢?看到这个名字大家应该就明白了吧,kubernetes 提供了 Secret 来存储相关的信息。
Secret命令帮助(secret创建和使用与ConfigMap大同小异,注意区别在于内容被base64加密了)
[root@k8s-master-155-221 manifests]# kubectl create secret --help Create a secret using specified subcommand. Available Commands: #secret主要有以下三种类型 docker-registry 创建一个给 Docker registry 使用的 secret #docker-registry私有仓库的证书,pod中pod.spec.imagePullSecrets字段使用 generic 从本地 file, directory 或者 literal value #通用的secret tls 创建一个 TLS secret #保存私钥和证书
1.创建secret
1.通用类型 [root@k8s-master-155-221 manifests]# kubectl create secret generic mysql-root-passwd --from-literal=passwd=MyP@ss123 secret/mysql-root-passwd created [root@k8s-master-155-221 manifests]# kubectl describe secrets mysql-root-passwd Name: mysql-root-passwd Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== passwd: 9 bytes #只能看到9个字节 但是看不到内容 [root@k8s-master-155-221 manifests]# kubectl get secrets mysql-root-passwd -o yaml apiVersion: v1 data: passwd: TXlQQHNzMTIz #实际是base64加密 kind: Secret metadata: creationTimestamp: "2020-01-14T01:47:51Z" name: mysql-root-passwd namespace: default resourceVersion: "7896989" selfLink: /api/v1/namespaces/default/secrets/mysql-root-passwd uid: dfb541fa-366f-11ea-87ad-525400512eca type: Opaque [root@k8s-master-155-221 manifests]# echo "TXlQQHNzMTIz"|base64 -d #实际上可以被解码的 MyP@ss123 2.TLS类型 [root@k8s-master-155-221 manifests]# kubectl create secret tls ${secret_name} --key nginx.key --cert nginx.crt 3.镜像仓库类型 [root@k8s-master-155-221 manifests]# kubectl create secret generic ${secret_name} --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
2.简单使用
[root@k8s-master-155-221 configmap]# vim pod-secret-1.yaml apiVersion: v1 kind: Pod metadata: name: pod-secret-1 namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: httpd containerPort: 80 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: key: passwd name: mysql-root-passwd optional: true [root@k8s-master-155-221 configmap]# kubectl apply -f pod-secret-1.yaml pod/pod-secret-1 created [root@k8s-master-155-221 configmap]# kubectl exec -it pod-secret-1 -- /bin/sh / # env|grep MYSQL MYSQL_ROOT_PASSWORD=MyP@ss123 #实际是解密后注入进来的,所以不建议使用环境变量的方式注入密码
其他方式与configmap雷同,不在赘述
其实目前 Secret 的实现,就是 ConfigMap 把 value 用 base64 encode 了一下.所以,其实不存在任何安全性,只要 decode 一下就能出现原来结果,相当于明文存储.
参考文档:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/
https://kubernetes.io/docs/concepts/configuration/secret/