Learning Objectives
By the end of this chapter, you should be able to:
- Understand the API REST-based architecture.
- Work with annotations.
- Understand a simple Pod template.
- Use kubectl with greater verbosity for troubleshooting.
- Separate cluster resources using namespaces.
APIS_AND_ACCESS
API Access
Kubernetes has a powerful REST-based API. The entire architecture is API-driven. Knowing where to find resource endpoints and understanding how the API changes between versions can be important to ongoing administrative tasks, as there is much ongoing change and growth. Starting with v1.16 deprecated objects are no longer honored by the API server.
As we learned in the Kubernetes Architecture chapter, the main agent for communication between cluster agents and from outside the cluster is the kube-apiserver. A curl query to the agent will expose the current API groups. Groups may have multiple versions, which evolve independently of other groups, and follow a domain-name format with several names reserved, such as single-word domains, the empty group, and any name ending in .k8s.io.
RESTful
kubectl makes API calls on your behalf, responding to typical HTTP verbs (GET, POST, DELETE). You can also make calls externally, using curl or other program. With the appropriate certificates and keys, you can make requests, or pass JSON files to make configuration changes.
$ curl --cert userbob.pem --key userBob-key.pem \
--cacert /path/to/ca.pem \
https://k8sServer:6443/api/v1/pods
The ability to impersonate other users or groups, subject to RBAC configuration, allows a manual override authentication. This can be helpful for debugging authorization policies of other users.
Checking Access
While there is more detail on security in a later chapter, it is helpful to check the current authorizations, both as an administrator, as well as another user. The following shows what user bob could do in the default namespace and the developer namespace, using the auth can-i subcommand to query:
$ kubectl auth can-i create deployments
yes
$ kubectl auth can-i create deployments --as bob
no
$ kubectl auth can-i create deployments --as bob --namespace developer
yes
There are currently three APIs which can be applied to set who and what can be queried:
-
SelfSubjectAccessReview Access review for any user, helpful for delegating to others.
-
LocalSubjectAccessReview Review is restricted to a specific namespace.
-
SelfSubjectRulesReview A review which shows allowed actions for a user within a particular namespace.
The use of reconcile allows a check of authorization necessary to create an object from a file. No output indicates the creation would be allowed.
Optimistic Concurrency
The default serialization for API calls must be JSON. There is an effort to use Google’s protobuf serialization, but this remains experimental. While we may work with files in a YAML format, they are converted to and from JSON.
Kubernetes uses the resourceVersion value to determine API updates and implement optimistic concurrency. In other words, an object is not locked from the time it has been read until the object is written.
Instead, upon an updated call to an object, the resourceVersion is checked, and a 409 CONFLICT is returned, should the number have changed. The resourceVersion is currently backed via the modifiedIndex parameter in the etcd database, and is unique to the namespace, kind, and server. Operations which do not change an object, such as WATCH or GET, do not update this value.
Using Annotations
Labels are used to work with objects or collections of objects; annotations are not.
Instead, annotations allow for metadata to be included with an object that may be helpful outside of the Kubernetes object interaction. Similar to labels, they are key to value maps. They are also able to hold more information, and more human-readable information than labels.
Having this kind of metadata can be used to track information such as a timestamp, pointers to related objects from other ecosystems, or even an email from the developer responsible for that object’s creation.
The annotation data could otherwise be held in an exterior database, but that would limit the flexibility of the data. The more this metadata is included, the easier it is to integrate management and deployment tools or shared client libraries.
For example, to annotate only Pods within a namespace, you can overwrite the annotation, and finally delete it:
$ kubectl annotate pods --all description='Production Pods' -n prod
$ kubectl annotate --overwrite pods description="Old Production Pods" -n prod
$ kubectl annotate pods foo description- -n prod
Simple Pod
As discussed earlier, a Pod is the lowest compute unit and individual object we can work with in Kubernetes. It can be a single container, but often, it will consist of a primary application container and one or more supporting containers.
Below is an example of a simple pod manifest in YAML format. You can see the apiVersion (it must match the existing API group), the kind (the type of object to create), the metadata (at least a name), and its spec (what to create and parameters), which define the container that actually runs in this pod:
apiVersion: v1
kind: Pod
metadata:
name: firstpod
spec:
containers:
- image: nginx
name: stan
You can use the kubectl create command to create this pod in Kubernetes. Once it is created, you can check its status with kubectl get pods. The output is omitted to save space:
$ kubectl create -f simple.yaml
$ kubectl get pods
$ kubectl get pod firstpod -o yaml
$ kubectl get pod firstpod -o json
Manage API Resources with kubectl
Kubernetes exposes resources via RESTful API calls, which allows all resources to be managed via HTTP, JSON or even XML, the typical protocol being HTTP. The state of the resources can be changed using standard HTTP verbs (e.g. GET, POST, PATCH, DELETE, etc.).
kubectl has a verbose mode argument which shows details from where the command gets and updates information. Other output includes curl commands you could use to obtain the same result. While the verbosity accepts levels from zero to any number, there is currently no verbosity value greater than ten. You can check this out for kubectl get. The output below has been formatted for clarity:
$ kubectl --v=10 get pods firstpod
....
I1215 17:46:47.860958 29909 round_trippers.go:417]
curl -k -v -XGET -H "Accept: application/json"
-H "User-Agent: kubectl/v1.8.5 (linux/amd64) kubernetes/cce11c6"
https://10.128.0.3:6443/api/v1/namespaces/default/pods/firstpod
....
If you delete this pod, you will see that the HTTP method changes from XGET to XDELETE.
$ kubectl --v=10 delete pods firstpod
....
I1215 17:49:32.166115 30452 round_trippers.go:417]
curl -k -v -XDELETE -H "Accept: application/json, */*"
-H "User-Agent: kubectl/v1.8.5 (linux/amd64) kubernetes/cce11c6"
https://10.128.0.3:6443/api/v1/namespaces/default/pods/firstpod
....
Access from Outside the Cluster
The primary tool used from the command line will be kubectl, which calls curl on your behalf. You can also use the curl command from outside the cluster to view or make changes.
The basic server information, with redacted TLS certificate information, can be found in the output of
$ kubectl config view
If you view the verbose output from a previous page, you will note that the first line references a configuration file where this information is pulled from, ~/.kube/config:
I1215 17:35:46.725407 27695 loader.go:357]
Config loaded from file /home/student/.kube/config
Without the certificate authority, key and certificate from this file, only insecure curl commands can be used, which will not expose much due to security settings. We will use curl to access our cluster using TLS in an upcoming lab.
~/.kube/config
Take a look at the output below:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdF.....
server: https://10.128.0.3:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTib.....
client-key-data: LS0tLS1CRUdJTi....
The output above shows 19 lines of output, with each of the keys being heavily truncated. While the keys may look similar, close examination shows them to be distinct.
- apiVersion
As with other objects, this instructs the kube-apiserver where to assign the data.
- clusters
This key contains the name of the cluster, as well as where to send the API calls. The certificate-authority-data is passed to authenticate the curl request.
- contexts
This is a setting which allows easy access to multiple clusters, possibly as various users, from one configuration file. It can be used to set namespace, user, and cluster.
- current-context
This shows which cluster and user the kubectl command would use. These settings can also be passed on a per-command basis.
- kind
Every object within Kubernetes must have this setting; in this case, a declaration of object type Config.
- preferences
Currently not used, this is an optional settings for the kubectl command, such as colorizing output.
- users
A nickname associated with client credentials, which can be client key and certificate, username and password, and a token. Token and username/password are mutually exclusive. These can be configured via the kubectl config set-credentials command.
Working with Namespaces
Take a look at the following commands:
$ kubectl get ns
$ kubectl create ns linuxcon
$ kubectl describe ns linuxcon
$ kubectl get ns/linuxcon -o yaml
$ kubectl delete ns/linuxcon
The above commands show how to view, create and delete namespaces. Note that the describe subcommand shows several settings, such as Labels, Annotations, resource quotas, and resource limits, which we will discus later in the course.
Once a namespace has been created, you can reference it via YAML when creating a resource:
$ cat redis.yaml
apiVersion: V1
kind: Pod
metadata:
name: redis
namespace: linuxcon
...
API Resources with kubectl
All API resources exposed are available via kubectl. To get more information, do kubectl help.
kubectl [command] [type] [Name] [flag]
Expect the list below to change:
all | events (ev) | podsecuritypolicies (psp) |
---|---|---|
certificatesigningrequests (csr) | horizontalpodautoscalers (hpa) | podtemplates |
clusterrolebindings | ingresses (ing) | replicasets (rs) |
clusterroles | jobs | replicationcontrollers (rc) |
clusters (valid only for federation apiservers) | limitranges (limits) | resourcequotas (quota) |
componentstatuses (cs) | namespaces (ns) | rolebindings |
configmaps (cm) | networkpolicies (netpol) | roles |
controllerrevisions | nodes (no) | secrets |
cronjobs | persistentvolumeclaims (pvc) | serviceaccounts (sa) |
customresourcedefinition (crd) | persistentvolumes (pv) | services (svc) |
daemonsets (ds) | poddisruptionbudgets (pdb) | statefulsets |
deployments (deploy) | podpreset | storageclasses |
endpoints (ep) | pods (po) |
Additional Resource Methods
In addition to basic resource management via REST, the API also provides some extremely useful endpoints for certain resources.
For example, you can access the logs of a container, exec into it, and watch changes to it with the following endpoints:
$ curl --cert /tmp/client.pem --key /tmp/client-key.pem \
--cacert /tmp/ca.pem -v -XGET \
https://10.128.0.3:6443/api/v1/namespaces/default/pods/firstpod/log
This would be the same as the following. If the container does not have any standard out, there would be no logs.
$ kubectl logs firstpod
There are other calls you could make, following the various API groups on your cluster:
GET /api/v1/namespaces/{namespace}/pods/{name}/exec
GET /api/v1/namespaces/{namespace}/pods/{name}/log
GET /api/v1/watch/namespaces/{namespace}/pods/{name}
Swagger and OpenAPI
The entire Kubernetes API uses a Swagger specification. This is evolving towards the OpenAPI initiative. It is extremely useful, as it allows, for example, to auto-generate client code. All the stable resources definitions are available on the documentation site.
You can browse some of the API groups via a Swagger UI on the OpenAPI Specification web page.
API Maturity
The use of API groups and different versions allows for development to advance without changes to an existing group of APIs. This allows for easier growth and separation of work among separate teams. While there is an attempt to maintain some consistency between API and software versions, they are only indirectly linked.
The use of JSON and Google’s Protobuf serialization scheme will follow the same release guidelines.
- Alpha
An Alpha level release, noted with alpha in the name, may be buggy and is disabled by default. Features could change or disappear at any time. Only use these features on a test cluster which is often rebuilt.
- Beta
The Beta level, found with beta in the name, has more well-tested code and is enabled by default. It also ensures that, as changes move forward, they will be tested for backwards compatibility between versions. It has not been adopted and tested enough to be called stable. You can expect some bugs and issues.
- Stable
Use of the Stable version, denoted by only an integer which may be preceded by the letter v, is for stable APIs.