In this Byte size post we will uncover the code that is executed in the background when we execute kubeadm init command.
If you had ever setup a self hosted kubernetes cluster then most probably you would have followed any one of the below:
- kubeadm way ( kubeadm cli provided by kubernetes)
- other tools ( tools like kops that are available in the market)
- The hard way ( most of us would have followed the excellent doc written by Kelsey Hightower )
When I started working on kubernetes I followed the kubeadm way which I felt was the most easiest solution for beginners and that still holds true. Initially, whenever I executed kubeadm init command, I wasn’t worried much about what’s going on in the background and just waited few minutes for the cluster to be up and running. It was when I read Kelsey Hightower’s documentation on setting up the cluster from scratch, I became skeptical and wanted to understand how kubeadm did all the tasks that was explained in that document and decided to trace it in the source code. Below explanation is based on what I found out.
Note: You should have a local copy of Kubernetes git repository as well as a fair understanding of Go programming language and Cobra CLI framework. Please refer my earlier post that can help you get started.
The Big Bang
If we just execute kubeadm command without any flags this is what it prints on the screen:
Now, where did the above output come from come? If we try to trace it , we would end up with the below sequence:
- From the local Kubernetes repository expand the cmd/kubeadm folder. You would notice a file kubeadm.go. This file contains the main function from where the execution of kubeadm program begins.
That file contains only few lines of code as show above and the function that we are interested is app.Run() which is available under the package k8s.io/kubernetes/cmd/kubeadm/app
2) Let’s see where can we find Run() function definition in the package k8s.io/kubernetes/cmd/kubeadm/app.
Note: Be aware that the file names are same for step 1 and 2. In step 2 we are referring to the file found under app directory and not kubeadm root directory.
This file contains the Run() function and most part of its code looks like it is handling some flags passed to kubeadm. The function that we have to trace next is cmd.NewKubeadmCommand() which is available under k8s.io/kubernetes/cmd/kubeadm/app/cmd package.
3) Expand the directory cmd under app and take a look at the contents of the file cmd.go
If we ignore the Cobra framework portion of code temporarily, we can easily understand that the output that we saw when when we ran kubeadm command comes from here.
Towards the end of this function, you will find the below code where all the subcommands of kubeadm (example init, join, reset, version etc) are attached to the parent command (which is kubeadm). All of this is pretty much Cobra stuff. Our next function to be traced is newCmdInit() because we are interested only in kubeadm init. (You can follow similar approach to understand other subcommands of kubeadm).
3) Under the same directory where we are currently in, there would be a file init.go that contains newCmdInit() function.
The initial few lines of this function would look like this:
If you execute kubeadm with the subcommand init and the help flag, you should get the output as below and that comes from the above code block:
The remaining output of kubeadm init -h shows that the entire init subcommand is divided into 12 phases (shown as below) which leads us to the set of next functions that we should start tracing to understand how all these phases are getting executed. We will start with preflight.
Note: Each phase is again a subcommand for the init subcommand (It’s the second level subcommand) and you can run a specific phase for init subcommand instead of running all the phases. Example You can execute kubeadm init phase certs which will generate only the certs required for setting up the control plane (basically just the phase 2 is executed).
4) Inside the newCmdInit() func, towards the end of the function you will notice few function calls as below and these is were the execution of the 12 phases begin.
For the first phase , NewPreflightPhase() function is available in the preflight.go file under the k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/init package
The code performs system checks based on the operating system before it starts generating certificates for kubernetes components:
If you want to know the different kinds of checks performed in this phase, then have a look into some of these files under app/preflight directory:
The next phase is certs and for that go back to app/cmd/phases directory and locate the file certs.go:
If you browse the contents of this file, you should be able to figure out what are the certificates and how are these generated by kubeadm init command.
You can now apply similar tracing technique for the remaining 10 phases and can figure out what each phase does in the background.
In a Nutshell
In short, kubeadm init execution is divided into 12 phases (with a support to run only a specific phase. Default is to run all phases) and if you want to understand what is getting executed as a part of these phases then you should look in these files:
The functions within these files make use of functions existing in other packages of kubeadm but with some effort you can easily trace out those dependencies too.
After I was able to figure out few internal workings of each phase, all the stuff that I learnt in Kelsey Hightower documentation made more sense to me.
Though this is not a mandatory topic to understand when it comes to setting up Kubernetes but understanding the underlying concepts might help you if you want to customize the way kubernetes is setup using kubeadm.
Hope you found this article helpful. Please feel free to reach me at firstname.lastname@example.org or https://www.linkedin.com/in/arunprasadk/