前言

在K8s中有Secret和configMap这两种资源对象,这也是实现数据持久化的一种方式,与之前写过的PV或挂载目录等这些数据持久化的方式有些许不一样。

Secret资源对象:可以保存轻量的敏感信息,比如数据库的用户名和密码或者认证秘钥等。它保存的数据是以秘文的方式存放的

configMap资源对象:和Secret一样,拥有大多数共同的特性,但是区别是,configMap保存的是一些不太重要的信息,它保存的数据是以明文的方式存放的。

当我们创建上述两种资源对象时,其实就是将这两种资源对象存储的信息写入了k8s群集中的etcd数据中心。

一、secret和configMap的异同点

相同点:

都是用来保存轻量级信息的,可以供其他资源对象(Deployment、RC、RS和POd)进行挂载使用。

这两种资源对象的创建方法(4种)及引用方法(2种)都是一样的,都是以键值对的方式进行存储的。

不同点:

Secret是用来保存敏感信息的,而configMap是用来保存一些不太重要的数据的,具体表现在当我们执行“kubectl describe ....”命令时,Secret这种类型的资源对象时查看不到其具体的信息的,而configMap是可以查看到其保存的具体内容的。

二、Secret资源对象的四种创建方式

创建方法1(通过--from-literal的方式)

假设要存储的数据是:
name:zhangsan
tel:15888888888

[root@master ~]# kubectl create secret generic secret
1 --from-literal=name=zhangsan --from-literal=tel=1588888888
[root@master ~]# kubectl get secrets secret1  #查看创建的secret1
NAME      TYPE     DATA   AGE
secret1   Opaque   2      89s
[root@master ~]# kubectl describe secrets secret1 
Name:         secret1
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
name:  8 bytes       #可以看到只能查看到其键的内容,而无法看到键对应的值
tel:   10 bytes

创建方法2(通过--from-file的方式)

这种方式比方法1还要麻烦一些,不建议使用。

#需要先将要存储的键值对写入到文件中,并且每个文件只能写入一个值
[root@master ~]# echo zhangsan > name
[root@master ~]# echo 15888888888 > tel
[root@master ~]# cat name tel
zhangsan
15888888888
[root@master ~]# kubectl create secret generic secret2 --from-file=name --from-file=tel 
#执行上述命令进行创建,然后使用方法1的命令自行查看即可

创建方法3(通过--from-env-file的方式)

这种方式可以在同一个文件中写入多个键值对,推荐使用。

[root@master ~]# cat > env.txt <<EOF  #将要存储的键值对写入文件中
> name=zhangsan
> tel=15888888888
> EOF
[root@master ~]# kubectl create secret generic secert3 --from-env-file=env.txt 
#执行上述命令即可以env.txt中的键值对存入k8s的数据中心
#自行查看是否创建即可

创建方法4(通过yaml配置文件的方式)

#可以将要存储的值加密
[root@master ~]# echo zhangsan | base64
emhhbmdzYW4K
[root@master ~]# echo 1588888888 | base64
MTU4ODg4ODg4OAo=
[root@master ~]# vim secret.yaml     #编写yaml文件
apiVersion: v1
kind: Secret
metadata:
  name: secret4
data:                           #下面的值是在命令行加密后的值
  name: emhhbmdzYW4K
  tel: MTU4ODg4ODg4OAo=
[root@master ~]# kubectl apply -f secret.yaml     #执行yaml文件
#可以使用下面的命令对加密字符进行解密
[root@master ~]# echo -n MTU4ODg4ODg4OAo= | base64 --decode 
1588888888

三、Secret的两种使用方式

既然secret的这种存储方式是无法通过命令行查看的,再一个就是,这种存储方式的意义是什么?通过下面的使用方式,应该就可以明白其使用场景了。

使用方法1(以volume挂载的方式使用secret)

[root@master ~]# vim secret-pod.yaml  #编写yaml文件,运行一个pod

apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: secret-pod
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000  #以上字段和使用secret无关
    volumeMounts:
    - name: test
      mountPath: /etc/test        #指定挂载到容器内的目录
      readOnly: true     #这里决定了,是以只读的方式挂载的
  volumes:
  - name: test
    secret:
      secretName: secret4         #这里指定secret的名字,也就是我们使用第四种方法创建的secret

[root@master ~]# kubectl apply -f secret-pod.yaml     #执行yaml文件
[root@master ~]# kubectl exec -it secret-pod /bin/sh   #进入创建的容器
/ # cat /etc/test/name /etc/test/tel     #查看挂载的目录下
zhangsan
1588888888
#可以发现自动给我们解密了

现在,我们可以验证一下,如果此时更改secret4的内容,那么容器内对应的挂载目录下的内容是否更改?

[root@master ~]# echo lisi | base64
bGlzaQo=
[root@master ~]# echo 1599999999 | base64
MTU5OTk5OTk5OQo=
[root@master ~]# vim secret.yaml      #修改其内容
apiVersion: v1
kind: Secret
metadata:
  name: secret4
data:
  name: bGlzaQo=
  tel: MTU5OTk5OTk5OQo=
[root@master ~]# kubectl apply -f secret.yaml     #重新执行yaml文件
[root@master ~]# kubectl exec -it secret-pod /bin/sh   #再次进入容器
/ # cat /etc/test/name /etc/test/tel     #可以看到容器内的数据也随之改变了
lisi
1599999999

使用方法2(以环境变量的方式使用secret)

[root@master ~]# vim secret-pod.yaml      #编写yaml文件
apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: secret-pod
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000
    env:          #设置环境变量,这里调用secert3存储的值
      - name: SECRET_NAME   #容器内的变量名
        valueFrom:
          secretKeyRef:
            name: secert3         #指定调用的是secert3
            key: name                   #调用的是secert3的name对应的值
      - name: SECRET_TEL          #这里的SECRET_TEL同上
        valueFrom:
          secretKeyRef:
            name: secert3
            key: tel
[root@master ~]# kubectl delete -f secret-pod.yaml  #删除之前的pod
[root@master ~]# kubectl apply -f secret-pod.yaml     #重新生成pod
#进入容器,输出对应的变量
[root@master ~]# kubectl exec -it secret-pod /bin/sh
/ # echo $SECRET_NAME
zhangsan
/ # echo $SECRET_TEL
15888888888

至此,以变量的形式引用secert存储的键值对就调用完成了,同样也可以去测试修改secert存储的值,看看pod容器中的变量是否会随之改变,答案是否定的,如果采用变量的方式调用secert存储的值,容器内的变量值并不会随着secert存储的值发生改变,除非重新生成pod。

四、configMap资源对象的四种创建方式

其实configMap和secert资源对象的创建方式完全一样,这里就写下“--from-literal”、“--from-env-file”和“yaml文件”这三种创建方式,至于“--from-file”的创建方式,参考secert的创建方式即可。

创建方法1(通过--from-literal的方式)

[root@master ~]# kubectl create configmap config1 --from-literal=name=lisi --from-literal=age=18
#存储名称为config1的键值对
[root@master ~]# kubectl describe configmaps config1   #查看创建的config1
Name:         config1
Namespace:    default
Labels:       <none>
Annotations:  <none>
#可以很明确的看到其中保存的数据,所以它用来存储一些不太重要的数据
Data
====
age:
----
18
name:
----
lisi
Events:  <none>

创建方法2(通过--from-env-file的方式)

[root@master ~]# cat > config.txt <<EOF   #将键值对写入文件中
> name=lisi
> age=18
> EOF
[root@master ~]# kubectl create configmap configmap2 --from-env-file=config.txt 
#执行命令

创建方法3(通过yaml配置文件的方式)

[root@master ~]# vim configmap3.yaml #编写yaml文件
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap3
data:
  name: lisi
  age: '18'       #如果值为数字,则必须要用单引号引起来
[root@master ~]# kubectl apply -f configmap3.yaml     #执行yaml文件

五、configMap数据的两种引用方式

应用方式和secert资源对象的方式类似,都是volume挂载或者以变量的方式引用,只是一些yaml文件中的一些关键字不一样。

引用方法1(通过volume挂载)

[root@master ~]# kubectl delete -f secret-pod.yaml    #删除之前创建的pod
[root@master ~]# vim secret-pod.yaml     #修改yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: secret-pod
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000   #这上面没有改变
    volumeMounts:
    - name: test
      mountPath: /mnt    #挂载到容器的mnt目录
      readOnly: true
  volumes:
  - name: test
    configMap:             #这里的关键字不一样
      name: configmap3         #挂载的是configmap3
[root@master ~]# kubectl apply -f secret-pod.yaml      #执行yaml文件
[root@master ~]# kubectl exec -it secret-pod /bin/sh  #进入容器
/ # cat /mnt/name /mnt/age    #查看挂载的内容
lisi18/ # 
(由于使用的容器有些特殊,所以输出格式上有些不太直观,但是数据是没错的)

同样,这种volume挂载的方式,pod容器内的数据会随着configmap3的数据改变而改变,它们共享的是同一个文件。

引用方法2(通过配置env环境变量)

[root@master ~]# kubectl delete -f secret-pod.yaml    #删除之前创建的pod
[root@master ~]# vim secret-pod.yaml         #修改yaml文件
apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: secret-pod
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000
    env:           #定义环境变量,这里使用的是创建的configmap
        2的键值对内容
      - name: USER_NAME
        valueFrom:
          configMapKeyRef:
            name: configmap2
            key: name      #调用configmap2中的name的值
      - name: USER_AGE
        valueFrom:
          configMapKeyRef:
            name: configmap2
            key: age      #调用configmap2中的age的值
[root@master ~]# kubectl apply -f secret-pod.yaml 
[root@master ~]# kubectl exec -it secret-pod /bin/sh    #进入容器输出环境变量
/ # echo $USER_NAME
lisi
/ # echo $USER_AGE
18

这里测试一下,如果修改configmap2的键值对,容器内的环境变量是否会发生改变?

[root@master ~]# vim config.txt    #修改configmap2的值
name=wangwu
age=28
[root@master ~]# kubectl delete configmaps     #需要先删除
[root@master ~]# kubectl create configmap configmap2 --from-env-file=config.txt       #再创建
[root@master ~]# kubectl exec -it secret-pod /bin/sh #进入容器输出变量,可以看到变量没有改变
/ # echo $USER_AGE
18
/ # echo $USER_NAME
lisi

那么,现在重新生成下pod,查看其环境变量是否会改变(肯定会改变的)?

[root@master ~]# kubectl delete -f secret-pod.yaml   #删除pod
[root@master ~]# kubectl apply -f secret-pod.yaml      #重新生成pod
[root@master ~]# kubectl exec -it secret-pod /bin/sh   #进入容器查看环境变量,发现已经改变了
/ # echo $USER_NAME
wangwu
/ # echo $USER_AGE
28

至此,验证完成。

———————— 本文至此结束,感谢阅读 ————————