应用往往需要获取所运行环境的一些信息,包括应用自身以及集群中其他组件的信息。Kubernetes可以通过环境变量以及DNS进行服务发现,但其他信息如何处理呢?下面将介绍特定pod和容器元数据如何被传递到容器,了解在容器中运行的应用如何便捷地与Kubernetes API服务器进行交互,从而获取在集群中部署资源的信息,并且进一步了解如何创建和修改这些资源。

1.通过Downward API传递元数据

  Kubernetes可以环境变量或者configMap和secret卷向应用传递配置数据。这对于pod调度、运行前预设的数据是可行的。但是对于那些不能预先知道的数据,比如pod的IP、主机名或者是pod自身的名称(当名称被生成,比如当pod通过ReplicaSet或类似的控制器生成时)呢?此外,对于那些己经在别处定义的数据,比如pod的标签和注解呢?不想在多个地方重复保留同样的数据。

  对于此类问题,可以通过使用Kubernetes Downward API解决。Downward API允许通过环境变量或者文件(在downwardAPI卷中)的传递pod的元数据。不要对这个名称产生困惑,Downward API的方式并不像REST endpoint那样需要通过访问的方式获取数据。这种方式主要是将在pod的定义和状态中取得的数据作为环境变量和文件的值。

1.1 了解可用元数据

  Downward API可以给在pod中运行的进程暴露pod的元数据。目前可以给容器传递以下数据:

    • pod的名称
    • pod的IP
    • pod所在的命名空间
    • pod运行节点的名称
    • pod运行所归属的服务账户的名称 •每个容器请求的CPU和内存的使用量
    • 每个容器可以使用的CPU和内存的限制
    • pod的标签
    • pod的注解

  这个清单中所列举的大部分项目,除了服务账户、CPU和内存的请求和限制概念,其他都无须进一步解释。其它篇章讲解。现在需了解,服务账户是pod访问API服务器时用来进行身份验证的账户。

  列表中的大部分项目既可以通过环境变量也可以通过downwardAPI卷传递给容器,但是标签和注解只可以通过卷暴露。部分数据可以通过其他方式获取(例如,可以直接从操作系统获取),但是DownwardAPI提供了一种更加便捷的方式。

  来看一个向容器化的进程传递元数据的例子。

1.2 通过环境变量暴露元数据

  首先了解如何通过环境变量的方式将pod和容器的元数据传递到容器中。根据如下列出的manifest创建一个简单的单容器。

代码8.1 在环境变量中使用downwardAPI: downward-api-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: downward
spec:
containers:
- name: main
image: busybox
command: ["sleep", "9999999"]
resources:
requests:
cpu: 15m
memory: 100Ki
limits:
cpu: 100m
memory: 4Mi
env:
- name: POD_NAME #引用pod manifest中的元数据名称字段,而不是设定一个具体的值
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: CONTAINER_CPU_REQUEST_MILLICORES #容器请求的CPU和内存使用量是引用resourceFieldRef字段,而不是fieldRef字段
valueFrom:
resourceFieldRef:
resource: requests.cpu
divisor: 1m #对于资源相关的字段,定义一个基数单位,从而生成每一部分的值
- name: CONTAINER_MEMORY_LIMIT_KIBIBYTES
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Ki

  当进程在运行时,它可以获取所有在pod的定义文件中设定的环境变量。图8-2展示了所有的环境变量以及变量值的来源。pod的名称、IP和命名空间可以通过pod_NAME、pod_IP和pod_NAMESPACE这几个环境变量分别暴露。容器运行的节点的名称可以通过NODE_NAME变量暴露。同样,服务账户可以使用环境变量SERVICE_ACCOUNT。也可以创建两个环境变量来保存容器请求使用的CPU的数量,以及容器被最大允许使用的内存数量。

  对于暴露资源请求和使用限制的环境变量,可以会设定一个基数单位。实际的资源请求直和限制直除以这个基数单位,所得的结果通过环境变量暴露出去。在前面的例子中,设定CPU请求的基数为1m(即1 millicore,也就是千分之一核CPU)。当设置资源请求15m时,环境变量CONTAINER_CPU_REQUEST_MILLICORES的值就是15。同样,我们设定内存的使用限制为4Mi(4 mebibytes),设定基数为1Ki(l Kbibyte),则环境变量 CONTAINER_MEMORY_LIMIT_KIBIBYTES的值就是 4096。

  对于CPU资源请求量和使用限制可以被设定为1,也就意味着整颗CPU的计算能力,也可以设定为1m,即千分之一核的计算能力。对于内存的资源请求和使用限制可以设定为1 (字节),也可以是1k(kilobute)或1Ki (kbibute),同样也可以设为1M (megavyte)或者1Mi(mebibyte),等等。

  在完成创建pod后,可以使用kubectl exec命令来查看容器中的所有环境变量,如下面的代码清单所示。

代码 8.2 downward pod中的环境变量
$ kubectl exec downward env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=downward
CONTAINER_MEMORY_LIMIT_KIBIBYTES=4096
POD_NAME=downward
POD_NAMESPACE=default
POD_IP=10.0.0.10
NODE_NAME=gke-kubia-default-pool-32a2cac8-sgl7
SERVICE_ACCOUNT=default
CONTAINER_CPU_REQUEST_MILLICORES=15
KUBERNETES_SERVICE_HOST=10.3.240.1
KUBERNETES_SERVICE_PORT=443

  所有在这个容器中运行的进程都可以读取并使用它们需要的变量。

1.3 通过downwardAPI卷来传递元数据

  如果更倾向于使用文件的方式而不是环境变量的方式暴露元数据,可以定义一个downwardAPI卷并挂载到容器中。由于不能通过环境变量暴露,所以必须使用downwardAPI卷来暴露pod标签或注解。为什么不能后面讨论原因。

  与环境变量一样,需要显示地指定元数据字段来暴露份进程。下面我们将把前面的示例从使用环境变量修改为使用存储卷,如下面的代码清单所示。

#代码8.3 —个带有downwardAPi卷的pod示例:downward-api-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: downward
labels:
foo: bar
annotations: #通过downwardAPI卷来暴露这些标签和注解
key1: value1
key2: |
multi
line
value
spec:
containers:
- name: main
image: busybox
command: ["sleep", "9999999"]
resources:
requests:
cpu: 15m
memory: 100Ki
limits:
cpu: 100m
memory: 4Mi
volumeMounts: #在/etc/downward目录下挂载这个downward卷
- name: downward
mountPath: /etc/downward
volumes:
- name: downward #通过将卷名字设定为downward来定义一个downwardAPI卷
downwardAPI:
items:
- path: "podName" #pod的名称(来自manifest文件中的metadata.name字段)将被写入podName中
fieldRef:
fieldPath: metadata.name
- path: "podNamespace"
fieldRef:
fieldPath: metadata.namespace
- path: "labels" #pod的标签将被保存到/etc/downward/labels文件中
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
- path: "containerCpuRequestMilliCores"
resourceFieldRef:
containerName: main
resource: requests.cpu
divisor: 1m
- path: "containerMemoryLimitBytes"
resourceFieldRef:
containerName: main
resource: limits.memory
divisor: 1

  现在没有通过环境变量来传递元数据,而是定义了一个叫作downward的卷,并且通过/etc/downward目录挂载到我们的容器中。卷所包含的文件会通过卷定义中的downwardAPI.items属性来定义。

  对于想要在文件中保存的每一个pod级的字段或者容器资源字段,都分别在downwardAPI.items中说明了元数据被保存和引用的path(文件名),如图8.3所示。

  从之前列表的manifest中删除原来的pod,并且新建一个pod。然后查看己挂载到downwardAPI卷目录的内容,存储卷被挂载在/etc/downward/目录下,列出目录中的文件,如下面的代码清单所示。

#代码8.4 downwordAPI卷中的文件
$ kubectl exec downward ls -lL /etc/downward
-rw-r- -r-- 1 root root 134 May 25 10:23 annotations
-rw-r- -r-- 1 root root 2 May 25 10:23 containerCpuRequestMilliCores
-rw-r- -r-- 1 root root 7 May 25 10:23 containerMemoryLimitBytes
-rw-r- -r-- 1 root root 9 May 25 10:23 labels
-rw-r- -r-- 1 root root 8 May 25 10:23 podName
-rw-r- -r-- 1 root root 7 May 25 10:23 podNamespace

  注意:与configMAp和secret卷一样,可以通过pod定义中downwardAPI卷的defaultMode属性来改变文件的访问权限设置。

  每个文件都对应了卷定义中的一项。文件的内容与之前例子中的元数据字段和值,这里不再重复展示。不过由于不能通过环境变量的方式暴露label和annotation,所以看一下暴露的这两个文件的代码清单。

#代码8.5 展示 downwardAPI卷中的标签和注解
$ kubectl exec downward cat /etc/downward/labels
foo="bar"
$ kubectl exec downward cat /etc/downward/annotations
key1="value1"
key2="multi\nline\nvalue\n"
kubernetes.io/config.seen="2016-11-28T14:27:45.664924282Z"
kubernetes.io/config.source="api"

  正如上面看到的,每一个标签和注解都以key=value的格式保存在单独的行中,如对应多个值,则写在同一行,并且用回车符\n连接。

  修改标签和注解

  可以在pod运行时修改标签和注解。当标签和注解被修改后, Kubernetes会更新存有相关信息的文件,从而使pod可以获取最新的数据。这也解释了为什么不能通过环境变量的方式暴露标签和注解,在环境变量方式下,一旦标签和注解被修改,新的值将无法暴露。

  在卷的定义中引用容器级的元数据

  需要说明一点,当暴露容器级的元数据时,如容器可使用的资源限制或者资源请求(使用字段resourceFieldRef),必须指定引用资源字段对应的容器名称,如下面的代码清单所示。

#代码8.6 在downwardAPI卷中引用容器级的元数据
spec:
volumes:
- name: downward
downwardAPI:
items:
- path: "containerCpuRequestMilliCores"
resourceFieldRef:
containerName: main #必须制定容器名称
resource:requests.cpu
divisor: 1m

  这样做的理由很明显,因为对于卷的定义是基于pod级的,而不是容器级的。 当我们引用卷定义某一个容器的资源字段时,我们需要明确说明引用的容器的名称。这个规则对于只包含单容器的pod同样适用。

  使用卷的方式来暴露容器的资源请求和使用限制比环境变量的方式稍显复杂, 但好处是如果有必要,可以传递一个容器的资源字段到另一个容器(当然两个容器必须处于同一个pod)。使用环境变量的方式,一个容器只能传递它自身资源申请求和限制的信息。

  何时使用Dowanward API方式

  Downward API方式并不复杂,它使得应用独立于Kubernetes。这一点在处理部分数据己在环境变量中的现有应用时特别有用。 Downward API方式使得我们不必通过修改应用,或者使用shell脚本获取数据再传递给环境变量的方式来暴露数据。

  不过通过Downward API的方式获取的元数据是相当有限的,如果需要获取更多的元数据,需要使用直接访问Kubernetes API服务器的方式。在与KubernetesAPI服务器交互章中讲解。

Kubernetes通过downwardAPI传递元数据的更多相关文章

  1. Kubernetes学习笔记(七):访问Pod元数据与Kubernetes API

    Downward API 我们已经了解到,使用ConfigMap和Secret向应用传递配置数据,这对于运行前预设的数据是可行的.但是对于那些不能预先知道的,就需要使用Downward API. Do ...

  2. 从应用访问Pod元数据-DownwardApi的应用

    对于某些需要调度之后才能知道的数据,比如 pod 的 ip,主机名,或者 pod 自身的名称等等,k8s 依旧很贴心的提供了 Downward API 的方式来获取此类数据,并且可以通过环境变量或者文 ...

  3. Kubernetes排错:用容器的元数据提供新思路

    在这篇文章中,让我们讨论一下Kubernetes中的元数据(Metadata),以及如何利用它来监控系统的性能. 元数据(Metadata) 是一个较为高大上的词.它的含义是"用来描述其他数 ...

  4. 【译】Asp.net core应用在 Kubernetes上内存使用率过高问题分析

    原文:https://blog.markvincze.com/troubleshooting-high-memory-usage-with-asp-net-core-on-kubernetes/ ps ...

  5. WCF 之 生成元数据和代理

    在WCF开发概述中讲解了手工方式的WCF应用,其实实际开发中使用更多的使用配置方式和元数据来实现WCF,下面我们来看一个具体的Demo,这个例子和WCF开发概述中使用的是同一个例子,只是实现方式不同, ...

  6. Rancher 2.3实现K8S一键式升级!再也不用同步升级Rancher啦!

    在Rancher 2.3之前,Rancher的新版本总是随着Kubernetes的新版本一起发布,如果你想要使用最新版本的Kubernetes,那么你需要先升级Rancher才能使用.Rancher ...

  7. [目录]Pentaho Kettle解决方案:使用PDI构建开源ETL解决方案

    第一部分:开始 1         ETL入门 1.1   OLTP和数据仓库对比 1.2   ETL是什么 1.2.1          ETL解决方案的演化过程 1.2.2          ET ...

  8. pandas教程1:pandas数据结构入门

    pandas是一个用于进行python科学计算的常用库,包含高级的数据结构和精巧的工具,使得在Python中处理数据非常快速和简单.pandas建造在NumPy之上,它使得以NumPy为中心的应用很容 ...

  9. Django---->视图(View)

    视图层之路由配置系统(views) URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于这个 ...

随机推荐

  1. SQL中那么多函数,Java8为什么还要提供重复的Stream方法,多此一举?

    有个同学提出一个这样的疑问; 在业务系统中,数据一般都从sql中查询,类似使用where,order by,limit,聚合函数等,为什么还要用java8的Stream方法? 对这个问题,大家有什么见 ...

  2. java集合-数组ArrayList

    1.简介 ArrayList是java集合框架常用的集合类之一,底层是基于数组来实现容量大小动态变化的. 2.类图(JDK 1.8) 下图是ArrayList实现的接口和继承的类关系图: public ...

  3. Envoy :V3APi 开启 TLS

    方案架构 本次实例与官方Envoy front_proxy Example相似,首先会有一个Envoy单独运行.ingress的工作是给其他地方提供一个入口.来自外部的传入连接请求到这里,前端代理将会 ...

  4. [OS] 汇编语言

    操作系统 每个进程拥有一片连续的内存空间(地址空间),空间中的每个字节都可以用一个32位无符号整数定位,每个字节的位置称为地址 CPU 32位:能够处理的数据最大为32bit,地址空间2^32< ...

  5. 服务器硬件必须支持M2 或PCIE才能支持NVME

    兆芯服务器不支持NVME. 服务器硬件必须支持M2 或PCIE才能支持NVME.1 因为物理接口只有M2 SATA 和PCIE这三中但是NVME只支持M2 和PCIE这2种2所以 NVME不支持SAT ...

  6. mitogen附带文件到远程主机

    #!/usr/bin/env python # import mitogen.master import mitogen.select import subprocess import logging ...

  7. YAML/YML文件一直提示格式错误解决方法

    第一次接触yml文件,各种格式报错,但是看了几次也没看出来.其实有一个好方法,那就是直接通过yml在线格式检查 可以将yml具体内容复制到以下网址进行查询.具体报错位置会更加详细 https://ww ...

  8. IT菜鸟之OSI七层模型

    OSI七层模型从下到上分别是: 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 第一层物理层: 物理层是传输媒介(网线.无线.光纤) 在线路中起到的作用:是将0/1转换成电信号或光信号 物 ...

  9. mysql基础之数据库变量(参数)管理

    数据库的数据存放路径:[root@ren7 mysql]# pwd /var/lib/mysql [root@ren7 mysql]# ls aria_log.00000001 ibdata1 mul ...

  10. .NET6系列:微软正式宣布Visual Studio 2022

    系列目录     [已更新最新开发文章,点击查看详细] 首先,我们要感谢正在阅读这篇文章的你,我们所有的产品开发都始于你也止于你,无论你是在开发者社区上发帖,还是填写了调查问卷,还是向我们发送了反馈意 ...