In this tutorial, we’re going to show how to use Kubermatic KubeOne to create a highly-available Kubernetes cluster on providers that are not natively-supported. The tutorial covers downloading KubeOne, and provisioning a cluster using KubeOne. As a result, you’ll get a production-ready and Kubernetes/CNCF compliant cluster.
This tutorial could be used in the following scenarios:
If you are able to use a provider, have a look at the creating clusters tutorial, as this is the recommended approach.
This tutorial assumes that you’re using Linux or macOS. KubeOne currently doesn’t release Windows binaries. If you’re using Windows, we recommend checking out the Windows Subsystem for Linux (WSL).
Kubermatic KubeOne is a CLI tool for managing highly-available Kubernetes clusters in any environment (cloud, on-prem, bare metal, edge…). Clusters created by KubeOne are production-ready and Kubernetes/CNCF compliant out of the box. Generally, KubeOne runs the following tasks:
Kubermatic machine-controller works only on natively-supported providers, so we can’t use it for bare metal setups. Instead, we’ll create worker nodes manually and use the KubeOne Static Worker Nodes feature to provision those worker nodes.
The infrastructure for the control plane and worker nodes is created by the user.
Once the infrastructure is created, the user provides information about the instances that will be used and the load balancer that’s running in the front of the control plane nodes.
To make this task easier, KubeOne integrates with Terraform by reading the Terraform state, and provides example Terraform configs that can be used to create the infrastructure.
The infrastructure for the worker nodes can be managed in two ways:
The first approach is recommended if your provider is natively-supported (AWS, Azure, DigitalOcean, GCP, Hetzner Cloud, Nutanix, OpenStack, and VMware vSphere), and is covered in Creating a Kubernetes cluster tutorial.
This tutorial focuses on bare metal without the usage of any provider to create the required infrastructure. Therefore, you need to create the required infrastructure on your own. Make sure to adhere to the requirements described in the Infrastructure Management document.
Below, you can find a diagram that shows how KubeOne works.
By default, KubeOne installs the following components:
It’s possible to configure which components are installed and how they are
configured by adjusting the KubeOne configuration manifest that we’ll create
later in the Step 3 (Provisioning The Cluster). To see possible configuration
options, refer to the configuration manifest reference which can be obtained
by running kubeone config print --full
.
The easiest way to download KubeOne is to use our installation script. The following command will download and run the script:
curl -sfL https://get.kubeone.io | sh
The script downloads the latest version of KubeOne from GitHub, and unpacks it
in the /usr/local/bin
directory. Additionally, the script unpacks the example
Terraform configs, addons, and helper scripts in your current working
directory. At the end of the script output, you can find the path to the
unpacked files:
The addons and helper scripts are supposed to be used for advanced deployments and we will not use those in this tutorial. They’re not required by KubeOne, so you’re not required to keep to them.
...
Kubermatic KubeOne has been installed into /usr/local/bin/kubeone
Terraform example configs, addons, and helper scripts have been downloaded into the ./kubeone_1.4.0_linux_amd64 directory
You can confirm that KubeOne has been installed successfully by running the
kubeone version
command. If you see an error, ensure that /usr/local/bin
is
in your PATH
or modify the script to install KubeOne in a different place.
You can also check the Getting KubeOne guide for alternative
installation methods.
With KubeOne installed, we’re ready to create the infrastructure for our cluster. Because we are not using any provider, it is up to you to create the necessary infrastructure. Below you can find the infrastructure requirements and recommendations for control plane and worker nodes.
The following infrastructure requirements must be satisfied to successfully provision a Kubernetes cluster using KubeOne:
ip link
or ifconfig -a
sudo cat /sys/class/dmi/id/product_uuid
6443
, 2379
, 2380
, 10250
, 10251
, 10252
Depending on the environment, you may need additional objects, such as VPCs, firewall rules, or images.
The requirements for the worker instances are similar as for the control plane instances:
ip link
or ifconfig -a
sudo cat /sys/class/dmi/id/product_uuid
10250
, and optionally 30000-32767
for
NodePort ServicesUsually the Kubermatic machine-controller would take care of managing the worker nodes. However, without a provider we can not make use of it. For the following steps, we assume that the required infrastructure is in place and SSH access is ensured.
Now that we have the infrastructure, we can use KubeOne to provision a Kubernetes cluster.
The first step is to create a KubeOne configuration manifest that contains a list of instances that will be used, and that describes how the cluster will be provisioned, which Kubernetes version will be used,
and more. To see possible configuration options reference, you can run kubeone config print --full
.
For clusters running on providers that are not natively-supported (e.g. bare metal), we need to set the cloudProvider
to none: {}
.
In order to prevent KubeOne from deploying the Kubermatic machine-controller, which requires a cloud provider, set machineController
to deploy: false
.
Next, we need to define our control plane and worker nodes, referenced as staticWorkers, in the KubeOneCluster configuration.
Furthermore, the apiEndpoint
needs to be set to a load balancer or the first control plane node.
You can find more information about load balancing at HA load balancing.
Below you find an example reference about the minimum necessary information for a bare metal deployment.
apiVersion: kubeone.k8c.io/v1beta2
kind: KubeOneCluster
name: bm-cluster
versions:
kubernetes: '1.29.4'
cloudProvider:
none: {}
controlPlane:
hosts:
- publicAddress: '1.2.3.4'
privateAddress: '172.18.0.1'
sshUsername: root
sshPrivateKeyFile: '/home/me/.ssh/id_rsa'
taints:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
staticWorkers:
hosts:
- publicAddress: '1.2.3.5'
privateAddress: '172.18.0.2'
sshUsername: root
sshPrivateKeyFile: '/home/me/.ssh/id_rsa'
# Provide the external address of your load balancer or the public addresses of
# the first control plane nodes.
apiEndpoint:
host: ''
port: 6443
machineController:
deploy: false
Before proceeding, make sure to select the Kubernetes version that you want to use, add your controlPlane and staticWorkers hosts and replace the placeholder values with real values where applicable.
In the following table, you can find a list of supported Kubernetes version
for latest KubeOne versions (you can run kubeone version
to find the version
that you’re running).
KubeOne \ Kubernetes | 1.33 | 1.32 | 1.31 | 1.30 | 1.291 |
---|---|---|---|---|---|
v1.11 | ✓ | ✓ | ✓ | - | - |
v1.10 | - | ✓ | ✓ | ✓ | - |
v1.9 | - | - | ✓ | ✓ | ✓ |
We recommend using a Kubernetes release that’s not older than one minor release than the latest Kubernetes release. For example, with 1.32 being the latest release, we recommend running at least Kubernetes 1.31.
Now, we’re ready to provision the cluster! This is done by running the
kubeone apply
command and providing it the configuration manifest.
kubeone apply -m kubeone.yaml
This command analyzes the provided instances by running a set of probes to determine is it needed to provision a cluster or is there already a Kubernetes cluster running. If the cluster is already there, the probes will check is the cluster healthy and is the actual state matching the expected state defined by the configuration manifest. This allows us to use one single command for all operations (provision, upgrade, enable features, and more). This process is called Cluster Reconciliation and is described with additional details in the Cluster Reconciliation document.
The output will show steps that will be taken to provision a cluster. You’ll be
asked to confirm the intention to provision a cluster by typing yes
.
INFO[11:37:21 CEST] Determine hostname…
INFO[11:37:28 CEST] Determine operating system…
INFO[11:37:30 CEST] Running host probes…
The following actions will be taken:
Run with --verbose flag for more information.
+ initialize control plane node "ip-172-31-220-51.eu-west-3.compute.internal" (172.31.220.51) using 1.20.4
+ join control plane node "ip-172-31-221-177.eu-west-3.compute.internal" (172.31.221.177) using 1.20.4
+ join control plane node "ip-172-31-222-48.eu-west-3.compute.internal" (172.31.222.48) using 1.20.4
+ join worker node "ip-172-31-223-103.eu-west-3.compute.internal" (172.31.223.103) using 1.20.4
+ join worker node "ip-172-31-224-178.eu-west-3.compute.internal" (172.31.224.178) using 1.20.4
Do you want to proceed (yes/no):
After confirming your intention to provision the cluster, the provisioning will start. It usually takes 5-10 minutes for cluster to be provisioned. At the end, you should see output such as the following one:
...
INFO[11:46:54 CEST] Downloading kubeconfig…
INFO[11:46:54 CEST] Restarting unhealthy API servers if needed...
INFO[11:46:54 CEST] Ensure node local DNS cache…
INFO[11:46:54 CEST] Activating additional features…
INFO[11:46:56 CEST] Applying canal CNI plugin…
INFO[11:47:10 CEST] Skipping creating credentials secret because cloud provider is none.
INFO[11:47:10 CEST] Joining worker node node=172.31.223.103
INFO[11:47:17 CEST] Joining worker node node=172.31.224.178
At this point, your cluster is fully provisioned.
KubeOne automatically downloads the Kubeconfig file for the cluster. It’s named as <cluster_name>-kubeconfig. You can use it with kubectl such as:
kubectl --kubeconfig=<cluster_name>-kubeconfig
or export the KUBECONFIG
environment variable:
export KUBECONFIG=$PWD/<cluster_name>-kubeconfig
If you want to learn more about kubeconfig and managing access to your clusters, you can check the Configure Access To Multiple Clusters document.
You can try to list all nodes in the cluster to confirm that you can access the cluster:
kubectl get nodes
You should see output such as the following one.
NAME STATUS ROLES AGE VERSION
ip-172-31-220-51.eu-west-3.compute.internal Ready master 43m v1.20.4
ip-172-31-221-177.eu-west-3.compute.internal Ready master 42m v1.20.4
ip-172-31-222-48.eu-west-3.compute.internal Ready master 41m v1.20.4
ip-172-31-223-103.eu-west-3.compute.internal Ready <none> 38m v1.20.4
ip-172-31-224-178.eu-west-3.compute.internal Ready <none> 38m v1.20.4
Congratulations!!! You have successfully provisioned a Kubernetes cluster using Kubermatic KubeOne. You’re now ready to run your workload on this cluster. We recommend checking the following learn more section for additional resources and recommendations.
Kubernetes 1.29 has reached End-of-Life (EOL) and is not supported any longer. We strongly recommend upgrading to a newer supported Kubernetes release as soon as possible. ↩︎