Kubernetes Cluster Setup in 7 Steps with Kubespray
There are many ways to set up a Kubernetes cluster. Some involve heavy manual configuration, others rely on cloud-specific tooling. The method that stands out for its simplicity and flexibility is Kubespray, an Ansible-based installer maintained by the Kubernetes SIGs community.
Kubespray supports a wide range of operating systems, from Ubuntu and CentOS to Debian and Red Hat. Configuration is done through YAML files, and enabling or disabling components often takes only a single line change. This reduces the workload significantly compared to setting up each component by hand.
Since Kubespray runs on Ansible, the control machine needs a few prerequisites: SSH access to the target nodes, Ansible, Git, and Python.
Step 1: Clone Kubespray
Start by cloning the Kubespray repository. Using --depth 1 limits the history to the latest commit, which speeds up the download.
git clone --depth 1 git@github.com:kubernetes-sigs/kubespray.gitThis creates a kubespray directory with the full project structure.
Step 2: Install Dependencies
Move into the cloned directory and install the required Python packages.
cd kubespray
sudo pip3 install -r requirements.txtIf you are using Python 2 instead of Python 3, use pip instead of pip3.
Step 3: Create an Inventory
Kubespray ships with a sample inventory. Copy it to a new directory named after your environment.
cp -rfp inventory/sample inventory/testThe inventory/test/ directory now holds the configuration files for your cluster. You can use any name instead of test; this is only a directory name.
Step 4: Configure the Inventory File
The main inventory file is inventory/test/inventory.ini. It defines the nodes in your cluster and their roles.
Assume the following three servers:
| Name | Private IP | Public IP | Role |
|---|---|---|---|
| node1 | 10.10.10.1 | 91.91.91.91 | Master |
| node2 | 10.10.10.2 | 92.92.92.92 | Worker |
| node3 | 10.10.10.3 | 93.93.93.93 | Worker |
Edit inventory.ini and organize the nodes into the relevant sections:
[all]
node1 ansible_host=91.91.91.91 ip=10.10.10.1 etcd_member_name=etcd1
node2 ansible_host=92.92.92.92 ip=10.10.10.2 etcd_member_name=etcd2
node3 ansible_host=93.93.93.93 ip=10.10.10.3 etcd_member_name=etcd3
[kube-master]
node1
[kube-node]
node2
node3
[etcd]
node1The ansible_host parameter is the IP address the control machine uses to reach the node. The ip parameter is the private IP used for node-to-node communication.
If you want the master node to also serve as a worker, add its name under [kube-node] as well.
Firewall Ports
If a firewall is in use, the following ports must be open on the respective nodes.
Master node:
| Port | Purpose |
|---|---|
| 6443/tcp | Kubernetes API |
| 2379-2380/tcp | etcd |
| 10250/tcp | kubelet API |
| 10251/tcp | kube-scheduler |
| 10252/tcp | kube-controller-manager |
| 10255/tcp | Read-only kubelet |
Worker node:
| Port | Purpose |
|---|---|
| 10250/tcp | kubelet API |
| 10255/tcp | Read-only kubelet |
| 30000-32767/tcp | NodePort services |
| 6783/tcp | Weave Net (if used) |
Step 5: Adjust Group Variables
Kubespray uses group variables for cluster-wide settings. Two files are important here:
inventory/test/group_vars/all/all.ymlinventory/test/group_vars/k8s-cluster/k8s-cluster.yml
These files contain parameters for enabling or disabling components such as the Nginx Ingress Controller, Helm, the Kubernetes Dashboard, CoreDNS, the Metrics Server, and proxy settings. Each option is documented inline, and most can be toggled by changing false to true (or the reverse).
Step 6: Run the Playbook
Once the inventory and variables are configured, run the Ansible playbook.
ansible-playbook -i inventory/test/inventory.ini --become cluster.ymlThis process takes about 20 to 30 minutes, depending on the number of nodes and network speed. The playbook installs all Kubernetes components, including etcd, kubelet, kube-apiserver, kube-controller-manager, kube-scheduler, kube-proxy, and the container runtime (Docker or containerd, depending on configuration).
Step 7: Configure kubectl on the Master
After the playbook completes successfully, SSH into the master node (node1 in this example) and verify that kubectl works.
kubectl get podsYou will likely see an error like:
The connection to the server localhost:8080 was refused - did you specify the right host or port?This happens because kubectl does not have a valid kubeconfig yet. The cluster configuration is located at /etc/kubernetes/admin.conf. Copy it to the default location:
mkdir ~/.kube
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $USER:$USER ~/.kube/configNow kubectl is ready. Test it by creating a deployment:
kubectl create deployment hello --image=hello-world
kubectl get podsThe output should show a running pod:
NAME READY STATUS RESTARTS AGE
hello-67d96bb797-lz8xf 1/1 Running 0 1dWrapping Up
Kubernetes continues to gain popularity as more teams adopt microservices and need to scale their applications. Kubespray makes the installation process repeatable and infrastructure-agnostic. Whether you are setting up a cluster for development or production, these seven steps provide a solid foundation.
The full Kubespray documentation covers many additional configuration options, including different network plugins, container runtimes, and add-on components. The official repository is a good next stop for deeper customization.
Hopefully this guide helps you get your cluster up and running without trouble. Wishing you a smooth Kubernetes journey.
Originally published in Turkish on Medium
You can read this post in Turkish.