Some applications need to be self-aware and require information about themselves. The Self Awareness pattern describes the Kubernetes Downward API that provides a simple mechanism for introspection and metadata injection to applications.
For the majority of use cases, cloud-native applications are stateless and disposable without an identity relevant to other applications. However, sometimes even these kinds of applications need to have information about themselves and the environment they are running in. That may include information known only at runtime, such as the Pod name, Pod IP address, and the hostname on which the application is placed. Or, other static information defined at Pod level such as the specific resource requests and limits, or some dynamic information such as annotations and labels that could be altered by the user at runtime.
For example, depending on the resources made available to the container, you may want to tune the application thread-pool size, or change the garbage collection algorithm or memory allocation. You may want to use the Pod name and the hostname while logging information, or while sending metrics to a central server. You may want to discover other Pods in the same namespace with a specific label and join them into a clustered application. For these and other use cases, Kubernetes provides the Downward API.
The requirements that we’ve described and the following solution are not specific only to containers but are present in any dynamic environment where the metadata of resources changes. For example, AWS offers Instance Metadata and User Data services that can be queried from any EC2 instance to retrieve metadata about the EC2 instance itself. Similarly, AWS ECS provides APIs that can be queried by the containers and retrieve information about the container cluster.
The Kubernetes approach is even more elegant and easier to use. The Downward API allows passing metadata about the Pod to the containers and the cluster through environment variables and files. These are the same mechanisms we used for passing application-related data from ConfigMaps and Secrets. But in this case, the data is not created by us. Instead, we specify the keys that interests us, and Kubernetes populates the values dynamically. Figure 13-1 gives an overview of how the Downward API injects resource and runtime information into interested Pods.
The main point here is that with the Downward API, the metadata is injected into your Pod and made available locally. The application does not need to use a client and interact with the Kubernetes API and can remain Kubernetes-agnostic. Let’s see how easy it is to request metadata through environment variables in Example 13-1.
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
random-generator
spec
:
containers
:
-
image
:
k8spatterns/random-generator:1.0
name
:
random-generator
env
:
-
name
:
POD_IP
valueFrom
:
fieldRef
:
fieldPath
:
status.podIP
-
name
:
MEMORY_LIMIT
valueFrom
:
resourceFieldRef
:
container
:
random-generator
resource
:
limits.memory
In this example we use fieldRef
to access Pod-level metadata. The keys shown in Table 13-1 are available for fieldRef.fieldPath
both as environment variables and downwardAPI
volumes.
Name | Description |
---|---|
|
Name of node hosting the Pod |
|
IP address of node hosting the Pod |
|
Pod name |
|
Namespace in which the Pod is running |
|
Pod IP address |
|
ServiceAccount that is used for the Pod |
|
Unique ID of the Pod |
|
Value of the Pod’s label key |
|
Value of the Pod’s annotation key |
Similarly to fieldRef
, we can use resourceFieldRef
to access metadata specific to a
container belonging to the Pod.
This metadata is specific to a container which can be specified with resourceFieldRef.container
. When used as environment variable then by default the current container is used. The possible keys for resourceFieldRef.resource
are shown in Table 13-2.
Name | Description |
---|---|
|
A container’s CPU request |
|
A container’s CPU limit |
|
A container’s memory request |
|
A container’s memory limit |
A user can change certain metadata such as labels and annotations while a Pod is running. Unless the Pod is restarted, environment variables will not reflect such a change. But downwardAPI
volumes can reflect updates to labels and annotations. In addition to the individual fields described previously, downwardAPI
volumes can capture all Pod labels and annotations into files with metadata.labels
and metadata.annotations
references. Example 13-2 shows how such volumes can be used.
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
random-generator
spec
:
containers
:
-
image
:
k8spatterns/random-generator:1.0
name
:
random-generator
volumeMounts
:
-
name
:
pod-info
mountPath
:
/pod-info
volumes
:
-
name
:
pod-info
downwardAPI
:
items
:
-
path
:
labels
fieldRef
:
fieldPath
:
metadata.labels
-
path
:
annotations
fieldRef
:
fieldPath
:
metadata.annotations
With volumes, if the metadata changes while the Pod is running, it is reflected in the volume files. But it is still up to the consuming application to detect the file change and read the updated data accordingly. If such a functionality is not implemented in the application, a Pod restart still might be required.
On many occasions, an application needs to be self-aware and have information about itself and the environment in which it is running. Kubernetes provides nonintrusive mechanisms for introspection and metadata injection. One of the downsides of the Downward API is that it offers a fixed number of keys that can be referenced. If your application needs more data, especially about other resources or cluster-related metadata, it has be queried on the API Server.
This technique is used by many applications that query the API Server to discover other Pods in the same namespace that have certain labels or annotations. Then the application may form a cluster with the discovered Pods and sync state, for example. It is also used by monitoring applications to discover Pods of interest and then start instrumenting them.
Many client libraries are available for different languages to interact with the Kubernetes API Server to obtain more self-referring information that goes beyond what the Downward API provides.