前言
在Pod中应用配置和密码,我们可以创建配置对象ConfigMap和密码对象Secret。
而这两种对象的使用有多种方式:
- 存储卷方式
 - 环境变量方式
 - 命令行方式
 
非加密ConfigMap
https://kubernetes.io/docs/concepts/configuration/configmap/
ConfigMap 常用在两种情况中. 第一种是提供环境变量.第二种是提供配置文件
写法
kind: ConfigMap
apiVersion: v1
metadata:
  name: cm-demo
  namespace: default
data:
  data.1: hello
  data.2: world
  data.conf: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
#immutable: true
immutable: true 表示这是一个不可变更的CM,一旦CM创建,则这个属性不可更改。意味着如果你要更改,则需要删除CM和调用CM的Pod。
上述例子中, 包含两种写法
- 环境变量
 
  data.1: hello
  data.2: world
- 配置文件
 
  data.conf: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
data.conf 是文件名, 管道符 | 下面是文件内容. ✨需要注意的是, data.conf 内容依然要遵循 yaml 的缩进规则
命令式写法
kubectl create cm cm-demo --from-file=data.conf
使用
- 方法1
 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      run: busybox
  template:
    metadata:
      labels:
        run: busybox 
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh", "-c", "echo ${DATA1} ${DATA2}"]
        env:
        - name: DATA1
          valueFrom:
            configMapKeyRef:
              name: cm-demo  # 注意,这是ConfigMap对象名
              key: data.1    # 这是ConfigMap里的key
        - name: DATA2
          valueFrom:
            configMapKeyRef:
              name: cm-demo
              key: data.2
        volumeMounts:
        - name: cm-demo-vol
          mountPath: "/etc"  # cm 对象获取的 key 内容文件的根路径。
          readOnly: true
      volumes:
      - name: cm-demo-vol
        configMap:
          name: cm-demo
          items:             # items 就是获取 cm 对象下的所有 key
          - key: "data.conf" # 获取名叫 data.conf 的 key
            path: "data.conf" # 将 data.conf 这个 key 的内容写入到 /etc/data.conf 这个路径文件里
通过上面的写法,可以在容器内找到 /etc/data.conf 。
✨当你更新 cm 对象的时候,cm 对象会把更新内容同步到容器中。更新速度并不是立马就能响应,也是轮询更新。
💥注意:这种方式会清空 mountPath 路径。因为挂载点是目录。
- 方法2
 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      run: busybox
  template:
    metadata:
      labels:
        run: busybox 
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh", "-c", "echo ${DATA1} ${DATA2}"]
        env:
        - name: DATA1
          valueFrom:
            configMapKeyRef:
              name: cm-demo  # 注意,这是ConfigMap对象名
              key: data.1    # 这是ConfigMap里的key
        - name: DATA2
          valueFrom:
            configMapKeyRef:
              name: cm-demo
              key: data.2
        volumeMounts:
        - name: cm-demo-vol
          subPath: data.conf         
          mountPath: "/etc/data.conf"
          readOnly: true
      volumes:
      - name: cm-demo-vol
        configMap:
          name: cm-demo
✨这种通过 subPath 获取 cm 的 key data.conf,并针对性的挂载到指定文件 /etc/data.conf 。可以避免挂载点是目录的时候被覆盖。
💥这种方式,cm对象修改无法同步到容器中。
- 
方法3
通过在 spec.containers.env 中定义. 例子中, DATA1 是环境变量名, DATA1的值通过valueFrom定义.最终,你可以在容器中使用环境变量DATA1和DATA2
通过在 spec.containers.envFrom 中定义一组环境变量,这种方式要求 cm 里的 key 必须都符合 C_IDENTIFIER 规范.
 
        env:
        - name: DATA1
          valueFrom:
            configMapKeyRef:
              name: cm-demo  # 注意,这是ConfigMap对象名
              key: data.1    # 这是ConfigMap里的key
        - name: DATA2
          valueFrom:
            configMapKeyRef:
              name: cm-demo
              key: data.2
        envFrom:
        - configMapRef:
            name: cm-envs
- 💥这种方式下ConfigMap更新后,环境变量不会更新。
 
加密Secret
https://kubernetes.io/docs/concepts/configuration/secret/
secret对象里的值需要写入加密后的.
写法
我们定义一个用户密码对,分别是username和password
secret对象要求值必须进行base64编码加密(当type为Opaque的时候).
[root@k8s00 test-yaml]# echo -n "admin" | base64
YWRtaW4=
[root@k8s00 test-yaml]# echo -n "admin321" | base64
YWRtaW4zMjE=
# 创建 secret 对象 mysecret
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: default
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
👀type用来定义不同的类型,比较常用的有:
Opaque普通加密字符串kubernetes.io/tlstls证书kubernetes.io/dockerconfigjsondocker仓库账户密码kubernetes.io/service-account-token服务账户授权token
使用
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: busybox
    command:
    - sleep
    - "3600"
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
    volumeMounts:
    - name: mysecret-vol
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: mysecret-vol
    secret:
      secretName: mysecret
✨secret 也支持 immutable: true ,即不可变的 secret。
- 使用2
 
通过在 spec.containers.envFrom.secretRef 中定义一组环境变量,这种方式要求 secret 里的 key 必须都符合 C_IDENTIFIER 规范.
kubectl explain deployment.spec.template.spec.containers.envFrom.secretRef
immutable: true
有以下好处
- 避免对象被意外修改
 - 降低 kube-apiserver 的压力,因为不可变,所以 kubelet 就无需 watch kube-apiserver.
 
临时卷
- 通过在 spec.volumes.secret 中定义临时卷 mysecret-vol。
 - 剩余用法和 spec.volumes.configMap 一样。
 
环境变量
- 通过在 spec.containers.env 中定义。
 
测试
在通过上述配置创建好资源后,我们进入pod,进行测试.
[root@k8s00 test-yaml]# kubectl exec -it mypod -- /bin/sh
===可以看到两个加密信息生成了两个软连接,并指向了隐藏文件
/ # ls -l /etc/foo
total 0
lrwxrwxrwx    1 root     root            15 Sep 17 07:18 password -> ..data/password
lrwxrwxrwx    1 root     root            15 Sep 17 07:18 username -> ..data/username
===环境变量
/ # echo ${SECRET_USERNAME}
admin
===文件方式
/ # cat /etc/foo/username
admin 
限制
- 资源和Pod限制在同一命名空间
 - 对象数据大小不能超过1MB
 - 当pod引用不存在的对象时,pod无法启动
 
其它
- 
命令方式创建
kubectl create configmap/secret
xxx 这里xxx可以用两种方式:
- –from-literal=
= 指定kv  - –from-file=<文件/目录> 当为目录的时候,会递归将目录里的文件都写入对象中
 
 - –from-literal=
 - 
在Pod中隐藏配置或者密码文件
你可以将
secret.data.<key>写成secret.data.<.key>来隐藏它. 
信息提供Downward API
https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/
Downward API用来向Pod中运行的容器公开提供容器和Pod的信息。
例子1:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: oom-sims
  namespace: default
  labels:
    app: oom-sims
spec:
  replicas: 1
  selector:
    matchLabels:
      app: oom-sims
  template:
    metadata:
      labels:
        app: oom-sims
    spec:
      volumes:
        - name: dumplog
          emptyDir: {}
      containers:
        - name: oom-sims-container
          image: cloudbeer/oom-sims:1.0
          command: ["/bin/sh", "-c", "java -Xms256m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumplog/${RANDOM}.dump -jar /app/oom-sims-1.0-SNAPSHOT.jar 1000"]
          resources:
            requests:
              memory: "2Gi"
              cpu: "500m"
            limits:
              memory: "2Gi"
              cpu: "500m"
          volumeMounts:
          - name: dumplog
            mountPath: /dumplog
        - name: dumplogupload
          image: aaa103439/dumplogupload:latest
          env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: NODE_IP
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: OSS_ENDPOINT
            value: "oss-cn-beijing-internal.aliyuncs.com"
          - name: OSS_ACCESSID
            value: "" # 
          - name: OSS_ACCESSSECRET
            value: ""
          - name: OSS_BUCKET
            value: "juaiit"
          - name: OSS_DUMPER_ROOT
            value: "logs/dump/$(NAMESPACE)"
          - name: APP_NAME # 应用名称,这个名称会附加在文件名后面
            value: $(POD_NAME)_$(NODE_IP)
          - name: DUMPER_ROOT # 会监视这个文件夹下面的文件,-XX:HeapDumpPath = DUMPER_ROOT/xxx.DUMPER_SUFFIX
            value: "/dumplog" 
          - name: DUMPER_SUFFIX # dump 文件后缀
            value: ".dump"
          volumeMounts:
          - name: dumplog
            mountPath: /dumplog
例子2: 将资源限制数据挂载到容器/etc/podinfo
apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example-2
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox:1.24
      command: ["sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          if [[ -e /etc/podinfo/cpu_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_limit; fi;
          if [[ -e /etc/podinfo/cpu_request ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_request; fi;
          if [[ -e /etc/podinfo/mem_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_limit; fi;
          if [[ -e /etc/podinfo/mem_request ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_request; fi;
          sleep 5;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "cpu_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.cpu
              divisor: 1m
          - path: "cpu_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.cpu
              divisor: 1m
          - path: "mem_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.memory
              divisor: 1Mi
          - path: "mem_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.memory
              divisor: 1Mi
projected volume使用方式
kubernetes 提供了一种卷类型 projected volume。可以将多个volume挂载到一个位置上。
写法:
        volumeMounts:
        - name: all-in-one
          mountPath: /etc/allinfo
          readonly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: user
      - secret:
          name: pass
      - configmap:
          name: content
      - downwardAPI:
          items:
            - path: "labels"
              fieldRef:
                fieldPath: metadata.labels
            - path: "annotations"
              fieldRef:
                fieldPath: metadata.annotations
user, pass, content, labels, annotations 将会以文件形式存在于容器挂载点 /etc/allinfo 内。
创建Secret对象: secret: user 和 secret: pass
echo -n "admin" > ./username.txt
kubectl create secret generic user --from-file=./username.txt
echo -n "1f2d1e2e67df" > ./username.txt
kubectl create secret generic pass --from-file=./password.txt
创建 ConfigMap对象: content
echo -n "userinfo" > ./content.txt
kubectl create configmap content --from-file=./content.txt
DownwardAPI 临时卷内容直接配置里写入