ConfigMap、Secret
为什么有这两个东西:
我们在kubernetes上部署应用的时候,经常会需要传一些配置给我们的应用,比如数据库地址啊,用户名密码啊之类的。我们要做到这个,有好多种方案,比如:
- 我们可以直接在打包镜像的时候写在应用配置文件里面,但是这种方式的坏处显而易见而且非常明显。
- 我们可以在配置文件里面通过env环境变量传入,但是这样的话我们要修改env就必须去修改yaml文件,而且需要重启所有的container才行。
- 我们可以在应用启动的时候去数据库或者某个特定的地方拿,没问题!但是第一,实现起来麻烦;第二,如果配置的地方变了怎么办?
当然还有别的方案,但是各种方案都有各自的问题。
而且,还有一个问题就是,如果说我的一个配置,是要多个应用一起使用的,以上除了第三种方案,都没办法进行配置的共享,就是说我如果要改配置的话,那得一个一个手动改。假如我们有100个应用,就得改100份配置,以此类推……
kubernetes对这个问题提供了一个很好的解决方案,就是用ConfigMap
和Secret
应用场景:
镜像往往是一个应用的基础,还有很多需要自定义的参数或配置,例如资源的消耗、日志的位置级别等等,这些配置可能会有很多,因此不能放入镜像中,Kubernetes中提供了Configmap来实现向容器中提供配置文件或环境变量来实现不同配置,从而实现了镜像配置与镜像本身解耦,使容器应用做到不依赖于环境配置
Secret资源对象:
可以保存轻量的敏感信息,比如数据库的用户名和密码或者认证秘钥等。它保存的数据是以秘文的方式存放的
configMap资源对象:
和Secret一样,拥有大多数共同的特性,但是区别是,configMap保存的是一些不太重要的信息,它保存的数据是以明文的方式存放的。
当我们创建上述两种资源对象时,其实就是将这两种资源对象存储的信息写入了k8s群集中的etcd数据中心
Secret与ConfigMap的异同:
相同之处:
都是用来保存轻量级信息的,可以供其他资源对象(Deployment、RC、RS和Pod)进行挂载使用
这两种资源对象的创建方法(4种)及引用方法(2种)都是一样的,都是以键值对的方式进行存储的
不同之处:
Secret是用来保存敏感信息的,而configMap是用来保存一些不太重要的数据的,具体表现在当我们执行“kubectl describe ….”命令时,Secret这种类型的资源对象时查看不到其具体的信息的,而configMap是可以查看到其保存的具体内容的
Secret:
Secret:用于保存一些敏感信息,比如数据库的用户名密码或者密钥。这些数据是比较少量的,将这些信息放在 secret
中比放在 pod
的定义或者 docker 镜像中来说更加安全和灵活
用户可以创建自己的secret,系统也会有自己的secret
内置 secret
[root@master ~]# kubectl get secrets -n kube-system
Secret有三种类型:
Opaque
:base64编码格式的Secret,用来存储密码、密钥等;但数据也通过base64 –decode解码得到原始数据,所有加密性很弱
kubernetes.io/dockerconfigjson
:用来存储私有docker registry的认证信息
kubernetes.io/service-account-token
: 用于被serviceaccount引用,serviceaccout创建时Kubernetes会默认创建对应的secret。Pod如果使用了serviceaccount,对应的secret会自动挂载到Pod目录/run/secrets/ kubernetes.io/serviceaccount中
举例:保存数据库的用户名和密码
用户名:root
密码:123.com
有四种方法:
1、通过- -from-literal(文字的):
也就是说需要保存什么,直接写出来就行
注意:每一个–from-literal只能保存一条信息
[root@master ~]# kubectl create secret generic mysecret1 --from-literal=username=root --from-literal=password=123.com
generic:通用的、一般的加密方式
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-x9ptl kubernetes.io/service-account-token 3 42d
mysecret1 Opaque(不透明的) 2 2m13s
Opaque(不透明的):也就是说你看不到
[root@master ~]# kubectl describe secrets
Type: Opaque
Data
====
password: 7 bytes
username: 4 bytes
//这里看不到真正的值是什么
2、- -from-file(文件):
同样,每一个只能保存一条信息
[root@master ~]# echo root > username
[root@master ~]# echo 123.com > password
[root@master ~]# kubectl create secret generic mysecret2 --from-file=username --from-file=password
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-x9ptl kubernetes.io/service-account-token 3 42d
mysecret1 Opaque 2 28m
mysecret2 Opaque 2 28s
既然是通过文件创建的,那么把文件删除,这个secret是否还在
[root@master ~]# rm -rf username password
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-x9ptl kubernetes.io/service-account-token 3 42d
mysecret1 Opaque 2 29m
mysecret2 Opaque 2 92s
//它确实还会存在
3、通过- -from-env-file:
这种方法可以把用户名和密码写在一个文件里面,这样就比前两种方便
[root@master ~]# vim env.txt
username=root
password=123.com
[root@master ~]# kubectl create secret generic mysecret3 --from-env-file=env.txt
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-x9ptl kubernetes.io/service-account-token 3 42d
mysecret1 Opaque 2 34m
mysecret2 Opaque 2 6m27s
mysecret3 Opaque 2 16s
[root@master ~]# kubectl describe secrets
Data
====
password: 7 bytes
username: 4 bytes
4、通过yaml配置文件
先看一下yaml怎么写
[root@master ~]# kubectl get secrets mysecret1 -o yaml
apiVersion: v1
data:
password: MTIzLmNvbQ==
username: cm9vdA==
kind: Secret
metadata:
creationTimestamp: "2020-02-14T02:01:34Z"
name: mysecret1
namespace: default
resourceVersion: "13766"
selfLink: /api/v1/namespaces/default/secrets/mysecret1
uid: ffce8c7a-2dfc-4958-9e3b-0fcb50d00cca
type: Opaque
可以看到数据是被加密后写入yaml文件里的,所以我们写的时候不能直接写数据,而是要加密一下
把保存的数据加密:
通过base64方式:
[root@master ~]# echo root | base64
cm9vdAo=
[root@master ~]# echo 123.com | base64
MTIzLmNvbQo=
创建secret资源对象:
[root@master ~]# vim secret4.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret4
data:
username: cm9vdAo=
password: MTIzLmNvbQo=
[root@master ~]# kubectl apply -f secret4.yaml
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-x9ptl kubernetes.io/service-account-token 3 42d
mysecret1 Opaque 2 42m
mysecret2 Opaque 2 14m
mysecret3 Opaque 2 8m
mysecret4 Opaque 2 18s
这种方法虽然说我们看不到真正的数据是什么,但是这种方式也是不安全的,每一次编码后的数据是一样的,是由规律的,同样它是可以被解码的
解码:
[root@master ~]# echo -n cm9vdAo | base64 --decode
root
如何来使用Secret资源:
Secret 可以作为数据卷被挂载,或作为环境变量 暴露出来以供 pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 pod 内
两种方法:
1、以Volume挂载的方式
//创建Pod来引用secret
[root@master ~]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: busybox
args:
- /bin/sh
- -c
- sleep 300000
volumeMounts:
- name: secret-test
mountPath: "/etc/secret-test"
readOnly: true //是否只读,也就是说对于/etc/secret-test只有只读的权限,不能修改
volumes:
- name: secret-test
secret:
secretName: mysecret1
[root@master ~]# kubectl apply -f pod.yaml
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 2m4s
进入容器查看是否有我们保存的数据
[root@master ~]# kubectl exec -it mypod /bin/sh
/ # cd /etc/secret-test
/etc/secret-test # cat username
root
/etc/secret-test # cat password
123.com
/etc/secret-test # echo admin > username
/bin/sh: can't create username: Read-only file system
//这个文件也是不能修改的,因为是只读文件
还可以自定义存放数据的文件名:
//在volumes字段下追加items字段:
volumes:
- name: secret-test
secret:
secretName: mysecret1
items:
- key: username
path: my-group/my-username
- key: password
path: my-group/my-password
[root@master ~]# kubectl apply -f pod.yaml
pod/mypod created
[root@master ~]# kubectl exec -it mypod /bin/sh
/ # cd /etc/secret-test/
/etc/secret-test # ls
my-group
/etc/secret-test # cd my-group/
/etc/secret-test/..2020_02_17_01_40_09.035305611/my-group # ls
my-username my-password
/etc/secret-test/..2020_02_17_01_40_09.035305611/my-group # cat my-username
root
/etc/secret-test/..2020_02_17_01_40_09.035305611/my-group # cat my-password
123.com
2、以环境变量的方式
[root@master ~]# cp pod.yaml pod-env.yaml
[root@master ~]# vim pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod2
spec:
containers:
- name: mypod2
image: busybox
args:
- /bin/sh
- -c
- sleep 300000
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef: //翻译过来就是机密键引用,提取mysecret2里面的数据到SECRET_USERNAME
name: mysecret2
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef: //与上面同理
name: mysecret2
key: password
[root@master ~]# kubectl apply -f pod-env.yaml
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 18m
mypod2 1/1 Running 0 79s
同样,进入pod查看
[root@master ~]# kubectl exec -it mypod2 /bin/sh
/ # echo $SECRET_USERNAME
root
/ # echo $SECRET_PASSWORD
123.com
如果现在将secret资源内保存的数据进行更新,使用此数据的应用内,数据是否也会更新
更新mysecret1的数据:把password—–>123.com—->admin
[root@master ~]# echo admin | base64
YWRtaW4K
[root@master ~]# kubectl get secrets zhbsecret2 -o yaml
//可以通过edit命令直接修改:
[root@master ~]# kubectl edit secrets zhbsecret2
data:
username: cm9vdAo=
password: YWRtaW4K //更改
[root@master ~]# kubectl exec -it mypod /bin/sh
/ # cd /etc/secret-test/my-group/
/etc/secret-test/..2020_02_17_01_57_25.223684048/my-group # cat my-password
admin
//可以看到已经跟着改变了
注意:
这里引用数据是以volumes挂载使用数据的方式,才会实时更新
那么,以环境变量的方式引用的数据,是否会实时更新?
[root@master ~]# kubectl edit secrets mysecret4
data:
username: cm9vdAo=
password: YWRtaW4K
[root@master ~]# kubectl exec -it mypod2 /bin/sh
/ # echo $SECRET_PASSWORD
123.com
//没有变化
总结:
如果引用secret数据的应用,要求会随着secret资源对象内保存的数据的更新而实时更新,那么应该使用volumes挂载的方式引用资源。因为用环境变量的方式引用不会实时更新数据
ConfigMap:
和Secret资源类似,不同之处在于,secret资源保存的是敏感信息,而configmap保存的方式是以明文的方式存放的数据
什么是ConfigMap:
ConfigMap对像是一系列配置的集合,k8s会将这一集合注入到对应的Pod对像中,并为容器成功启动使用。注入的方式一般有两种,一种是挂载存储卷,一种是传递变量。ConfigMap被引用之前必须存在,属于名称空间级别,不能跨名称空间使用,内容明文显示。ConfigMap内容修改后,对应的pod必须重启或者重新加载配置
创建ConfigMap的4种方式:
username:adam
age:18
和secretc创建的方式一模一样
1、通过- -from-literal(文字的):
[root@master ~]# kubectl create configmap myconfigmap1 --from-literal=username=adam --from-literal=age=18
configmap/myconfigmap1 created
[root@master ~]# kubectl get configmaps
NAME DATA AGE
myconfigmap1 2 32s
[root@master ~]# kubectl describe configmaps
Data
====
age:
----
18
username:
----
adam
2、- -from-file(文件):
[root@master ~]# touch adam > username
[root@master ~]# touch 18 > age
[root@master ~]# kubectl create configmap myconfigmap2 --from-file=username --from-file=age
configmap/myconfigmap2 created
[root@master ~]# kubectl get configmaps
NAME DATA AGE
myconfigmap1 2 4m23s
myconfigmap2 2 63s
3、通过- -from-env-file:
[root@master ~]# vim env.txt
username=adam
age=18
[root@master ~]# kubectl create configmap myconfigmap3 --from-env-file=env.txt
configmap/myconfigmap3 created
[root@master ~]# kubectl get configmaps
NAME DATA AGE
myconfigmap1 2 16m
myconfigmap2 2 5m18s
myconfigmap3 2 8m56s
4、通过yaml配置文件
[root@master ~]# vim configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfigmap4
data:
username: adam
age: "18"
[root@master ~]# kubectl apply -f configmap.yaml
configmap/myconfigmap4 created
[root@master ~]# kubectl get configmaps
NAME DATA AGE
myconfigmap1 2 16m
myconfigmap2 2 5m18s
myconfigmap3 2 8m56s
myconfigmap4 2 4m8s
使用configmap:
和secret一样,有两种方法
第一种方法是:
以volumes挂载的方式引用资源
[root@master ~]# vim v-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: pod1
image: busybox
args:
- bin/sh
- -c
- sleep 300000
volumeMounts:
- name: cmp-test
mountPath: "/etc/cmp-test"
readOnly: true
volumes:
- name: cmp-test
configMap:
name: myconfigmap1
[root@master ~]# kubectl apply -f v-pod.yaml
pod/pod1 created
第二种方式:
以环境变量的方式引用资源
[root@master ~]# vim e-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
containers:
- name: pod2
image: busybox
args:
- bin/sh
- -c
- sleep 300000
env:
- name: CONFIGMAP_NAME
valueFrom:
configMapKeyRef:
name: myconfigmap2
key: username
- name: CONFIGMAP_AGE
valueFrom:
configMapKeyRef:
name: myconfigmap2
key: age
[root@master ~]# kubectl apply -f e-pod.yaml
pod/pod2 created
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 5m34s
pod2 1/1 Running 0 48s
如果现在将confgimap资源内保存的数据进行更新,使用此数据的应用内,数据是否也会更新
[root@master ~]# kubectl edit configmaps myconfigmap1
data:
age: "18"
username: root
[root@master ~]# kubectl exec -it pod1 /bin/sh
/ # cd /etc/cmp-test/
/etc/cmp-test # cat username
root
//这里会跟着更新,如果操作过快,它会反应不过来,你就话看不到改变,稍微等一下就行了
那么,以环境变量的方式引用的数据,是否会实时更新?
[root@master ~]# kubectl exec -it pod2 /bin/sh
/ # echo $CONFIGMAP_AGE
18
/ # echo $CONFIGMAP_NAME
adam
/ # exit
[root@master ~]# kubectl edit configmaps myconfigmap2
data:
age: |
18
username: |
root
[root@master ~]# kubectl describe configmaps myconfigmap2
Data
====
age:
----
18
username:
----
root
[root@master ~]# kubectl exec -it pod2 /bin/sh
/ # echo $CONFIGMAP_NAME
adam
//和secret一样,是不会更新的
小结
Secret:
用于存放一些敏感信息,比如数据库的用户名密码、密钥等,以密文的方式保存
创建Secret资源对象的四种方式:
- –from-literal(文字的):需要保存什么内容直接写出来,一次只能保存一条
- –from-file(文件):把需要保存的内容写到文件里面,通过–from-file指定这个文件。一次只能保存一条
- –from-env-file(环境变量):把想要保存的内容都写入一个文件里面,通过–from-env-file指定
- 通过yaml配置文件:在data字段写入要保存的内容,注意是以密文的格式写入(使用base64的方式加密就行)
引用Secret资源的两种方法:
- Volumes挂载的方式:
- 环境变量的方式:
ConfigMap:
和Secret一样,拥有大多数共同的特性,但是区别是,configMap保存的是一些不太重要的信息,它保存的数据是以明文的方式存放的,使用describe来查看是,能看到真正的信息
创建ConfigMap资源对象的四种方式和引用ConfigMap的两种方式一摸一样
–from-literal(文字的)
–from-file(文件)
–from-env-file(环境变量)
通过yaml配置文件
Volumes挂载的方式:
环境变量的方式:
如果引用secret、CongigMap数据的应用,要求会随着secret、ConfigMap资源对象内保存的数据的更新而实时更新,那么应该使用volumes挂载的方式引用资源。因为用环境变量的方式引用不会实时更新数据