This document explains how the
kubicorn project works, the project’s structure and information you need to know so you can easily start contributing.
This chapter explains the most important concepts.
- Cluster API — universal (cloud provider agnostic) representation of a Kubernetes cluster. It defines every part of a cluster, including infrastructure parts such as virtual machines, networking units and firewalls. The matching of universal representation of the cluster to the representation for specific cloud provider is done as part of reconciling process.
- State — representation of an specific Kubernetes cluster. It’s used in the reconciling process to create the cluster.
- State store — place where state is stored. Currently, we only support states located on the disk and in YAML or JSON format. We’re looking forward to implementing Git and S3 state stores.
- Reconciler — the core of the project and place where provision logic is located. It matches cloud provider agnostic Cluster definition to the specific cloud provider definition, which is used to provision cluster. It takes care of provisioning new clusters, destroying the old ones and keeping the consistency between Actual and Expected states.
- Actual state — the representation of current resources in the cloud.
- Expected state — the representation of intended resources in the cloud.
- Bootstrap scripts — Bootstrap scripts are provided as the
user dataon the cluster creation to install dependencies and create the cluster. They’re provided as Bash scripts, so you can easily create them without Go knowledge. You can also inject values in the reconciling process, per your needs.
- Profile — profile is a unique representation of a cluster written in Go. Profiles contain all the information needed to create a cluster, such as: cluster name, cloud provider, VM size, SSH key, network and firewall configurations.
The project is contained in several packages.
The most important package is the
cloud package, which contains the Reconciler interface and Reconciler implementations for each cloud provider. Currently, we have implementations for four cloud providers:
The Cluster API is located in the
Default profiles are located in the
profiles package. Currently, we have Ubuntu profiles available for Amazon, DigitalOcean and GCE, and CentOS profiles available for Amazon and DigitalOcean.
State store definitions are located in the
We have two type of tests — CI tests and E2E tests. CI tests are regular Go tests, while E2E tests are run against real cloud infrastucture and it can cost money. E2E tests are available in the
This part of the document will try to summarize what steps are being taken in the reconciling process and how it works.
The first task of Reconciler is to convert universal, cloud-provider agnostic representation of a cluster to representation for a specific cloud provider. This transition is called rendering and is defined in the
model.go file, as well as in the
immutableRender function of the cloud-specific Reconciler. For example, this is how
model.go and Droplet’s
immutableRender looks for DigitalOcean.
Once the cluster is rendered, we can easily obtain Expected state of the cluster using the
Expected function, which represents what resources we are expecting in the cloud. This is how
Expected function is defined for DigitalOcean Droplets.
Next, Reconciler obtains the Actual state using the
Actual function, which represents what resources we already have in the cloud. You can take a look at the following function, which is used to obtain Actual state of DigitalOcean Droplets.
The most important task of Reconciler is applying, using the
Apply function. Firstly, Reconciler is checking if a cluster already exists, by comparing Actual and Expected states, and if yes, it’s stopping there returning the already existing one. If it doesn’t exist, we are proceeding on the creation part, which consists of:
- Building Bootstrap scripts and injecting values at the runtime,
- Creating the appropriate resources for Master node,
- Obtaining needed information for Node creation,
- Creating Nodes.
- Downloading the
.kubeconfigfile for the cluster from the master node.
At this point, we have fully functional Kubernetes cluster.
Besides creating the cluster, Reconciler also takes care of destroying the cluster, which is done by the
Delete function. This is how it looks for DigitalOcean Droplets.
The website runs on Jekyll, straight from GitHub Pages. It consists of templates and markdown files that are automatically built into HTML pages whenever any of the content changes.
The most common edits are changing the home.html files (our index page), and adding or editing files in the documentation/ folder.
Below are the relevant bits of the website’s structure. Other files can be ignored. For a more detailed overview see the Website Documentation document. Instructions for how to test your changes locally can be found there as well.
kubicorn/docs/ │ ├── _documentation/ │ → All docs to be displayed in the Documentation section of the website │ should go here. They should be markdown, and include the YAML header as │ shown in the link above. │ ├── _friends/ │ → Files in this folder feed the *Friends of kubicorn* section of the website. │ You should follow the formatting as per the files already present. │ ├── _includes/ │ → This holds the includes for every page of the website: footer, header, and │ head sections. │ ├── _layouts/ │ │ → This holds the different templates that make up the website. In │ │ practice we're only using two: │ │ │ ├── documentation.html │ │ → This is the template used to generate all files in the documentation │ │ section. │ │ │ └── home.html │ → This is the website's index page. Most of the text in the index page │ is hard-coded here. Exceptions are the _friends/ content and the │ _documentation/ list, which are generated dynamically. │ ├── img/ │ → All images go here. │ └── _site/ → This folder contains the auto-generated files that the website serves. They are built automatically whenever anything else on the folders above change, and should not be edited manually. Any changes to these files will be discarded.
Where should I start?
If you need more help understanding the reconciling process, take a look at the examples. It should explain which steps are taken to create a Kubernetes cluster.
To be able to better understand how the project works, you should read the Reconciler part of this document and follow the links to see how the code looks.
Once you get familiar with the process, find the issue you want to work on.
Our issue tracker has every issue labeled, so you can easily filter and navigate through it.
Besides the Hacktoberfest label, you can filter by the following labels:
- Help (small) – containing issues which shouldn’t require a lot of effort to be addressed.
- Help (medium) – issues that could require you a medium amount of time to get it addressed.
- Help (hard) – issues that require a lot of effort to get addressed.
We also label our issue per Cloud provider, operating system and type of the problem.
To get your Pull Request merged, you must follow the following Contributing Guidelines.
We will try to summarize it in this document, but you should read the above linked one:
- Your Go code must be formatted using the
go fmttool. This can be easily done using the
- Your Go files must contain license headers. You can check are headers correct with the
check-headersmake target, and you can append them to the files where they’re missing using the
- You should write unit tests where this is possible.
- Tests must pass.
Why we are doing stuff this way?
In this document, we’ll not explain reasoning and decisions involved in this project. If you are interested in the details, you should take a look at the Cloud Native Infrastructure book by Justin Garrison and Kris Nova.
Also, if you have any question, feel free to create an issue or ask us on the
kubicorn channel at the Kubernetes Slack.