configMap

ConfigMap功能在Kubernetes1.2版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMapAPI给我们提供了向容器中注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制对象

ConfigMap用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件。ConfigMap跟secret很类似,但它可以更方便地处理不包含敏感信息的字符串。

ConfigMap的创建

I、使用目录创建

  1. $ ls docs/user-guide/configmap/kubectl/
  2. game.properties
  3. ui.properties
  4. $ cat docs/user-guide/configmap/kubectl/game.properties
  5. enemies=aliens
  6. lives=3
  7. enemies.cheat=true
  8. enemies.cheat.level=noGoodRotten
  9. secret.code.passphrase=UUDDLRLRBABAS
  10. secret.code.allowed=true
  11. secret.code.lives=30
  12. $ cat docs/user-guide/configmap/kubectl/ui.properties
  13. color.good=purple
  14. color.bad=yellow
  15. allow.textmode=true
  16. how.nice.to.look=fairlyNice
  17. $ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
  18. # kubectl create configmap 配置名 指定路径

**-from-file** 指定在目录下的所有文件都会被用在ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容

Ⅱ、使用文件创建

只要指定为一个文件就可以从单个文件中创建 ConfigMap

  1. $ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties
  2. $ kubectl get configmaps game-config-2 -o yaml # 查看详细信息

-from-file 这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的

Ⅲ、使用字面值创建

使用文字值创建,利用 -from-literal 参数传递配置信息,该参数可以使用多次,格式如下

  1. $ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
  2. $ kubectl get configmaps special-config -o yaml

ConfigMap使用

ConfigMap可以通过多种方式在Pod中使用,比如设置环境变量、设置容器命令行参数、在Volume中创建配置文件等。

注意

  • ConfigMap必须在Pod引用它之前创建
  • 使用envFrom时,将会自动忽略无效的键
  • Pod只能使用同一个命名空间内的ConfigMap

Pod 中使用ConfigMap

I、使用ConfigMap 来替代环境变量

首先创建ConfigMap:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: special-config
  5. namespace: default
  6. data:
  7. special.how: very
  8. special.type: charm
  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: env-config
  5. namespace: default
  6. data:
  7. log_level: INFO

然后以环境变量方式引用

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: dapi-test-pod
  5. spec:
  6. containers:
  7. - name: test-container
  8. image: hub.atguigu.com/library/myapp:v1
  9. command: [ "/bin/sh", "-c", "env" ]
  10. env:
  11. - name: SPECIAL_LEVEL_KEY
  12. valueFrom:
  13. configMapKeyRef:
  14. name: special-config
  15. key: special.how
  16. - name: SPECIAL_TYPE_KEY
  17. valueFrom:
  18. configMapKeyRef:
  19. name: special-config
  20. key: special.type
  21. envFrom:
  22. - configMapRef:
  23. name: env-config
  24. restartPolicy: Never

当pod运行结束后,它的输出会包括

  1. SPECIAL_LEVEL_KEY=very
  2. SPECIAL_TYPE_KEY=charm
  3. log_level=INFO

Ⅱ、用ConfigMap设置命令行参数

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: special-config
  5. namespace: default
  6. data:
  7. special.how: very
  8. special.type: charm
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: dapi-test-pod
  5. spec:
  6. containers:
  7. - name: test-container
  8. image: hub.atguigu.com/library/myapp:v1
  9. command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
  10. env:
  11. - name: SPECIAL_LEVEL_KEY
  12. valueFrom:
  13. configMapKeyRef:
  14. name: special-config
  15. key: special.how
  16. - name: SPECIAL_TYPE_KEY
  17. valueFrom:
  18. configMapKeyRef:
  19. name: special-config
  20. key: special.type
  21. restartPolicy: Never

Ⅲ、通过数据卷插件使用ConfigMap

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: special-config
  5. namespace: default
  6. data:
  7. special.how: very
  8. special.type: charm

在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: dapi-test-pod
  5. spec:
  6. containers:
  7. - name: test-container
  8. image: hub.atguigu.com/library/myapp:v1
  9. command: [ "/bin/sh", "-c", "cat /etc/config/special.how" ]
  10. volumeMounts:
  11. - name: config-volume
  12. mountPath: /etc/config
  13. volumes:
  14. - name: config-volume
  15. configMap:
  16. name: special-config
  17. restartPolicy: Never

ConfigMap的热更新

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: log-config
  5. namespace: default
  6. data:
  7. log_level: INFO
  8. ---
  9. apiVersion: extensions/v1beta1
  10. kind: Deployment
  11. metadata:
  12. name: my-nginx
  13. spec:
  14. replicas: 1
  15. template:
  16. metadata:
  17. labels:
  18. run: my-nginx
  19. spec:
  20. containers:
  21. - name: my-nginx
  22. image: hub.atguigu.com/library/myapp:v1
  23. ports:
  24. - containerPort: 80
  25. volumeMounts:
  26. - name: config-volume
  27. mountPath: /etc/config # 容器中挂载目录
  28. volumes:
  29. - name: config-volume
  30. configMap:
  31. name: log-config
  1. $ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2` cat /etc/config/log_level
  2. INFO

修改ConfigMap

  1. $ kubectl edit configmap log-config

修改 log_level 的值为 DEBUG 等待大概10秒钟时间,再次查看环境变量的值

  1. $ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2` cat /etc/config/log_level
  2. DEBUG

ConfigMap更新后滚动更新Pod

更新ConfigMap目前并不会触发相关Pod的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新

  1. $ kubectl patch deployment my-nginx --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20190411"}}}}}'

这个例子里我们在 .spec.template.metadata.annotations 中添加 version/config ,每次通过修改 version/config 来触发滚动更新

!!!更新ConfigMap后:

  • 使用该 ConfigMap 挂载的 Env 不会同步更新
  • 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新

Secret

Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。
**
Secret有三种类型:

  • Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;
  • Opaque:base64 编码格式的 Secret,用来存储密码、密钥等;
  • kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。

Service Account

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

  1. $ kubectl run nginx --image nginx
  2. deployment "nginx" created
  3. $ kubectl get pods
  4. NAME READY STATUS RESTARTS AGE
  5. nginx-3137573019-md1u2 1/1 Running 0 13s
  6. $ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
  7. ca.crt
  8. namespace
  9. token

Opaque Secret

一、创建说明

Opaque类型的数据是一个map类型,要求value是base64编码格式:

  1. $ echo -n "admin" | base64
  2. YWRtaW4=
  3. $ echo -n "1f2d1e2e67df" | base64
  4. MWYyZDFlMmU2N2Rm

secrets.yml

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: mysecret
  5. type: Opaque
  6. data:
  7. password: MWYyZDFlMmU2N2Rm
  8. username: YWRtaW4=

接着,就可以创建secret了:kubectl create -f secrets.yml
创建好secret之后,有两种方式来使用它:

  • 以Volume方式
  • 以环境变量方式

    二、使用方式

    1、将Secret挂载到Volume中

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. labels:
    5. name: secret-test
    6. name: secret-test
    7. spec:
    8. volumes:
    9. - name: secrets
    10. secret:
    11. secretName: mysecret
    12. containers:
    13. - image: hub.atguigu.com/library/myapp:v1
    14. name: db
    15. volumeMounts:
    16. - name: secrets
    17. mountPath: "/etc/secrets"
    18. readOnly: true

    2、将Secret导出到环境变量中

    1. apiVersion: extensions/v1beta1
    2. kind: Deployment
    3. metadata:
    4. name: pod-deployment
    5. spec:
    6. replicas: 2
    7. template:
    8. metadata:
    9. labels:
    10. app: pod-deployment
    11. spec:
    12. containers:
    13. - name: pod-1
    14. image: hub.atguigu.com/library/myapp:v1
    15. ports:
    16. - containerPort: 80
    17. env:
    18. - name: TEST_USER
    19. valueFrom:
    20. secretKeyRef:
    21. name: mysecret
    22. key: username
    23. - name: TEST_PASSWORD
    24. valueFrom:
    25. secretKeyRef:
    26. name: mysecret
    27. key: password

    kubernetes.io/dockerconfigjson

    可以直接用kubectl命令来创建用于 docker registry 认证的 secret:
    1. $ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
    2. secret "myregistrykey" created.
    也可以直接读取~/.docker/config.json的内容来创建:
    1. $ cat ~/.docker/config.json | base64
    2. $ cat > myregistrykey.yaml <<EOF
    3. apiVersion: v1
    4. kind: Secret
    5. metadata:
    6. name: myregistrykey
    7. data:
    8. .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
    9. type: kubernetes.io/dockerconfigjson
    10. EOF
    11. $ kubectl create -f myregistrykey.yaml
    在创建Pod的时候,通过imagePullSecrets来引用刚创建的myregistrykey:
    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: foo
    5. spec:
    6. containers:
    7. - name: foo
    8. image: janedoe/awesomeapp:v1
    9. imagePullSecrets:
    10. - name: myregistrykey

Volumes

容器中的磁盘的生命周期是短暂的,这就带来了一系列的问题,第一,当一个容器损坏之后,kubelet 会重启这个容器,但是文件会丢失-这个容器会是一个全新的状态,第二,当很多容器在同一 Pod 中运行的时候,很多时候需要数据文件的共享。Kubernete Volume解决了这个问题

Background背景

Docker有一个Volumes的概念,虽然这个Volume有点宽松和管理性比较小。在Docker中,一个 Volume 是一个简单的所在主机的一个目录或者其它容器中的。生命周期是没有办法管理,直到最近才有 local-disk-backed 磁盘。Docker现在提供了磁盘驱动,但是功能非常有限(例如Docker1.7只能挂在一个磁盘每个容器,并且无法传递参数)

从另外一个方面讲,一个Kubernetes volume,拥有明确的生命周期,与所在的Pod的生命周期相同。因此,Kubernetes volume独立与任何容器,与Pod相关,所以数据在重启的过程中还会保留,当然,如果这个Pod被删除了,那么这些数据也会被删除。更重要的是,Kubernetes volume 支持多种类型,任何容器(Pod)都可以使用多个Kubernetes volume。

Types of Volumes

Kubernete 支持如下类型的 volume:
awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir fc flocker gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs persistentVolumeClaim projected portworxVolume quobyte rbd scaleIO secret storageos vsphereVolume

emptyDir

当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyoir 中的数据将被永久删除

注意:容器崩溃不会从节点中移除 pod, 因此, emptyDir 卷中的数据在容器崩溃时是安全的

emptyDir 的用法有:

  • 暂存空间,例如用于基于磁盘的合并排序
  • 用作长时间计算崩溃恢复时的检查点
  • Web 服务器容器提供数据时,保存内容管理器容器提取的文件
    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: test-pod
    5. spec:
    6. containers:
    7. - image: k8s.gcr.io/test-webserver
    8. name: test-container
    9. volumeMounts:
    10. - mountPath: /cache
    11. name: cache-volume
    12. volumes:
    13. - name: cache-volume
    14. emptyDir: {}

hostPath

hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中
hostPath 的用途如下:

  • 运行需要访问Docker内部的容器;使用 /var/lib/dockerhostPath
  • 在容器中运行 cAdvisor;使用 /dev/cgroupshostPath
  • 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在

除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type

行为
空字符串(默认)用于向后兼容,这意味着在挂载 hostPath卷之前不会执行任何检查。
DirectoryOrCreate 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权。
Directory 给定的路径下必须存在目录
FileOrCreate 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。
File 给定的路径下必须存在文件
Socket 给定的路径下必须存在UNIX套接字
CharDevice 给定的路径下必须存在字符设备
BlockDevice 给定的路径下必须存在块设备

使用这种卷类型时请注意,因为:

  • 由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同
  • 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源
  • 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷
    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: test-pd
    5. spec:
    6. containers:
    7. - image: k8s.gcr.io/test-webserver
    8. name: test-container
    9. volumeMounts:
    10. - mountPath: /test-pd
    11. name: cache-volume
    12. volumes:
    13. - name: cache-volume
    14. hostPath:
    15. # directory localtion on host
    16. path: /data
    17. # this field is optional
    18. type: Directory