In this chapter, we present recipes that address the basic interaction with Kubernetes objects as well as the API. Every object in Kubernetes, no matter if namespaced like a deployment or cluster-wide like a node, has certain fields available—for example, metadata
, spec
, and status
.1 The spec
describes the desired state for an object (the specification), and the status
captures the actual state of the object, managed by the Kubernetes API server.
You want to discover the various API endpoints available on the Kubernetes API server.
If you have access to the API server via an unauthenticated private port, you can directly issue HTTP requests to the API server and explore the various endpoints. For example, with Minikube, you can ssh
inside the virtual machine (minikube ssh
) and reach the API server on port 8080, as shown here:
$ curl localhost:8080/api/v1 ... { "name": "pods", "namespaced": true, "kind": "Pod", "verbs": [ "create", "delete", "deletecollection", "get", "list", "patch", "proxy", "update", "watch" ], "shortNames": [ "po" ] }, ...
In this listing you see an example of an object of kind Pod
as well as the allowed operations on this subject, such as get
and delete
.
Alternatively, if you don’t have direct access to the machine the Kubernetes API server is running on, you can use kubectl
to proxy the API locally. This will allow you to reach the API server locally, but using an authenticated session:
$ kubectl proxy --port=8001 --api-prefix=/
And then in another window, do this:
$ curl localhost:8001/foobar
The use of the /foobar
API path allows you to list all the API endpoints.
Note that both --port
and --api-prefix
are optional.
When discovering the API endpoints, you will see different ones, like:
/api/v1
/apis/apps
/apis/authentication.k8s.io
/apis/authorization.k8s.io
/apis/autoscaling
/apis/batch
Each of these endpoints corresponds to an API group. Within a group, API objects are versioned (e.g., v1beta1
, v1beta2
) to indicate the maturity of the objects. Pods, services, config maps, and secrets, for example, are all part of the /api/v1
API group, whereas deployments are part of the /apis/extensions/v1beta1
API group.
The group an object is part of is what is referred to as the apiVersion
in the object specification, available via the API reference.
Kubernetes API Conventions
In Recipe 6.1, you learned about the various API groups and how to discover which group a particular object is in.
All API resources are either objects or lists. All resources have a kind
and an apiVersion
. In addition, every object kind
must have metadata
. The metadata
contains the name of the object, the namespace it is in (see Recipe 6.3), and potentially some labels (see Recipe 6.6) and annotations (see Recipe 6.7).
A pod, for example, will be of kind Pod
and apiVersion v1
, and the beginning of a simple manifest written in YAML will look like this:
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
mypod
...
To complete a manifest, most objects will have a spec
and, once created, will also return a status
:
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
mypod
spec
:
...
status
:
...
Create namespaces and place your objects in different ones.
If you don’t specify anything, objects will get created in the default
namespace. Try creating a second namespace called my-app
, as shown here, and list the existing namespaces. You will see the default
namespace, two other namespaces that were created on startup (kube-system
and kube-public
), and the my-app namespace you just created:
$ kubectl create namespace my-app namespace "my-app" created $ kubectl get ns NAME STATUS AGE default Active 30s my-app Active 1s kube-public Active 29s kube-system Active 30s
Attempting to start two objects with the same name in the same namespace (e.g., default
) leads to a collision, and an error is returned by the Kubernetes API server. However, if you start the second object in a different namespace, the API server will create it:
$ kubectl run foobar --image=ghost:0.9 deployment "foobar" created $ kubectl run foobar --image=nginx:1.13 Error from server (AlreadyExists): deployments.extensions "foobar" already exists $ kubectl run foobar --image=nginx:1.13 --namespace foobar deployment "foobar" created
This is because many API objects in Kubernetes are namespaced. The namespace they belong to is defined as part of the object’s metadata.
The kube-system
namespace is reserved for administrators, whereas the kube-public
namespace is meant to store public objects available to any users of the cluster.
Use a ResourceQuota
object to specify the limitations on a namespace basis:
$ cat resource-quota-pods.yaml apiVersion: v1 kind: ResourceQuota metadata: name: podquota spec: hard: pods: "10" $ kubectl create namespace my-app $ kubectl create -f resource-quota-pods.yaml --namespace=my-app $ kubectl describe resourcequota podquota --namespace=my-app Name: podquota Namespace: my-app Resource Used Hard -------- ---- ---- pods 0 10
You can set a number of quotas on a per-namespace basis, including but not limited to pods, secrets, and config maps.
You want to label an object in order to find it later on. The label can be used for further end-user queries (see Recipe 6.6) or in the context of system automation.
Use the kubectl label
command. For example, to label a pod named foobar
with the key/value pair tier=frontend
, do this:
$ kubectl label pods foobar tier=frontend
Check the complete help for the command (kubectl label --help
). You can use it to find out how to remove labels, overwrite existing ones, and even label all resources in a namespace.
In Kubernetes, you use labels to organize objects in a flexible, nonhierarchical manner. A label is a key/value pair without any predefined meaning for Kubernetes. In other words, the content of the key/value pair is not interpreted by the system. You can use labels to express membership (e.g., object X belongs to department ABC), environments (e.g., this service runs in production), or really anything you need to organize your objects. Note that labels do have restrictions concerning their length and allowed values.2
Use the kubectl get --selector
command. For example, given the following pods:
$ kubectl get pods --show-labels NAME READY ... LABELS cockroachdb-0 1/1 ... app=cockroachdb, cockroachdb-1 1/1 ... app=cockroachdb, cockroachdb-2 1/1 ... app=cockroachdb, jump-1247516000-sz87w 1/1 ... pod-template-hash=1247516000,run=jump nginx-4217019353-462mb 1/1 ... pod-template-hash=4217019353,run=nginx nginx-4217019353-z3g8d 1/1 ... pod-template-hash=4217019353,run=nginx prom-2436944326-pr60g 1/1 ... app=prom,pod-template-hash=2436944326
You can select the pods that belong to the CockroachDB app (app=cockroachdb
):
$ kubectl get pods --selector app=cockroachdb NAME READY STATUS RESTARTS AGE cockroachdb-0 1/1 Running 0 17h cockroachdb-1 1/1 Running 0 17h cockroachdb-2 1/1 Running 0 17h
Labels are part of an object’s metadata. Any object in Kubernetes can be labeled. Labels are also used by Kubernetes itself for pod selection by deployments (see Recipe 4.1) and services (see Chapter 5).
Labels can be added manually with the kubectl label
command (see Recipe 6.5), or you can define labels in an object manifest, like so:
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
foobar
labels
:
tier
:
frontend
...
Once labels are present, you can list them with kubectl get
, noting the following:
-l
is the short form of --selector
and will query objects with a specified key=value
pair.
--show-labels
will show all the labels of each object returned.
-L
will add a column to the results returned with the value of the specified label.
Many object kinds support set-based querying, meaning you can state a query in a form like “must be labelled with X and/or Y.” For example, kubectl get pods -l 'env in (production, development)'
would give you pods that are in either the production or development environment.
With two pods running, one with label run=barfoo
and the other with label run=foobar
, you would get outputs similar to the following:
$ kubectl get pods --show-labels NAME READY ... LABELS barfoo-76081199-h3gwx 1/1 ... pod-template-hash=76081199,run=barfoo foobar-1123019601-6x9w1 1/1 ... pod-template-hash=1123019601,run=foobar $ kubectl get pods -Lrun NAME READY ... RUN barfoo-76081199-h3gwx 1/1 ... barfoo foobar-1123019601-6x9w1 1/1 ... foobar $ kubectl get pods -l run=foobar NAME READY ... foobar-1123019601-6x9w1 1/1 ...
Kubernetes Labels documentation
Use the kubectl annotate
command:
$ kubectl annotate pods foobar description='something that you can use for automation'
Annotations tend to be used for added automation of Kubernetes. For example, when you create a deployment with the kubectl run
command and you forget to use the --record
option, you will notice that the change-cause
column in your rollout history (see Recipe 4.5) is empty.
As of Kubernetes v1.6.0, to start recording the commands that cause changes to the deployment, you can annotate it with the kubernetes.io/change-cause
key. Given a deployment foobar
, you might annotate it with:
$ kubectl annotate deployment foobar kubernetes.io/change-cause="Reason for creating a new revision"
Subsequent changes to the deployment will be recorded.
1 Kubernetes, “Understanding Kubernetes Objects”.
2 Kubernetes, “Labels and Selectors: Syntax and character set”.
3.147.89.85