Kubernetes入门实践(ConfigMap/Secret)

Kubernetes中用于管理配置信息的两种对象: ConfigMap和Secret,可使用它们来灵活地配置和定制应用。应用程序有很多类别的配置信息,从数据安全的角度看可分为明文配置和机密配置,明文配置就是不保密,可以任意修改,如服务端口、运行参数、文件路径等等,机密配置涉及敏感信息需要保密,不能随便查看,比如密码、密钥和证书等

创建ConfigMap

kubectl create来创建一个它的YAML样板,可以使用缩写"cm":

$ minikube kubectl -- create cm info --dry-run=client -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: info

ConfigMap中没有spec这样的字段,只有apiVersion、kind和metadata,因为ConfigMap存储的是配置数据,是静态的字符串,并非容器,所以就无需spec字段,但应当给它定义一个data字段,就要加一个参数--from-literal,表示从字面值生成一些数据:

$ minikube kubectl -- create cm info --from-literal=k=v --dry-run=client -o yaml
apiVersion: v1
data:
  k: v
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: info

这里的--fron-literal指定了k=v,原因是其中数据都是key-value结构,编辑这个样板:

apiVersion: v1
data:
  count: '10'
  debug: 'on'
  path: '/etc/systemd'
  greeting: |
    say hello to kubernetes.
kind: ConfigMap
metadata:
  name: info

使用apply来创建ConfigMap对象,使用get cm来查看,使用describe cm来查看详细信息:

$ minikube kubectl -- apply -f cm.yml 
configmap/info created
$ minikube kubectl -- get cm
NAME               DATA   AGE
info               4      40s
$ minikube kubectl -- describe cm info
Name:         info
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
count:
----
10
debug:
----
on
greeting:
----
say hello to kubernetes.

path:
----
/etc/systemd

BinaryData
====

Events:  <none>

现在这个配置信息已经存入etcd数据库了,后续可以被其他API对象使用

创建Secret

与ConfigMap相似,但细分了很多类:

  1. 访问私有镜像仓库的认证信息
  2. 身份识别的凭证信息
  3. HTTPS通信的证书和私钥
  4. 一般的机密信息(格式由用户自行解释)

创建样板:

$ minikube kubectl -- create secret generic user --from-literal=name=root --dry-run=client -o yaml
apiVersion: v1
data:
  name: cm9vdA==
kind: Secret
metadata:
  creationTimestamp: null
  name: user

Secret对象和ConfigMap比较相似,只是kind字段由ConfigMap变成了Secret,data里同样是key-value数据

可以发现Secret中的name是做了base64编码的,不让用户直接看到原来的内容,现在来直接编辑这个样板:

apiVersion: v1
data:
  name: cm9vdA== # root
  pwd: MTIzNDU2  # 123456
  db: bXlzcWw=   # mysql
kind: Secret
metadata: 
  name: user

创建和查看对象:

$ minikube kubectl -- apply -f secret.yml 
secret/user created
$ minikube kubectl -- get secret
NAME                  TYPE                                  DATA   AGE
default-token-cg2ws   kubernetes.io/service-account-token   3      5d12h
user                  Opaque                                3      67s
$ minikube kubectl -- describe secret
Name:         default-token-cg2ws
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 4d3b6e91-89b6-4345-85ae-e9e8b1e9073f

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1111 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ik1JWmxuY0Jac1B1OXFXcmNLQ3pONmstcVZqdzQwMHJ0UmY4R3BWYWxIQ1UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tY2cyd3MiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRkM2I2ZTkxLTg5YjYtNDM0NS04NWFlLWU5ZThiMWU5MDczZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.U87mqQq1jAb9JCyxfoFG0D-_UF1qZAszbIwnR-a_HNPTq4-Wnn3xSlMkc6ZUSHOQ2YytTuyi0KVYlxl6uzqJiJ78n_EnjLb_4r-gzVaRFBchtSND4RmM0TDG_uvIZMie4rhF8-E3O2h-iPv6jV9Jj-lA_6HoK3v1Fngucq_jzQX1MWwRhS-95OD-fDtukNotX29E7K-P0t__vFWFX4dVm00FAxIXkvPhkIKwfR1qazsg-o9ykalA9LxUoiJxRKzyCSS9MPCOdal8Dik_2CXAcX6NcijcXWTQkmbLdSK0Alm4CiKiYTInQyVo_hlLMMmS19NhhzpVWtLtomzrvDNfTA


Name:         user
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
db:    5 bytes
name:  4 bytes
pwd:   6 bytes

可以看到信息是保密的,describe并不难直接看到信息

使用方法

在Kubernetes中ConfigMap和Secret的应用方式有两种: 环境变量和加载文件,让其在Pod运行时产生效果

环境变量

在Pod的containers字段中有一个env,定义了Pod里容器能够看到的环境变量,还可以用valueFrom,从ConfigMap或者Secret对象中取值,这样就实现了把配置信息以环境变量的形式注入Pod,也就是配置与应用的解耦

由于valueFrom字段在YAML里的嵌套层次比较深,初次使用可以看kubectl explain 对它的说明:

$ minikube kubectl -- explain pod.spec.containers.env.valueFrom
KIND:     Pod
VERSION:  v1

RESOURCE: valueFrom <Object>

DESCRIPTION:
     Source for the environment variable's value. Cannot be used if value is not
     empty.

     EnvVarSource represents a source for the value of an EnvVar.

FIELDS:
   configMapKeyRef	<Object>
     Selects a key of a ConfigMap.

   fieldRef	<Object>
     Selects a field of the pod: supports metadata.name, metadata.namespace,
     `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName,
     spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.

   resourceFieldRef	<Object>
     Selects a resource of the container: only resources limits and requests
     (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu,
     requests.memory and requests.ephemeral-storage) are currently supported.

   secretKeyRef	<Object>
     Selects a key of a secret in the pod's namespace

valueFrom指定了环境变量值的来源,可以是configMapKeyRet(从ConfigMap中获取配置信息)或者secretKeyRef,然后要再进一步指定应用的ConfigMap/Secret的name和它里面的key:

apiVersion: v1
kind: Pod
metadata:
  name: env-pod
spec:
  containers:
  - env:
    - name: COUNT
      valueFrom:
        configMapKeyRef:
          name: info
          key: count
    - name: GREETING
      valueFrom:
        configMapKeyRef:
          name: info
          key: greeting      
    - name: USERNAME
      valueFrom:
        secretKeyRef:
          name: user
          key: name
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: user
          key: pwd      

    image: busybox
    name: busy
    imagePullPolicy: IfNotPresent
    command: ["/bin/sleep","300"]

这个Pod的名字是env-pod,镜像是busybox,执行命令sleep睡眠300秒

env中定义了4个环境变量: COUNT、GREETING、USERNAME、PASSWORD

对于明文配置数据,COUNT、GREETING引用的是ConfigMap对象,所以使用字段configMapKeyRef,里面name是ConfigMap对象的名字,也就是之前创建的info,而key字段分别是info对象里的count和greeting

同样对于机密配置数据,USERNAME、PASSWORD引用的是Secret对象,使用字段secretKeyRef,再用name指定Secret对象的名字user,用key字段应用里面的name和pwd

显然,Pod与ConfigMap、Secret的松耦合关系,它们不是直接嵌套包含,而是使用KeyRef字段间接引用对象,同一段配置信息就可以在不同的对象之间共享

接下来创建Pod,并使用exec进行验证:

$ minikube kubectl -- apply -f env-pod.yml 
pod/env-pod created

使用exec打开一个shell,验证环境变量:

$ minikube kubectl -- exec -it env-pod -- sh
/ # echo $COUNT
10
/ # echo $GREETING
say hello to kubernetes.
/ # echo $USERNAME
root
/ # echo $PASSWORD
123456

成功输出了在两个YAML里定义的配置信息,就是说Pod对象成功组合了ConfigMap和Secret对象

查看状态信息:

$ minikube kubectl -- get pod
NAME                     READY   STATUS      RESTARTS   AGE
env-pod                  1/1     Running     0          4m39s

Volume

Kubernetes为Pod定义了一个volume的概念,可以翻译成存储卷,如果将Pod理解成一个虚拟机,那么Volume就相当于虚拟机里的磁盘,可以为Pod挂载多个volume,里面存放供Pod访问的数据,这种方式类似docker run -v

在Pod里要挂载只要在spec中增加一个volumns字段,然后再定义卷的名字和引用的ConfigMap/Secret中即可,要注意的是volume属于Pod,不属于容器,所以它和字段containers属于同级,都属于spec

编辑YAML文件:

apiVersion: v1
kind: Pod
metadata:
  name: env-pod
  
spec:
  volumes:
  - name: cm-vol
    configMap:
      name: info
  - name: sec-vol
    secret:
      secretName: user

  containers:
  - volumeMounts:
    - mountPath: /tmp/cm-items
      name: cm-vol
    - mountPath: /tmp/sec-items
      name: sec-vol   

    image: busybox
    name: busy
    imagePullPolicy: IfNotPresent
    command: ["/bin/sleep","300"]

定义两个volume,分别引用ConfigMap和Secret,名字是cm-vol和sec-vol,有了volume的定义后就可以在容器里挂载,这就要使用volumeMounts字段,正如其字面含义,将定义好的volume挂载到容器的某个路径,所以需要在里面用mountPath和name明确地指定挂载路径和volume的名字,使用volume的好处是统一抽象了所有的存储,不仅现在支持ConfigMap/Secret,以后还能支持临时卷、持久卷、动态卷、快照卷等许多形式的存储,扩展性良好

创建Pod:

$ minikube kubectl -- apply -f env-pod.yml 
pod/vol-pod created

创建之后,使用kubectl exec进入Pod,配置信息:

$ minikube kubectl -- exec -it vol-pod -- sh
/ # ls /tmp/cm-items/
count     debug     greeting  path
/ # ls /tmp/sec-items/
db    name  pwd
/ # cat /tmp/cm-items/greeting 
say hello to kubernetes.
/ # cat /tmp/sec-items/pwd
123456/

ConfigMap和Secret都变成了目录的形式,而它们里面的key-value变成了一个个文件,文件名就是key

环境变量用法简单,更适合存放简短的字符串,而Volume更适合存在大数据量的配置文件,在Pod中加载成文件后让应用直接读取使用

posted @ 2022-07-28 13:16  N3ptune  阅读(321)  评论(0编辑  收藏  举报