Chapter 6. Exploring the Kubernetes API and Key Metadata

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.

6.1 Discovering API Endpoints of the Kubernetes API Server

Problem

You want to discover the various API endpoints available on the Kubernetes API server.

Solution

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.

Tip

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.

Discussion

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.

6.2 Understanding the Structure of a Kubernetes Manifest

Problem

While Kubernetes has a few convenience generators with kubectl run and kubectl create, you need to learn how to write Kubernetes manifests, expressing Kubernetes object specifications. To do this, you need to understand the general structure of manifests.

Solution

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:
  ...

6.3 Creating Namespaces to Avoid Name Collisions

Problem

You want to create two objects with the same name but want to avoid naming collisions.

Solution

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
Note

Alternatively, you can write a manifest to create your namespace. If you save the following manifest as app.yaml, you can then create the namespace with the kubectl create -f app.yaml command:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app

Discussion

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.

Note

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.

6.4 Setting Quotas Within a Namespace

Problem

You want to limit the resources available in a namespace—for example, the overall number of pods that can run in the namespace.

Solution

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

Discussion

You can set a number of quotas on a per-namespace basis, including but not limited to pods, secrets, and config maps.

6.5 Labeling an Object

Problem

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.

Solution

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
Tip

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.

Discussion

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

6.6 Using Labels for Queries

Problem

You want to query objects efficiently.

Solution

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

Discussion

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     ...

See Also

6.7 Annotating a Resource with One Command

Problem

You want to annotate a resource with a generic, nonidentifying key/value pair, possibly using nonhuman readable data.

Solution

Use the kubectl annotate command:

$ kubectl annotate pods foobar 
description='something that you can use for automation'

Discussion

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.89.85