在应用启动过程中需要一些敏感信息,比如数据库用户名、密码,如果直接明文存储在容器镜像中是不安全的,K8S提供的方案是Secret。

1.1 创建与查看Secret

Secret会以密文的方式存储数据,避免了直接在配置文件中保存敏感信息。Secret会以Volume的形式被mount到Pod,容器可通过文件的方式使用Secret中的敏感数据;此外,容器也可以环境变量的方式使用这些数据。
Secret可通过命令行或YAML创建。比如希望Secret中包含如下信息:用户名admin、密码123456。

这里假设我们要创建一个包含以下信息的Secret:用户名:Test 密码:Test123456*
有4种方法来创建Secret:
(1)通过 --from-literal:

kubectl create secret generic mysecret --from-literal=username=Test--from-literal=password=Test123456*

PS:每个 --from-literal 对应一个信息条目
(2)通过 --from-file:

echo -n Test> ./username
echo -n Test123456* > ./password
kubectl create secret generic mysecret --from-file=./username --from-file=./password

PS:每个文件内容对应一个信息条目
(3)通过 --from-env-file:

cat << EOF > env.txt
username=Test
password=Test123456*
EOF
kubectl create secret generic mysecret --from-env-file=env.txt

PS:文件 env.txt 中每行 Key=Value 对应一个信息条目
(4)通过YAML配置文件创建:(推荐方式)
由于配置文件中的敏感数据必须是通过base64编码后的结果,因此需要获取base64编码后的值:

[root@k8s-master ~]#  echo -n Test | base64
VGVzdA==
[root@k8s-master ~]#  echo -n Test123456* | base64
VGVzdDEyMzQ1Nio=
[root@k8s-master ~]#

vi secret-demo.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
data:
  username: VGVzdA==
  password: VGVzdDEyMzQ1Nio=

通过kubectl get secret查看存在的secret。
通过kubectl describe secret查看条目的Key。

[root@k8s-master ~]# vi secret-demo.yaml
[root@k8s-master ~]#  kubectl apply -f secret-demo.yaml
secret/mysecret created
[root@k8s-master ~]# kubectl get secret mysecret
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      16s
[root@k8s-master ~]# kubectl describe serect myserect
error: the server doesn't have a resource type "serect"
[root@k8s-master ~]# kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:
Type:         Opaque

Data
====
password:  11 bytes
username:  4 bytes


通过kubectl edit secret mysecret 查看value,然后通过base64将Value反编码。

password: VGVzdDEyMzQ1Nio=
username: VGVzdA==
[root@k8s-master ~]# echo -n VGVzdA== | base64 --decode
Test[root@k8s-master ~]# echo -n VGVzdDEyMzQ1Nio= | base64 --decode
Test123456*[root@k8s-master ~]#

1.2 在Pod中使用Secret

K8S中Pod中使用Secret有两种方式,一是Volume方式,二是环境变量的方式。
(1)Volume方式
这里我们以一个示例演示一下如何通过Volume方式使用Secret,首先定义一个Pod:
vi secret-demo-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo-pod
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

该Pod中会使用到刚刚定义的secret(edc-secret),然后volumeMounts定义了将foo mount到容器中的路径为/etc/foo的目录下,并且指定了读写权限为只读。
通过kubectl apply创建之后,我们试着在容器中读取secret来验证一下

[root@k8s-master ~]#  kubectl apply -f secret-demo-pod.yaml
pod/secret-demo-pod created
[root@k8s-master ~]# kubectl exec -it secret-demo-pod /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # ls /etc/foo/
password  username
/ # cat /etc/foo/password
Test123456*/ #
/ # cat /etc/foo/username
Test/ #


我们也可以自定义存放数据的文件名。

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo-pod
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
     secret:
      secretName: edc-secret
      items:
      - key: username
        path: /my-group/username
      - key: password
        path: /my-group/password

这时数据将分别存放在/etc/foo/my-group/my-username和/etc/foo/my-group/my-password中。
以Volume方式使用的Secret支持动态更新:Secret更新后,容器中的数据也会更新将password更新为abcdef,base64编码为YWJjZGVm。

几秒钟后,新的password会同步到容器。

[root@k8s-master ~]# vi secret-demo.yaml
[root@k8s-master ~]#  kubectl apply -f secret-demo.yaml
secret/mysecret configured
[root@k8s-master ~]# kubectl exec -it secret-demo-pod /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # cat /etc/foo/password
abcdefg/ #

1.3 环境变量⽅式

通过Volume使用Secret看起来稍微麻烦了一点,容器必须通过文件读取数据。K8S提供了另外一种方式,那就是环境变量方式。
下面仍以上面的例子为例,修改配置文件:
vi secret-demo-pod2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo-pod
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    env:
      - name: MY_SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: MY_SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password


通过环境变量SECRET_USERNAME和SECRET_PASSWORD成功读取到Secret的数据。
需要注意的是,环境变量读取Secret很方便,但无法支撑Secret动态更新。

[root@k8s-master ~]# vi secret-demo-pod2.yaml
[root@k8s-master ~]#  kubectl apply -f secret-demo-pod2.yaml
pod/secret-demo-pod2 created
[root@k8s-master ~]# kubectl exec -it secret-demo-pod2 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # echo $MY_SECRET_USERNAME
Test
/ # echo $MY_SECRET_PASSWORD
abcdefg

1.4 使用Configmap

Secret可以为Pod提供密码、Token、私钥等敏感数据;对于⼀些非敏感数据,比如应用的配置信息,则可以用ConfigMap。
ConfigMap的创建和使用⽅式与Secret非常类似,主要的不同是数据以明文的形式存放。
和Secret一样,也可以通过Volume 或 环境变量两种方式来使用Configmap。
(1)Volume方式

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo
spec:
  containers:
  - name: configmap-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    configMap:
      name: service-configmap

(2)环境变量方式

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    env:
      - name: SERVICE_LOG_LEVEL
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: LogLevel
      - name: SERVICE_LOG_FILE
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: LogFile
      - name: SERVICE_ALLOWED_HOSTS
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: AllowedHosts

大多数情况下,大家建议的最佳实践是:
(1)创建ConfigMap采用YAML配置方式 => 便于复用和版本管理
(2)读取ConfigMap采用Volume方式 => 便于配置动态更新

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐