downwardAPI存储卷

每个Pod在被成功创建出来以后,都会被系统分配唯一的名字,IP地址,并且处在某个namespace中,我们如何在Pod的容器内获取Pod的这些重要信息呢,答案就是使用DownwardAPI Downward API可用通过两种方式将Pod信息注入容器内部

  • 环境变量:用于单个变量,可用将Pod信息和container信息注入容器内部
  • Volume挂载: 将数组类信息生成为文件并挂载到容器内

很多时候,应用程序需要基于其所在的环境信息设定运行特性等,这类环境信息包括节点及集群的部分详细属性信息等,例如,Nginx进程可根据节点的CPU核心数量自动设定要启动的worker进程数,JVM虚拟机可根据节点内存资源自动设定其堆内存大小。类似的,托管运行于K8S的Pod对象中的容器化应用偶尔也需要获取其所属Pod对象的IP,主机名,标签,注解,UID,请求的CPU及内存资源量及其限额,甚至是Pod所在的节点名称等,容器可以通过环境变量或downwardAPI存储卷访问此类信息,不过,标签和注解仅支持通过存储卷暴露给容器

环境变量式元数据注入

引用downwardAPI元数据信息的常用方式之一是使用容器的环境变量,它通过在.spec.containers.env.valueFrom字段中嵌套fieldRefresourceFieldRef字段来引用相应的数据源。不过,通常只有常量类型的属性才能够通过环境变量注入到容器中,毕竟,在进程启动完成后将无法再向其告知变量值的变动,于是,环境变量也就不支持中途的更新操作 .spec.containers.env.valueFrom.fieldRef可引用的字段信息如下

  • .spec.nodeName: 节点名称
  • .status.hostIP: 节点IP
  • .metadata.name:: Pod对象的名称
  • metadata.namespace: Pod对象隶属的名称空间
  • status.podIP: Pod对象的IP地址
  • spec.serviceAccountName: Pod对象使用的ServiceAccount资源的名称
  • metadata.uid: Pod对象的UID
  • metadata.labels['<KEY>']: Pod对象标签中指定键的值,例如,metadata.labels[‘mylabel’]
  • metadata.annotations['<KEY>']: Pod对象注解信息中的指定键的值

另外,可通过resourceFieldRef字段引用的信息是指当前容器的资源请求及资源限额的定义,因此它们包括requests.cpulimits.cpurequests.memorylimits.memory四项

下面的资源配置清单示例(downwardAPI-env.yaml)中定义的Pod对象通过环境变量向容器myweb-nginx中注入了Pod对象的名称,隶属的名称空间,标签app的值以及容器自身的CPU资源限额和内存资源请求等信息

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: env-test-ward
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: myweb
  10. template:
  11. metadata:
  12. labels:
  13. app: myweb
  14. spec:
  15. containers:
  16. - name: myweb-nginx
  17. image: docker.io/ikubernetes/myapp:v2
  18. ports:
  19. - containerPort: 80
  20. name: http
  21. imagePullPolicy: IfNotPresent
  22. resources:
  23. requests:
  24. cpu: "125m"
  25. memory: "200Mi"
  26. limits:
  27. cpu: "250m"
  28. memory: "512Mi"
  29. command: ["/bin/sh","-c","env"]
  30. env:
  31. #注入节点名称
  32. - name: MY_NODE_NAME
  33. valueFrom:
  34. fieldRef:
  35. fieldPath: spec.nodeName
  36. #注入节点IP
  37. - name: MY_NODE_IP
  38. valueFrom:
  39. fieldRef:
  40. fieldPath: status.hostIP
  41. #注入Pod名称
  42. - name: MY_POD_NAME
  43. valueFrom:
  44. fieldRef:
  45. fieldPath: metadata.name
  46. #注入名称空间
  47. - name: MY_POD_NAMESPACE
  48. valueFrom:
  49. fieldRef:
  50. fieldPath: metadata.namespace
  51. #注入PodIP
  52. - name: MY_POD_IP
  53. valueFrom:
  54. fieldRef:
  55. fieldPath: status.podIP
  56. #注入标签信息
  57. - name: MY_APP_LABEL
  58. valueFrom:
  59. fieldRef:
  60. fieldPath: metadata.labels['app']
  61. #注入CPU资源最大限额信息
  62. - name: MY_CPU_LIMIT
  63. valueFrom:
  64. resourceFieldRef:
  65. resource: limits.cpu
  66. divisor: 1m
  67. #注入内存资源最大限额信息
  68. - name: MY_MEMORY_LIMIT
  69. valueFrom:
  70. resourceFieldRef:
  71. resource: limits.memory
  72. divisor: 1Mi
  73. #注入内存资源信息
  74. - name: MY_MEMORY_REQUEST
  75. valueFrom:
  76. resourceFieldRef:
  77. resource: requests.memory
  78. divisor: 1Mi
  79. #注入CPU资源请求信息
  80. - name: MY_CPU_REQUEST
  81. valueFrom:
  82. resourceFieldRef:
  83. resource: requests.cpu
  84. divisor: 1m

资源清单文件配置完成之后,即可创建Pod资源,该Pod资源创建完成之后,向控制台打印所有的环境变量就会终止运行,它仅用于测试通过环境变量注入信息到容器的使用效果

  1. [root@k8s-master01 pv]# kubectl apply -f downwardAPI-env.yaml
  2. deployment.apps/env-test-ward configured
  3. [root@k8s-master01 pv]#
  4. [root@k8s-master01 pv]# kubectl get pods -l app=myweb
  5. NAME READY STATUS RESTARTS AGE
  6. env-test-ward-568f44db9b-ckg97 0/1 Completed 0 3s
  7. [root@k8s-master01 pv]#

而后可通过控制台日志获取注入的环境变量

  1. [root@k8s-master01 pv]# kubectl logs env-test-ward-568f44db9b-ckg97 |grep "^MY"
  2. MY_MEMORY_REQUEST=200
  3. MY_NODE_IP=172.18.15.113
  4. MY_POD_NAMESPACE=default
  5. MY_POD_IP=10.244.59.2
  6. MY_CPU_LIMIT=1
  7. MY_APP_LABEL=myweb
  8. MY_MEMORY_LIMIT=512
  9. MY_NODE_NAME=172.18.15.113
  10. MY_CPU_REQUEST=1
  11. MY_POD_NAME=env-test-ward-568f44db9b-ckg97
  12. [root@k8s-master01 pv]#

如示例中类似硬件资源的环境表里所示,在定义资源请求或资源限制时还可以额外指定一个”divisor”字段,用于为音容的值指定一个除数以事先所引用的相关值的单位换算。CPU资源的divisor字段其默认值为1,表示为1个核心,相除的结果不足1个单位时则向上圆整(例如,0.25向上圆整的结果为1),它的另外一个可用单位为1m,即表示1个微核心。内存资源的divisor字段其默认值为也是1,不过,它意指1个字节。其他可用的单位还有1Ki,1Mi,1Gi等,于是,在将divisor字段的值设置为1Mi时,200Mi的内存资源的换结果为200

如果没有未容器定义资源请求及资源限额时,downwardAPI引用的值即默认为节点的可分配CPU及内存资源量

存储卷式元数据注入(volume挂载)

向容器注入元数据信息的另一种方式是使用downwardAPI存储卷,它将配置的字段数据映射为文件并可通过容器中的挂载点进行访问。之前章节中通过环境变量的方式注入的元数据信息也都可用使用存储卷的方式进行信息暴漏,初次之外,还可用在downwardAPI存储卷中使用fieldRef引用如下两个数据源

  • .metadata.labels: Pod对象的所有标签信息,每行一个,格式为label-key=”escaped-label-value”
  • .metadata.annotations: Pod对象的所有注解信息,每行一个,格式为annotations-key=”escaped-annotations-value”

下面的资源清单配置示例(downwardAPI-vol.yaml)中定义的Pod对象通过downwardAPI存储卷向容器dapi-nginx中注入了Pod对象隶属的名称空间,标签,注解以及容器自身的CPU资源限额和内存资源请求等信息。存储卷在容器中的挂载点为/etc/podinfo目录,因此,注入的每一项信息均会映射为此路径下的一个文件

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: vol-downward
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: dapi-vol-web
  10. zone: east-china
  11. env: stable
  12. template:
  13. metadata:
  14. labels:
  15. app: dapi-vol-web
  16. zone: east-china
  17. env: stable
  18. annotations:
  19. annotation1: "test-volumes1"
  20. spec:
  21. containers:
  22. - name: dapi-nginx
  23. image: docker.io/ikubernetes/myapp:v2
  24. ports:
  25. - containerPort: 80
  26. name: http
  27. imagePullPolicy: IfNotPresent
  28. resources:
  29. requests:
  30. cpu: "100m"
  31. memory: "200Mi"
  32. limits:
  33. cpu: "200m"
  34. memory: "400Mi"
  35. volumeMounts:
  36. - name: podinfo
  37. mountPath: /etc/podinfo
  38. readOnly: false
  39. volumes:
  40. - name: podinfo
  41. downwardAPI:
  42. defaultMode: 420
  43. items:
  44. - path: pod_namespace
  45. fieldRef:
  46. fieldPath: metadata.namespace
  47. - path: pod_labels
  48. fieldRef:
  49. fieldPath: metadata.labels
  50. - path: pod_annotations
  51. fieldRef:
  52. fieldPath: metadata.annotations
  53. - path: cpu_limit
  54. resourceFieldRef:
  55. containerName: dapi-nginx
  56. resource: limits.cpu
  57. - path: memory_limit
  58. resourceFieldRef:
  59. containerName: dapi-nginx
  60. resource: limits.memory
  61. divisor: 1Mi
  62. - path: cpu_request
  63. resourceFieldRef:
  64. containerName: dapi-nginx
  65. resource: requests.cpu
  66. - path: memory_request
  67. resourceFieldRef:
  68. containerName: dapi-nginx
  69. resource: requests.memory
  70. divisor: 1Mi

创建完资源配置清单中定义的Pod对象后即可测试访问由downwardAPI存储卷映射的文件pod_namespace、pod_labels、pod_annotations、cpu_limit和memory_request等

  1. [root@k8s-master01 pv]# kubectl apply -f downwardAPI-vol.yaml
  2. deployment.apps/vol-downward created
  3. [root@k8s-master01 pv]#
  4. [root@k8s-master01 pv]# kubectl get pods -l "env=stable"
  5. NAME READY STATUS RESTARTS AGE
  6. vol-downward-556f6948cc-zq79w 1/1 Running 0 4m52s
  7. [root@k8s-master01 pv]#

Pod处于running状态之后,即可测试访问上述的映射文件

  1. [root@k8s-master01 pv]# kubectl exec vol-downward-556f6948cc-zq79w -- cat /etc/podinfo/pod_labels
  2. app="dapi-vol-web"
  3. env="stable"
  4. pod-template-hash="556f6948cc"
  5. zone="east-china"[root@k8s-master01 pv]#
  6. [root@k8s-master01 pv]# kubectl exec vol-downward-556f6948cc-zq79w -- cat /etc/podinfo/memory_request
  7. 200
  8. [root@k8s-master01 pv]#
  9. [root@k8s-master01 pv]# kubectl exec vol-downward-556f6948cc-zq79w -- cat /etc/podinfo/memory_limit
  10. 400
  11. [root@k8s-master01 pv]#
  12. [root@k8s-master01 pv]# kubectl exec vol-downward-556f6948cc-zq79w -- cat /etc/podinfo/cpu_limit
  13. 1
  14. [root@k8s-master01 pv]#

如命令结果所示,Pod对象的标签信息每行一个的映射于自定义的路径/etc/podinfo/pod_labels文件中,类似的,注解信息也以这种方式进行处理。如前面的文章中所述,标签和注解支持运行时修改,其改动的结果也会实时映射进downwardAPI生成的文件中。例如,为vol-downward-556f6948cc-zq79w添加新的标签

  1. [root@k8s-master01 pv]# kubectl label pod vol-downward-556f6948cc-zq79w idc="sh"
  2. pod/vol-downward-556f6948cc-zq79w labeled
  3. [root@k8s-master01 pv]#

而后再次查看容器内的pod_labels文件的内容,由如下的命令结果可知新的标签已经能够通过相关的文件获取到

  1. [root@k8s-master01 pv]# kubectl exec vol-downward-556f6948cc-zq79w -- cat /etc/podinfo/pod_labels
  2. app="dapi-vol-web"
  3. env="stable"
  4. idc="sh"
  5. pod-template-hash="556f6948cc"
  6. zone="east-china"
  7. [root@k8s-master01 pv]#

downwardAPI存储卷为K8S上运行容器化应用提供了获取额外环境信息的有效途径,这一点对那些非为云原生开发的应用程序在不进行代码重构的前提下,获取环境信息进行自身配置等操作时尤为有用