kubernetes之secret和configmap

在日常单机甚至集群状态下,我们需要对一个应用进行配置,只需要修改其配置文件即可。那么在容器中又该如何提供配置信息呢???例如,为Nginx配置一个指定的server_name或worker进程数,为Tomcat的JVM配置其堆内存大小。

传统的实践过程中通常有以下几种方式:

  • 启动容器时,通过命令传递参数;
  • 将定义好的配置文件通过镜像文件进行写入;
  • 通过环境变量的方式传递配置数据;
  • 挂载Docker卷传送配置文件;

而在Kubernetes系统之中也存在这样的组件,就是特殊的存储卷类型。其并不是提供pod存储空间,而是给管理员或用户提供从集群外部向Pod内部的应用注入配置信息的方式。这两种特殊类型的存储卷分别是:configMap和secret。

  • Secret:用于向Pod传递敏感信息,比如密码,私钥,证书文件等,这些信息如果在容器中定义容易泄露,Secret资源可以让用户将这些信息存储在集群中,然后通过Pod进行挂载,实现敏感数据和系统解耦的效果。
  • ConfigMap:主要用于向Pod注入非敏感数据,使用时,用户将数据直接存储在ConfigMap对象当中,然后Pod通过使用ConfigMap卷进行引用,实现容器的配置文件集中定义和管理。
[root@k8s-master volumes]# kubectl explain pods.spec.volumes
......
   configMap    <Object>
     ConfigMap represents a configMap that should populate this volume

   secret   <Object>
     Secret represents a secret that should populate this volume. More info:
     https://kubernetes.io/docs/concepts/storage/volumes

Secret解析

Secret对象存储数据的方式是以键值方式存储数据,在Pod资源进行调用Secret的方式是通过环境变量或者存储卷的方式进行访问数据,解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。另外,Secret对象的数据存储和打印格式为Base64编码的字符串,因此用户在创建Secret对象时,也需要提供该类型的编码格式的数据。在容器中以环境变量或存储卷的方式访问时,会自动解码为明文格式。需要注意的是,如果是在Master节点上,Secret对象以非加密的格式存储在etcd中,所以需要对etcd的管理和权限进行严格控制。

Secret有4种类型:

  • Service Account :用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount目录中;

  • Opaque:base64编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为generic;

  • kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息,类型标识为docker-registry;

  • kubernetes.io/tls:用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。

创建 Secret 的2种方式

1、命令式创建

  • 通过 --from-literal。(每个 --from-literal 对应一个信息条目)
[root@master ~]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123456
secret/mysecret created
[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
mysecret               Opaque                                2      10s
  • 通过 --from-file。(每个文件内容对应一个信息条目)
[root@master ~]# echo -n admin > ./username
[root@master ~]# echo -n 123456 > ./password
[root@master ~]# kubectl create secret generic mysqlsecret --from-file=./username --from-file=./password
secret/mysqlsecret created
[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
mysecret               Opaque                                2      5m6s
mysqlsecret            Opaque                                2      8s
  • 通过 --from-env-file。(文件 env.txt 中每行 Key=Value 对应一个信息条目)
[root@master ~]# cat env.txt 
username=admin
password=123456
[root@master ~]# kubectl create secret generic redissecret --from-env-file=env.txt  
secret/redissecret created
[root@master ~]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
mysecret               Opaque                                2      9m15s
mysqlsecret            Opaque                                2      4m17s
redissecret            Opaque                                2      8s

2、清单式创建

  • 通过 YAML 配置文件
[root@master secret]# vim secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-demo
data:
  username: YWRtaW4=
  password: MTIzNDU2
[root@master secret]# kubectl apply -f secret-demo.yaml 
secret/secret-demo created
[root@master secret]# kubectl get secret
NAME                   TYPE                                  DATA   AGE
mysecret               Opaque                                2      16m
mysqlsecret            Opaque                                2      11m
redissecret            Opaque                                2      7m6s
secret-demo            Opaque                                2      11s
[root@master secret]# kubectl describe secret secret-demo
Name:         secret-demo
Namespace:    default
Labels:       <none>
Annotations:  
Type:         Opaque

Data
====
password:  6 bytes
username:  5 bytes
[root@master secret]# kubectl edit secret secret-demo  # 查看具体的value值
apiVersion: v1
data:
  password: MTIzNDU2
  username: YWRtaW4=
kind: Secret
metadata:
......
[root@master secret]# echo -n MTIzNDU2 | base64 --decode  # 通过base64将value值反编码
123456
[root@master secret]# echo -n YWRtaW4= | base64 --decode
admin

如何使用Secret??

Pod 可以通过 Volume 或者环境变量的方式使用 Secret。

  • 通过 Volume
[root@master secret]# vim pod-secret-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-demo
spec:
  containers:
  - name: pod-secret
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:  # 将 foo 挂载到容器路径 /etc/foo,可指定读写权限为 readOnly。
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:  # 定义 volume foo,来源为 secret/mysecret。
  - name: foo
    secret:
      secretName: mysecret
[root@master secret]# kubectl apply -f pod-secret-demo.yaml
pod/pod-secret-demo created
[root@master secret]# kubectl get pods
NAME              READY   STATUS    RESTARTS   AGE
pod-secret-demo   1/1     Running   0          23s
[root@master secret]# kubectl exec -it pod-secret-demo  -- /bin/sh
/ # cd /etc/foo
/etc/foo # ls
password  username
/etc/foo # cat username 
admin
/etc/foo # cat password 
123456

可以看到,Kubernetes 会在指定的路径 /etc/foo 下为每条敏感数据创建一个文件,文件名就是数据条目的 Key,这里是 /etc/foo/username 和 /etc/foo/password,Value 则以明文存放在文件中。
也可以自定义存放数据的文件名,比如将配置文件改为:

[root@master secret]# vim pod-secret-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-demo
spec:
  containers:
  - name: pod-secret
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:  # 将 foo 挂载到容器路径 /etc/foo,可指定读写权限为 readOnly。
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:  # 定义 volume foo,来源为 secret/mysecret。
  - name: foo
    secret:
      secretName: mysecret
      items:  # 自定义存放数据的文件名
      - key: username
        path: my-secret/my-username
      - key: password
        path: my-secret/my-password
[root@master secret]# kubectl delete -f pod-secret-demo.yaml 
pod "pod-secret-demo" deleted
[root@master secret]# kubectl apply -f pod-secret-demo.yaml 
pod/pod-secret-demo created
[root@master secret]# kubectl exec -it pod-secret-demo -- /bin/sh
/ # cat /etc/foo/my-secret/my-username
admin
/ # cat /etc/foo/my-secret/my-password
123456

这时数据将分别存放在 /etc/foo/my-secret/my-username 和 /etc/foo/my-secret/my-password 中。

以 Volume 方式使用的 Secret 支持动态更新:Secret 更新后,容器中的数据也会更新。

例如:将 password 更新为 abcdef,

[root@master secret]# echo -n abcdef | base64        
YWJjZGVm
[root@master secret]# kubectl edit secret mysecret
apiVersion: v1
data:
  password: YWJjZGVm
  username: YWRtaW4=
kind: Secret
...
[root@master secret]# kubectl exec -it pod-secret-demo -- /bin/sh
/ # cat /etc/foo/my-secret/my-password
abcdef

通过 Volume 使用 Secret,容器必须从文件读取数据,会稍显麻烦,Kubernetes 还支持通过环境变量使用 Secret。

  • 通过环境变量
[root@master secret]# vim pod-secret-env-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-env-demo
spec:
  containers:
  - name: pod-secret-env
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10; touch /tmp/healthy; sleep 30000
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
[root@master secret]# kubectl apply -f pod-secret-env-demo.yaml
pod/pod-secret-env-demo created
[root@master secret]# kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
pod-secret-demo       1/1     Running   0          17m
pod-secret-env-demo   1/1     Running   0          10s
[root@master secret]# kubectl exec -it pod-secret-env-demo -- /bin/sh
/ # echo $SECRET_USERNAME
admin
/ # echo $SECRET_PASSWORD
abcdef
/ # 

通过环境变量 SECRET_USERNAME 和 SECRET_PASSWORD 成功读取到 Secret 的数据。
需要注意的是,环境变量读取 Secret 很方便,但无法支撑 Secret 动态更新。
Secret 可以为 Pod 提供密码、Token、私钥等敏感数据;对于一些非敏感数据,比如应用的配置信息,则可以用 ConfigMap。

 

ConifgMap解析

很多情况下我们为某一应用做好镜像,当我们想修改其中的一些参数的时候,就变得比较麻烦,又要重新制作镜像,我们是不是有一种方式,让镜像根据不同的场景调用我们不同的配置文件呢,那我们就需要用到 k8s 的另外一种资源,那就是 ConfigMap。

我们知道,在几乎所有的应用开发中,都会涉及到配置文件的变更,比如说在web的程序中,需要连接数据库,缓存甚至是队列等等。而我们的一个应用程序从写第一行代码开始,要经历开发环境、测试环境、预发布环境只到最终的线上环境。而每一个环境都要定义其独立的各种配置。如果我们不能很好的管理这些配置文件,你的运维工作将顿时变的无比的繁琐。为此业内的一些大公司专门开发了自己的一套配置管理中心,如360的Qcon,百度的disconf等。kubernetes也提供了自己的一套方案,即ConfigMap。kubernetes通过ConfigMap来实现对容器中应用的配置管理。

configmap是让配置文件从镜像中解耦,让镜像的可移植性和可复制性。许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。这些配置信息需要与docker image解耦,你总不能每修改一个配置就重做一个image吧?ConfigMap API给我们提供了向容器中注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。

ConfigMap API资源用来保存key-value 形式的配置数据,这个数据可以在pod里使用,或者被用来为像controller一样的系统组件存储配置数据。虽然ConfigMap跟Secrets类似,但是ConfigMap更方便的处理不含敏感信息的字符串。 注意:ConfigMaps不是属性配置文件的替代品。ConfigMaps只是作为多个properties文件的引用。可以把它理解为Linux系统中的/etc目录,专门用来存储配置文件的目录。

[root@master volumes]# kubectl explain cm
KIND:     ConfigMap
VERSION:  v1
FIELDS:
   apiVersion   <string>
   binaryData   <map[string]string>
   data <map[string]string>
   kind <string>
   metadata <Object>

ConfigMap创建方式

与 Secret 一样,ConfigMap 也支持四种创建方式:

  • 通过 --from-literal,每个 --from-literal 对应一个信息条目:
[root@master ~]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.magedu.com
configmap/nginx-config created
[root@master ~]# kubectl get cm
NAME           DATA   AGE
nginx-config   2      3s
[root@master ~]# kubectl describe cm nginx-config
Name:         nginx-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
nginx_port:
----
80
server_name:
----
myapp.magedu.com
Events:  <none>
  • 通过 --from-file,每个文件内容对应一个信息条目:
[root@master ~]# mkdir nginx-cm
[root@master ~]# cd nginx-cm
[root@master nginx-cm]# vim www.conf
server {
    server_name myapp.magedu.com;
    listen 80;
    root /data/web/html;
}
[root@master nginx-cm]# kubectl create configmap nginx-www --from-file=./www.conf
configmap/nginx-www created
[root@master nginx-cm]# kubectl get cm
NAME           DATA   AGE
nginx-config   2      4m26s
nginx-www      1      14s
[root@master nginx-cm]# kubectl get cm nginx-www -o yaml
apiVersion: v1apiVersion: v1
data:
  www.conf: |
    server {
        server_name myapp.magedu.com;
        listen 80;
        root /data/web/html;
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2019-09-25T10:44:41Z"
  name: nginx-www
  namespace: default
  resourceVersion: "354415"
  selfLink: /api/v1/namespaces/default/configmaps/nginx-www
  uid: 5d113a7a-96a1-4a95-adf7-5c3288ff8f1b
  • 通过一个文件内多个键值对,--from-env-file= 
cat << EOF > env.txt
db.host=10.0.0.50
db.port=3306
EOF
kubectl create cm env-cm --from-env-file=env.txt

如果有多个env文件, 只有最后一个env文件会生效:

[root@master configmap_test]# cat game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

[root@master configmap_test]# cat ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# 执行命令创建configmap
kubectl create configmap configmap-env --from-env-file=./game.properties --from-env-file=./ui.properties
# 可以看到, 只有ui.properties生效了
[root@master configmap_test]# kubectl get configmaps configmap-env -o yaml
apiVersion: v1
data:
  allow.textmode: "true"
  color.bad: yellow
  color.good: purple
  how.nice.to.look: fairlyNice
kind: ConfigMap
metadata:
  creationTimestamp: "2019-09-11T01:58:17Z"
  name: configmap-env
  namespace: default
  resourceVersion: "186936"
  selfLink: /api/v1/namespaces/default/configmaps/configmap-env
  uid: 4e36009f-267c-4713-8a7a-99d8f6dd3039
  •  通过yaml文件创建
[root@master configmap]# cat test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-4
data:
  db.host: 10.0.0.50
  db.port: "3306"
[root@master configmap]# kubectl apply -f test.yaml
[root@master configmap]# kubectl describe cm cm-4
Name:         cm-4
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"db.host":"10.0.0.50","db.port":"3306"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cm-4","...

Data
====
db.host:
----
10.0.0.50
db.port:
----
3306
Events:  <none>

如何使用configMap??

  • 环境变量方式注入到pod
[root@master nginx-cm]# vim pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-1
  namespace: default
  labels: 
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80 
    env:
    - name: NGINX_SERVER_PORT
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: nginx_port
    - name: NGINX_SERVER_NAME
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: server_name
[root@master nginx-cm]# kubectl apply -f pod-configmap.yaml 
pod/pod-cm-1 created
[root@master nginx-cm]# date
Sun Sep 29 16:07:57 CST 2019
[root@master nginx-cm]# kubectl exec -it pod-cm-1 -- /bin/sh
/ # echo $NGINX_SERVER_PORT
80
/ # echo $NGINX_SERVER_NAME
myapp.magedu.com

修改端口,可以发现使用环境变化注入pod中的端口不会根据配置的更改而变化。

[root@master nginx-cm]# kubectl edit cm nginx-config
configmap/nginx-config edited
[root@master nginx-cm]# kubectl exec -it pod-cm-1 -- /bin/sh
/ # echo $NGINX_SERVER_PORT
80
  • 存储卷方式挂载configmap,Volume 形式的 ConfigMap 也支持动态更新:
[root@master configmap ~]# vim pod-configmap-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-2
  namespace: default
  labels: 
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80 
    volumeMounts:
    - name: nginxconf
      mountPath: /etc/nginx/config.d/
      readOnly: true
  volumes:
  - name: nginxconf
    configMap:
      name: nginx-config
[root@master configmap ~]# kubectl apply -f pod-configmap-2.yaml
pod/pod-cm-2 created
[root@master configmap ~]# kubectl exec -it pod-cm-2 -- /bin/sh
/ # cd /etc/nginx/config.d
/etc/nginx/config.d # cat nginx_port
80
/etc/nginx/config.d # cat server_name 
myapp.magedu.com

[root@master configmap ~]# kubectl edit cm nginx-config  # 修改端口,再进入容器中查看端口是否变化。
apiVersion: v1
data:
  nginx_port: "800"
  ......
  
[root@master configmap ~]# kubectl exec -it pod-cm-2 -- /bin/sh
/ # cd /etc/nginx/config.d
/etc/nginx/config.d # cat nginx_port
800
[root@k8s-master configmap ~]# kubectl delete -f pod-configmap2.yaml

configmap的item使用 

创建configmap

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

将configmap中的SPECIAL_LEVEL挂载到pod/etc/config/keys

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh","-c","sleep 3600"]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: SPECIAL_LEVEL
          path: keys

 可以看到已经生效了

[root@master configmap_test]# kubectl exec -ti test-pod -- /bin/sh
/ # cat /etc/config/keys
very
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值