The Kubernetes API server handles all of the requests to your Kubernetes cluster.
But how does it actually work?
When you type
kubectl apply -f my.yaml, your YAML is sent to the API and stored in etcd.
But what is the API server doing?
The API has a single block in the diagram, but the reality is that several components are involved in processing your request in sequence.
The first module is the HTTP handler.
This is nothing more than a regular web server.
Once the API receives the requests, it has to make sure that:
- You have access to the cluster (authentication).
- You can create, delete, list, etc. resources (authorization).
This is the part where the RBAC rules are evaluated.
So you're authenticated, and you can create Pods; what's next?
The API passes the request to the Mutation Admission Controller.
This component is in charge of looking at your YAML and modifying it.
What YAML can you change with it, though?
Does your Pod have an image pull policy?
If not, the admission controller will add "Always" for you.
Is the resource a Pod?
- It sets the default Service Account (if none is set).
- Adds a volume with the token.
After all modifications, does the Pod still look like a Pod?
The API makes a quick check to ensure that the resource is valid against the internal schema.
You don't want malformed YAML to be stored in the cluster.
If you try to deploy a Pod in a namespace that doesn't exist, is there anyone stopping you?
Are you trying to deploy more resources than your quota?
The controller will prevent that too.
The Validation and the Mutation Admission controller are also customizable.
You can register your scripts and design your checks to decide if a resource should be rejected from reaching etcd.
Two excellent examples of custom Admission controllers:
- Istio automatically injects an extra container to all Pods (mutation).
- Gatekeeper (Open Policy Agent) checks your resources against policies and reports violations (validation).
If you managed to pass the Validation Admission Controller, your resource is safely stored in etcd.
- The request is deserialized.
- A runtime object is created in memory.
- Finally, the new representation is persisted in etcd.
It's worth noting that Pods have versions when you define them in YAML.
However, the same Pod does not have a version when stored in the database.
It is stored with an internal representation that can be later deserialized to a version.
And to conclude this thread, the Kubernetes API is also extensible!
You can add your own APIs and register them with Kubernetes.
An excellent example of that is the metrics API server.
The metrics API server registers itself with the API and exposes extra API endpoints.
It's worth noting that you can integrate with the rest of the API and use the existing authentication and authorization modules from the API server.
And finally, if you've enjoyed this thread, you might also like the Kubernetes workshops that we run at Learnk8s https://learnk8s.io/training or this collection of past Twitter threads https://twitter.com/danielepolencic/status/1298543151901155330.
Until next time!