Table of Contents
Introduction
Install Kubernetes Cluster with Ansible, This is required when we need to automate the whole installation process in a few minutes. Let’s go through step by step process. To familiarise ourselves with it, we need to know the whole step-by-step setup and workflow.
If you need to know the manual installation steps, have a look at these guides How to Install and configure Kubernetes (k8s) on Ubuntu 18.04 LTS. For, more Kubernetes-related articles click here.
New Playbook updated with Containers, Jump to containers
System Requirements
I’m using the below system configuration in my home lab.
| OPERATING SYSTEM VERSION | HOSTNAME | IP ADDRESS | SYSTEM CPU | SYSTEM MEMORY | KUBEADM VERSION |
| Ubuntu 16.04.6 LTS or Ubuntu 18.08 LTS | k8mas1.linuxsysadmins.local | 192.168.0.26 | 4 vCPU | 8 GB | v1.19.0 |
| Ubuntu 16.04.6 LTS or Ubuntu 18.08 LTS | k8nod1.linuxsysadmins.local | 192.168.0.27 | 4 vCPU | 8 GB | v1.19.0 |
| Ubuntu 16.04.6 LTS or Ubuntu 18.08 LTS | k8nod1.linuxsysadmins.local | 192.168.0.28 | 4 vCPU | 8 GB | v1.19.0 |
| CentOS Linux release 8.2.2004 (Core) | gateway.linuxsysadmins.local | 192.168.0.16 | 1 vCPU | 1 GB | NA |
Setting Up Ansible Inventory
In the first place, decide which user is going to handle this installation and which user will manage the Kubernetes cluster. In my case, I’m about to use “ansible” as my user for both.

Moreover, I’m using my default Ansible host inventory file for this guide and segregated the hosts into a separate group as masters and workers to ease the process to put in separate playbooks.
$ cat /etc/ansible/hosts
[users]
k8mas1.linuxsysadmins.local
k8nod1.linuxsysadmins.local
k8nod2.linuxsysadmins.local
[masters]
master ansible_host=k8mas1.linuxsysadmins.local ansible_user=ansible
[workers]
worker1 ansible_host=k8nod1.linuxsysadmins.local ansible_user=ansible
worker2 ansible_host=k8nod2.linuxsysadmins.local ansible_user=ansible
Creating User Account
To Install the Kubernetes cluster and manage the cluster let’s create an account. While running the below playbook it will prompt to type the username required to be created on the remote servers.
---
- hosts: users
become: yes
vars_prompt:
- name: "new_user"
prompt: "Account need to be create in remote server."
private: no
tasks:
- name: creating the user {{ new_user }}.
user:
name: "{{ new_user }}"
createhome: yes
shell: /bin/bash
append: yes
state: present
- name: Create a dedicated sudo entry file for the user.
file:
path: "/etc/sudoers.d/{{ new_user }}"
state: touch
mode: '0600'
- name: "Setting up Sudo without Password for user {{ new_user }}."
lineinfile:
dest: "/etc/sudoers.d/{{ new_user }}"
line: '{{ new_user }} ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
- name: Set authorized key for user copying it from current {{ new_user }} user.
authorized_key:
user: "{{ new_user }}"
state: present
key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"
- name: Print the created user.
shell: id "{{ new_user }}"
register: new_user_created
- debug:
msg: "{{ new_user_created.stdout_lines[0] }}"
...
Save the above YAML in a cat and run as follow.
$ ansible-playbook cretae_user.yaml -k -K
The playbook will manage to create the account, adding a SUDO entry with no password to root and copying the SSH authorized key from the Ansible host to remote servers.
TASK [debug] ******************************************************************************************************
ok: [k8mas1.linuxsysadmins.local] => {
"msg": "uid=1011(ansibleuser1) gid=1011(ansibleuser1) groups=1011(ansibleuser1)"
}
ok: [k8nod1.linuxsysadmins.local] => {
"msg": "uid=1011(ansibleuser1) gid=1011(ansibleuser1) groups=1011(ansibleuser1)"
}
ok: [k8nod2.linuxsysadmins.local] => {
"msg": "uid=1011(ansibleuser1) gid=1011(ansibleuser1) groups=1011(ansibleuser1)"
}
PLAY RECAP ********************************************************************************************************
k8mas1.linuxsysadmins.local : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
k8nod1.linuxsysadmins.local : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
k8nod2.linuxsysadmins.local : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@gateway ~]$
Install Kubernetes & Docker Packages.
Right after creating the user start with installing and configuring required packages on all the master and worker nodes. Additionally, disabling the swap, resolving dependencies are included as well. At the end of the installation, it will reboot all the nodes.
---
- hosts: "masters, workers"
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Make the Swap inactive
command: swapoff -a
- name: Remove Swap entry from /etc/fstab.
lineinfile:
dest: /etc/fstab
regexp: swap
state: absent
- name: Installing Prerequisites for Kubernetes
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- vim
- software-properties-common
state: present
- name: Add Dockerโs official GPG key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable
state: present
filename: docker
mode: 0600
- name: Install Docker Engine.
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
- name: Enable service docker, and enable persistently
service:
name: docker
enabled: yes
- name: Add Google official GPG key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add Kubernetes Repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
state: present
filename: kubernetes
mode: 0600
- name: Installing Kubernetes Cluster Packages.
apt:
name:
- kubeadm
- kubectl
- kubelet
state: present
- name: Enable service kubelet, and enable persistently
service:
name: kubelet
enabled: yes
- name: Reboot all the kubernetes nodes.
reboot:
post_reboot_delay: 10
reboot_timeout: 40
connect_timeout: 60
test_command: uptime
...
Save the YAML as follows and run it.
$ ansible-playbook pacakge_install.yaml -k -K
Output for your reference.
TASK [Reboot all the kubernetes nodes.] ***************************************************************************
changed: [worker2]
changed: [master]
changed: [worker1]
PLAY RECAP *******************************************************************************************************
master : ok=13 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker1 : ok=13 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker2 : ok=13 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@gateway ~]$
The next step is to set up the master node.
Setting up Kubernetes Master Server
It’s now time to start the master server initialization. Before running the playbook decide which pod network CIDR, Pod Network, Networking, and Network Policy needs to be created.
Flannel Network
If you need to use flannel as your network use.
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Calico Network
In case, your choice is Calico get it from here.
While writing this guide we have used v3.16.
https://docs.projectcalico.org/v3.16/manifests/calico.yaml
The list of Release versions is here.
https://docs.projectcalico.org/releases
Current latest version while updating this guide.
https://docs.projectcalico.org/v3.18/manifests/calico.yaml
A new version may be out by tomorrow, find the same from the below URL.
https://docs.projectcalico.org/manifests/calico.yaml
If you are looking to learn more about Calico, find it here. Learn, test your skills, and be certified as a calico Operator Level 1.
https://academy.tigera.io/course/certified-calico-operator-level-1/
Weave Network
For Weave get the same from here.
https://cloud.weave.works/k8s/net
RBAC Manifest from Calico
Role-based access control
https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
While prompting use the required network and RBAC URL.
---
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
vars_prompt:
- name: "pod_network_cidr"
prompt: "Enter the Pod Network CIDR, example: 192.168.100.0/24"
private: no
- name: "k8s_master_ip"
prompt: "Enter the Apiserver advertise address, example: 192.168.0.26"
private: no
- name: "pod_network_manifest_file"
prompt: "Enter the Pod network manifest file URL, Your choice could be flannel, weave or calico, etc."
private: no
- name: "rbac_manifest_file"
prompt: "Enter the RBAC manifest file URL"
private: no
tasks:
- name: Intilizing Kubernetes Cluster
command: kubeadm init --pod-network-cidr "{{ pod_network_cidr }}" --apiserver-advertise-address "{{ k8s_master_ip }}"
run_once: true
delegate_to: "{{ k8s_master_ip }}"
- pause: seconds=30
- name: Create directory for kube config.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ansible_user }}/.kube
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
- name: Copy /etc/kubernetes/admin.conf to user's home directory /home/{{ ansible_user }}/.kube/config.
become_user: root
become_method: sudo
become: yes
copy:
src: /etc/kubernetes/admin.conf
dest: /home/{{ ansible_user }}/.kube/config
remote_src: yes
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
- pause: seconds=10
- name: Remove the cache directory.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ ansible_user }}/.kube/cache
state: absent
- name: Create Pod Network & RBAC.
become_user: ansible
become_method: sudo
become: yes
command: "{{ item }}"
with_items:
- kubectl apply -f {{ pod_network_manifest_file }}
- kubectl apply -f {{ rbac_manifest_file }}
- pause: seconds=30
- name: Get the token for joining the nodes with Kuberentes master.
shell: kubeadm token create --print-join-command
register: kubernetes_join_command
- debug:
msg: "{{ kubernetes_join_command.stdout }}"
- name: Copy join command to local file.
local_action: copy content="{{ kubernetes_join_command.stdout_lines[0] }}" dest="/tmp/kubernetes_join_command" mode=0777
...
Truncated the long output.
[ansible@gateway ~]$ ansible-playbook cluster_init.yaml -k -K
SSH password:
BECOME password[defaults to SSH password]:
Enter the Pod Network CIDR, example: 192.168.100.0/24: 192.168.100.0/24
Enter the Apiserver advertise address, example: 192.168.0.26: 192.168.0.26
Enter the Pod network manifest file URL, Your choice could be flannel, weave or calico, etc.: https://docs.projectcalico.org/v3.16/manifests/calico.yaml
Enter the RBAC manifest file URL: https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
PLAY [masters] ***************************************************************************************************
TASK [debug] *****************************************************************************************************
ok: [master] => {
"msg": "kubeadm join 192.168.0.26:6443 --token h6s1ox.kqqfpl5to1ga0bo6 --discovery-token-ca-cert-hash sha256:19c2bc5db8dca256f44e9a992c599c6455ce243148edf9b170d75b9f4b3b5712 "
}
TASK [Copy join command to local file.] **************************************************************************
changed: [master]
PLAY RECAP *******************************************************************************************************
master : ok=12 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@gateway ~]$
As before, save it in a file and run it.
$ ansible-playbook cluster_init.yaml -k -K
At the end of the maser server setup, it will print the worker nodes join command.
Setting Up Worker Nodes
Once the master server setup is completed, start with working on joining the worker nodes with the master by running the below playbook.
---
- hosts: workers
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Copy join command to worker nodes.
become: yes
become_method: sudo
become_user: root
copy:
src: /tmp/kubernetes_join_command
dest: /tmp/kubernetes_join_command
mode: 0777
- name: Join the Worker nodes with the master.
become: yes
become_method: sudo
become_user: root
command: sh /tmp/kubernetes_join_command
register: joined_or_not
- debug:
msg: "{{ joined_or_not.stdout }}"
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Configure kubectl command auto-completion.
lineinfile:
dest: /home/{{ ansible_user }}/.bashrc
line: 'source <(kubectl completion bash)'
insertafter: EOF
...
Output for reference.
TASK [debug] ****************************************************************************************************
ok: [worker1] => {
"msg": "[preflight] Running pre-flight checks\n[preflight] Reading configuration from the cluster...\n[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'\n[kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\"\n[kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\"\n[kubelet-start] Starting the kubelet\n[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...\n\nThis node has joined the cluster:\n* Certificate signing request was sent to apiserver and a response was received.\n* The Kubelet was informed of the new secure connection details.\n\nRun 'kubectl get nodes' on the control-plane to see this node join the cluster."
}
ok: [worker2] => {
"msg": "[preflight] Running pre-flight checks\n[preflight] Reading configuration from the cluster...\n[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'\n[kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\"\n[kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\"\n[kubelet-start] Starting the kubelet\n[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...\n\nThis node has joined the cluster:\n* Certificate signing request was sent to apiserver and a response was received.\n* The Kubelet was informed of the new secure connection details.\n\nRun 'kubectl get nodes' on the control-plane to see this node join the cluster."
}
PLAY [masters] **************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [master]
TASK [Configure kubectl command auto completion.] ***************************************************************
changed: [master]
PLAY RECAP *******************************************************************************************************
master : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker1 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker2 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@gateway ~]$
Finally, copy the worker node setup YAML and save the file in the named worker.YAML and run it.
$ ansible-playbook worker.yaml -k -K
That’s it, we are good with setting up the Kubernetes cluster.
1 Playbook to Install Kubernetes cluster with Ansible
If you are interested to put all the plays in a single playbook you can do the same similar to below.
This guide was updated on 11th December 2020 with Containerd by replacing Docker.
Playbook with Containerd as Container Runtimes
To install and configure with Containerd instead of Docker.
---
- hosts: "masters, workers"
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Make the Swap inactive
command: swapoff -a
- name: Remove Swap entry from /etc/fstab.
lineinfile:
dest: /etc/fstab
regexp: swap
state: absent
- name: Create a empty file for containerd module.
copy:
content: ""
dest: /etc/modules-load.d/containerd.conf
force: no
- name: Configure module for containerd.
blockinfile:
path: /etc/modules-load.d/containerd.conf
block: |
overlay
br_netfilter
- name: Create a empty file for kubernetes sysctl params.
copy:
content: ""
dest: /etc/sysctl.d/99-kubernetes-cri.conf
force: no
- name: Configure sysctl params for Kubernetes.
lineinfile:
path: /etc/sysctl.d/99-kubernetes-cri.conf
line: "{{ item }}"
with_items:
- 'net.bridge.bridge-nf-call-iptables = 1'
- 'net.ipv4.ip_forward = 1'
- 'net.bridge.bridge-nf-call-ip6tables = 1'
- name: Apply sysctl params without reboot.
command: sysctl --system
- name: Installing Prerequisites for Kubernetes
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- vim
- software-properties-common
state: present
- name: Add Dockerโs official GPG key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable
state: present
filename: docker
update_cache: yes
- name: Install containerd.
apt:
name:
- containerd.io
state: present
- name: Configure containerd.
file:
path: /etc/containerd
state: directory
- name: Configure containerd.
shell: /usr/bin/containerd config default > /etc/containerd/config.toml
- name: Enable containerd service, and start it.
systemd:
name: containerd
state: restarted
enabled: yes
daemon-reload: yes
- name: Add Google official GPG key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add Kubernetes Repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
state: present
filename: kubernetes
mode: 0600
- name: Installing Kubernetes Cluster Packages.
apt:
name:
- kubeadm
- kubectl
- kubelet
state: present
- name: Enable service kubelet, and enable persistently
service:
name: kubelet
enabled: yes
- name: Reboot all the kubernetes nodes.
reboot:
post_reboot_delay: 10
reboot_timeout: 40
connect_timeout: 60
test_command: uptime
- pause: seconds=20
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
vars_prompt:
- name: "pod_network_cidr"
prompt: "Enter the Pod Network CIDR, example: 192.168.100.0/24"
private: no
- name: "k8s_master_ip"
prompt: "Enter the Apiserver advertise address, example: 192.168.0.26"
private: no
- name: "pod_network_manifest_file"
prompt: "Enter the Pod network manifest file URL, Your choice could be flannel, weave or calico, etc."
private: no
- name: "rbac_manifest_file"
prompt: "Enter the RBAC manifest file URL"
private: no
tasks:
- name: Intilizing Kubernetes Cluster
command: kubeadm init --pod-network-cidr "{{ pod_network_cidr }}" --apiserver-advertise-address "{{ k8s_master_ip }}"
run_once: true
delegate_to: "{{ k8s_master_ip }}"
- pause: seconds=30
- name: Create directory for kube config.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ansible_user }}/.kube
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
- name: Copy /etc/kubernetes/admin.conf to user home directory /home/{{ ansible_user }}/.kube/config.
become_user: root
become_method: sudo
become: yes
copy:
src: /etc/kubernetes/admin.conf
dest: /home/{{ ansible_user }}/.kube/config
remote_src: yes
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
- pause: seconds=10
- name: Remove the cache directory.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ ansible_user }}/.kube/cache
state: absent
- name: Create Pod Network & RBAC.
become_user: ansible
become_method: sudo
become: yes
command: "{{ item }}"
with_items:
- kubectl apply -f {{ pod_network_manifest_file }}
- kubectl apply -f {{ rbac_manifest_file }}
- pause: seconds=30
- name: Get the token for joining the nodes with Kuberentes master.
shell: kubeadm token create --print-join-command
register: kubernetes_join_command
- debug:
msg: "{{ kubernetes_join_command.stdout }}"
- name: Copy join command to local file.
become: false
local_action: copy content="{{ kubernetes_join_command.stdout_lines[0] }}" dest="/tmp/kubernetes_join_command" mode=0777
- hosts: workers
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Copy join command to worker nodes.
become: yes
become_method: sudo
become_user: root
copy:
src: /tmp/kubernetes_join_command
dest: /tmp/kubernetes_join_command
mode: 0777
- name: Join the Worker nodes with master.
become: yes
become_method: sudo
become_user: root
command: sh /tmp/kubernetes_join_command
register: joined_or_not
- debug:
msg: "{{ joined_or_not.stdout }}"
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Configure kubectl command auto completion.
lineinfile:
dest: /home/{{ ansible_user }}/.bashrc
line: 'source <(kubectl completion bash)'
insertafter: EOF
...
Version of containerd
ansible@k8mas1:~$ containerd --version
containerd containerd.io 1.4.3 269548fa27e0089a8b8278fc4fc781d7f65a939b
ansible@k8mas1:~$
ansible@k8mas1:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8mas1 Ready control-plane,master 45m v1.20.0
k8nod1 Ready <none> 44m v1.20.0
k8nod2 Ready <none> 44m v1.20.0
ansible@k8mas1:~$
ansible@k8mas1:~$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8mas1 Ready control-plane,master 107m v1.20.0 192.168.0.26 <none> Ubuntu 18.04.5 LTS 4.15.0-112-generic containerd://1.4.3
k8nod1 Ready <none> 105m v1.20.0 192.168.0.27 <none> Ubuntu 18.04.5 LTS 4.15.0-112-generic containerd://1.4.3
k8nod2 Ready <none> 105m v1.20.0 192.168.0.28 <none> Ubuntu 18.04.5 LTS 4.15.0-112-generic containerd://1.4.3
ansible@k8mas1:~$
Playbook with Docker as Container Runtimes
Below Playbook is an old one with Docker as Container runtimes.
---
- hosts: "masters, workers"
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Make the Swap inactive
command: swapoff -a
- name: Remove Swap entry from /etc/fstab.
lineinfile:
dest: /etc/fstab
regexp: swap
state: absent
- name: Installing Prerequisites for Kubernetes
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- vim
- software-properties-common
state: present
- name: Add Dockerโs official GPG key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable
state: present
filename: docker
mode: 0600
- name: Install Docker Engine.
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
- name: Enable service docker, and enable persistently
service:
name: docker
enabled: yes
- name: Add Google official GPG key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add Kubernetes Repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
state: present
filename: kubernetes
mode: 0600
- name: Installing Kubernetes Cluster Packages.
apt:
name:
- kubeadm
- kubectl
- kubelet
state: present
- name: Enable service kubelet, and enable persistently
service:
name: kubelet
enabled: yes
- name: Reboot all the kubernetes nodes.
reboot:
post_reboot_delay: 10
reboot_timeout: 40
connect_timeout: 60
test_command: uptime
- pause: seconds=20
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
vars_prompt:
- name: "pod_network_cidr"
prompt: "Enter the Pod Network CIDR, example: 192.168.100.0/24"
private: no
- name: "k8s_master_ip"
prompt: "Enter the Apiserver advertise address, example: 192.168.0.26"
private: no
- name: "pod_network_manifest_file"
prompt: "Enter the Pod network manifest file URL, Your choice could be flannel, weave or calico, etc."
private: no
- name: "rbac_manifest_file"
prompt: "Enter the RBAC manifest file URL"
private: no
tasks:
- name: Intilizing Kubernetes Cluster
command: kubeadm init --pod-network-cidr "{{ pod_network_cidr }}" --apiserver-advertise-address "{{ k8s_master_ip }}"
run_once: true
delegate_to: "{{ k8s_master_ip }}"
- pause: seconds=30
- name: Create directory for kube config.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ansible_user }}/.kube
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
- name: Copy /etc/kubernetes/admin.conf to user home directory /home/{{ ansible_user }}/.kube/config.
become_user: root
become_method: sudo
become: yes
copy:
src: /etc/kubernetes/admin.conf
dest: /home/{{ ansible_user }}/.kube/config
remote_src: yes
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
- pause: seconds=10
- name: Remove the cache directory.
become_user: ansible
become_method: sudo
become: yes
file:
path: /home/{{ ansible_user }}/.kube/cache
state: absent
- name: Create Pod Network & RBAC.
become_user: ansible
become_method: sudo
become: yes
command: "{{ item }}"
with_items:
- kubectl apply -f {{ pod_network_manifest_file }}
- kubectl apply -f {{ rbac_manifest_file }}
- pause: seconds=30
- name: Get the token for joining the nodes with Kuberentes master.
shell: kubeadm token create --print-join-command
register: kubernetes_join_command
- debug:
msg: "{{ kubernetes_join_command.stdout }}"
- name: Copy join command to local file.
become: false
local_action: copy content="{{ kubernetes_join_command.stdout_lines[0] }}" dest="/tmp/kubernetes_join_command" mode=0777
- hosts: workers
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Copy join command to worker nodes.
become: yes
become_method: sudo
become_user: root
copy:
src: /tmp/kubernetes_join_command
dest: /tmp/kubernetes_join_command
mode: 0777
- name: Join the Worker nodes with the master.
become: yes
become_method: sudo
become_user: root
command: sh /tmp/kubernetes_join_command
register: joined_or_not
- debug:
msg: "{{ joined_or_not.stdout }}"
- hosts: masters
remote_user: ansible
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- name: Configure kubectl command auto-completion.
lineinfile:
dest: /home/{{ ansible_user }}/.bashrc
line: 'source <(kubectl completion bash)'
insertafter: EOF
...
Running all in one playbook too works fine. Output for your reference.
TASK [Configure kubectl command auto completion.] ****************************************************************
changed: [master]
PLAY RECAP *******************************************************************************************************
master : ok=28 changed=15 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker1 : ok=17 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker2 : ok=17 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@gateway ~]$
In case, if the installation fails at any stage, run the below command on all three nodes and re-run the playbook.
$ sudo kubeadm reset --ignore-preflight-errors=all
That’s it, we have successfully completed the installing Kubernetes cluster with ansible.
Conclusion
Install Kubernetes Cluster with Ansible, To ease the cluster setup we have created with Ansible playbook. Usually, the manual step-by-step installation will take more time. By using Ansible, it can be completed within 5 minutes. Subscribe to our newsletter to receive more automation-related articles.
This is great stuff, thank you!
In replicating it myself, I’ve tweaked your “Installing Kubernetes & Docker Packages” play to only report as “changed” when the swap has actually been disabled. It’s a bit hacky and I’m sure there’s a neater way but in case you’re interested:
– name: Make the Swap inactive
shell: |
before=$(wc -l /proc/swaps)
swapoff -a
after=$(wc -l /proc/swaps)
if [ “$before” != “$after” ]; then echo CHANGED;fi
register: swapoff
changed_when: ‘”CHANGED” in swapoff.stdout’
Superb work this is going to be helpful for lots of peoples.
Excellent work done.