The core function of kubelet is to create a pod on the host and start the containers it defines.
In the kubernetes community, both kubelet and cri belong to sig node.
Kubernetes has two irreplaceable components: Kube apiserver and kubelet.
Kubelet itself works according to the controller mode. The core of the work is a control loop syncloop
There are four events that drive the operation of the control cycle
- Pod update event
- Pod life cycle change
- Execution cycle set by kubelet itself
- Scheduled cleanup events
Kubelet will monitor the changes of pod objects related to him through the watch mechanism. Of course, the filter condition of this watch is that the nodeName field of the pod is the same as its own. Kubelet will cache the information of these pods in its own memory.
It should be noted here that the execution process of kubelet calling the lower container runtime does not directly call the docker API, but is indirectly executed through a set of grpc interfaces called CRI. Kubernetes before version 1.6 directly called the docker API to create and manage containers
The core of CRI mechanism is that each container project can now implement a CRI shim to process CRI requests by itself. In this way, kubernetes has a unified container abstraction layer.
In addition to dockershim, CRI shim of other container runtime needs to be additionally deployed on the host.
The containerd project in CNCF can provide a typical CRI shim capability, convert the CRI request sent by kubernetes into a call to containerd, and then create a runc container. The runc project is the component responsible for basic operations such as setting container namespace, cgroups and chroot.
There is also a set of interfaces called runpodsandbox in CRI. It does not correspond to the pod API object in kubernetes, but only extracts some fields related to the container runtime in pod, such as hostname, dnsconfig, cgroupparent, etc.
As a specific container project, you need to decide how to use these fields to implement a pod model expected by kubernetes.
After kubectl run is executed and a pod containing containers a and B is created, the information of this pod finally comes to kubelet.
Then kubelet will create a and B containers according to the following steps
RunPodSandbox(foo)
- CreatContainer(A)
- StartContainer(A)
- CreatContainer(B)
- StartContainer(B)
In the specific CRI shim, the implementation of these interfaces can be completely different
If it is a docker project, dockershim will create an infra container named foo (pause container) to hold the network namespace of the whole pod.
If it is a container based on virtualization technology, such as Kata containers project, its CRI implementation will directly create a lightweight virtual machine to act as a pod
In the implementation of runpodsandbox interface, you also need to call networkplugin Setuppod (…) to set up the network for this sandbox. This setuppod (…) is to execute the add (…) method in the CNI plug-in.
So finally, on the host, dockershim will leave three containers, while Kata containers will leave a lightweight virtual machine.
If kubectl exec is called for a container, the request will be handed over to the API server first, and then the API server will call kubelet’s exec API. In this way, kubelet will call CRI’s exec interface, and cri shim is responsible for responding to this interface.
CRI shim will return the address and port URL of the streaming server of this cri shim to kubelet. After kubelet gets the URL, it will return it to API server in the way of redirect. API server will initiate a real exec request to the streaming server through redirection and establish a long connection with it.