Z.S.K.'s Records

Kubernetes学习(kubernetes中的反射模式(DownwardAPI))

该文章为翻译文档, 主要在阐述kubernetes中的DownwardAPI的作用, 这里是原文地址

什么是“反射”?

反射是大多数(不是全部)编程语言中都可以使用的概念。它只是指某种对象揭示其自身重要信息的能力。例如,它的名称,它的父类以及它包含的任何元数据。在Cloud和DevOps领域中具有相同的概念。例如,如果您登录到AWS EC2实例,则可以通过从以下位置发出GET请求到http://169.254.169.254/latest/meta-data/来轻松获取有关该特定实例的大量信息。

为什么我们需要反射?

对象的能用术语指的是工作单元。因此,在编程语言中,对象是类的实例,在内部部署基础结构中,对象可以是物理或虚拟主机,在云环境中,它是实例,而在Kubernetes中,它是Pod 。

在本文中,我们对Kubernetes感兴趣,因此Pod和object可以互换使用。

在许多情况下,您需要Pod的元数据,尤其是在该Pod是无状态应用程序的一部分的情况下,其中Pod本质上是动态的。让我们看一些可能的情况:

  • 您需要Pod的IP地址,以识别它是否是网络上检测到的可疑流量的来源。
  • 在容器内运行的应用程序需要知道Pod在其中运行的名称空间,这可能是因为该程序被编程为根据名称空间所传达的运行环境而有所不同。
  • 您需要知道限制容器当前资源限制(CPU和内存)。例如,您可以进一步使用此数据在启动Java应用程序时自动调整其堆大小。

幸运的是,Kubernetes通过使用Downward API使这项任务相对容易。

DownwardAPI是如何工作?

Downward API通过环境变量和文件将元数据注入到容器中。它们的使用方式与configMaps和Secrets一样,用于处理将外部信息传递给应用程序的情况。但是,Downward API不会将所有可用的元数据注入到容器中。相反,我们选择需要对容器可用的变量。

让我们举个例子以便更好地理解。以下定义文件创建一个Pod,该Pod从bash映像运行容器。我们使用Downward API注入三个可用变量:Pod的IP地址,此Pod运行所在的名称空间以及对其施加的当前内存限制。下图可以描述这种情况:

反射

了解如何持续优化您的k8s集群

定义文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- image: bash
name: mycontainer
command: ['bash','-c','sleep 1000000']
env:
- name: MY_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: mycontainer
resource: limits.memory
divisor: 1Mi

让我们使用kubectl apply -f filename运行此定义,然后访问Pod内的容器,看看我们的元数据是否可用:

1
2
3
4
5
6
7
8
9
$ kubectl exec -it mypod bash
bash-5.0# echo MY_IP
MY_IP
bash-5.0# echo $MY_IP
172.17.0.4
bash-5.0# echo $MY_NAMESPACE
default
bash-5.0# echo $MY_MEMORY_LIMIT
1900

因此,我们可以通过查询相应的环境变量MY_IP,MY_NAMESPACE和MY_MEMORY_LIMIT来获取运行此Pod的IP地址和命名空间。

FieldRef

在第一个示例中,我们使用fieldRef参数来选择需要通过fieldPath注入到Pod中的信息。以下是通过fieldRef可用的可能值的列表:

Name Description
spec.nodename The name of the node where the Pod is running.
status.hostIP The IP address of the node where the Pod us running.
metadata.name The Pod name (notice that this is different than the container’s name. A Pod may have more than one container)
metadata.namespace The namespace of the Pod
status.podIP The IP address of the Pod
spec.serviceAccountName The service account that was used with the Pod.
metadata.uid The UID of the running Pod
metadata.labels[‘label‘] The value of the label put on the Pod. For example, if a Pod is labeled env=prod, then metadata.labels[‘env’] returns ‘prod’.
metadata.annotations[‘annotation’] Similar to labels, it gets the value of the specified annotation.

ResourceFieldRef

fieldRef参数允许您注入有关Pod的元数据。如果需要有关Pod消耗的资源(即CPU和内存)的数据,则应使用resourceFieldRef。以下是可用于获取此数据的可用选项的列表:

Name Description
requests.cpu The amount of CPU specified in the requests field of the Pod definition
requests.memory The amount of memory specified in the requests field of the Pod definition
limits.cpu The CPU limit of the Pod
limits.memory The memory limit of the Pod

可以在其定义文件内的Pod上添加requests和limits。它们都允许您控制给定Pod可以消耗多少资源的硬性限制和软性限制。它们还帮助调度程序根据其资源请求和限制将Pod分配给适当的节点。有关此主题的更多信息,您可以参考我们的容量规划文章。

在修改它们之后获取Pod元数据

在Pod运行时,允许Kubernetes用户更改Pod的某些元数据。因此,否则无法更改诸如资源请求和限制之类的字段是无法修改的, 除非删除Pod, 但可以更改Pod标签。如果用户发出了kubectl edit pod pod_name命令,则只要该字段接受,他们就可以对Pod定义进行动态修改。

如果Pod的元数据已动态更改,则无法通过环境变量将它们重新注入到容器中,因为这需要重新启动容器。但是,您仍然可以通过使用将数据注入到容器中的另一种方法(卷)来监视和捕获这些更改。

以下定义演示了如何使用与configMaps和Secrets一起使用卷的方式相同的卷,以允许容器访问数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
env: prod
spec:
containers:
- image: bash
name: mycontainer
command: ['bash','-c','sleep 1000000']
volumeMounts:
- name: mypod-vol
mountPath: /mypod-metadata
volumes:
- name: mypod-vol
downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labels
- path: annotations
fieldRef:
fieldPath: metadata.annotations

应用此定义并登录到Pod,我们可以看到已经为我们安装了包含相关数据的卷:

1
2
3
4
5
title: Kubernetes学习(使用PodSecurityPolicy)
comments: flase
date: 2019-12-13 17:10:53
tags: Kubernetes
categories: Kubernetes

如您所见,我们通过存储在卷上的文件而不是环境变量来获取数据。这使我们能够在信息变化的任何地方动态地检索信息,而无需重新启动容器。但是,仍需要对正在运行的应用程序进行配置,以检测标签或注释文件中的更改(如果正在使用其值),并在进行修改时采取相应的措施。

  • 在很多情况下,您需要应用程序了解运行它的基础结构的某些元数据。应用程序可以使用此信息来做出明智的决定或使手动任务自动化。
  • Kubernetes提供了Downward API,该API允许您将其中一些元数据注入Pod,并使其中的容器可以访问它们。
  • Downward API允许您在API服务器上查询许多元数据项以及资源请求和限制。
  • 您可以通过环境变量或安装卷将所需的信息注入Pod。
  • 使用环境变量的不利之处在于它们无法反映对Pod的元数据(如标签和注释)的动态更改。您可以将卷用作解决方法。
  • 尽管Downward API是实现Pod反射的一种优雅方法,但它仍然可以提供的数据量受到限制。还有其他Pod方面可能需要通过Downward API提供,而其他方面则不提供。解决此缺点的方法是让应用程序直接查询API服务器以获取丢失的数据。许多编程语言中都有许多客户端库,使您可以通过代码查询API服务器。
Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?