Introduction
This article to show Kubernetes installation using Ansible on Ubuntu 20.04.
# Our lab setup as follow:
#
# Container Runtime : Containerd
# Pod CIDR : 192.168.3.0/24
# Advertised API address : 192.168.1.108
# Pod network : calico
# Latest calico manifest file as of this writing:
# https://docs.projectcalico.org/archive/v3.19/manifests/calico.yaml
# List the latest release
# https://docs.projectcalico.org/releases
#
# RBAC manifest file
# https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
#
# Servers
# k8s master
192.168.1.108 k8s5gcms01 k8s5gcms01.subok-tech.local
# k8s workers
192.168.1.149 k8s5gcn1 k8s5gcn1.subok-tech.local
192.168.1.112 k8s5gcn2 k8s5gcn2.subok-tech.local
Install required packages
Next is to install packages and configure the master and workers with the required settings
# k8s_containrd_pkg.yml
---
- hosts: "masters, workers"
remote_user: k8s5gc
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: 60
reboot_timeout: 80
connect_timeout: 300
test_command: uptime
...
# Execute k8s_master_init.yml
$ ansible-playbook k8s_containrd_pkg.yml -k -K
# OUTPUT
SSH password:
BECOME password[defaults to SSH password]:
PLAY [masters, workers] ********************************************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************************************************
ok: [master]
ok: [worker1]
ok: [worker2]
TASK [Make the Swap inactive] **************************************************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [Remove Swap entry from /etc/fstab.] **************************************************************************************************************************************************************
changed: [worker2]
changed: [master]
changed: [worker1]
TASK [Create a empty file for containerd module.] ******************************************************************************************************************************************************
changed: [worker1]
changed: [worker2]
changed: [master]
TASK [Configure module for containerd.] ****************************************************************************************************************************************************************
changed: [worker1]
changed: [worker2]
changed: [master]
TASK [Create a empty file for kubernetes sysctl params.] ***********************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [Configure sysctl params for Kubernetes.] *********************************************************************************************************************************************************
changed: [master] => (item=net.bridge.bridge-nf-call-iptables = 1)
changed: [worker1] => (item=net.bridge.bridge-nf-call-iptables = 1)
changed: [worker2] => (item=net.bridge.bridge-nf-call-iptables = 1)
changed: [master] => (item=net.ipv4.ip_forward = 1)
changed: [worker1] => (item=net.ipv4.ip_forward = 1)
changed: [worker2] => (item=net.ipv4.ip_forward = 1)
changed: [master] => (item=net.bridge.bridge-nf-call-ip6tables = 1)
changed: [worker2] => (item=net.bridge.bridge-nf-call-ip6tables = 1)
changed: [worker1] => (item=net.bridge.bridge-nf-call-ip6tables = 1)
TASK [Apply sysctl params without reboot.] *************************************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [Installing Prerequisites for Kubernetes] *********************************************************************************************************************************************************
changed: [master]
changed: [worker2]
changed: [worker1]
TASK [Add Docker’s official GPG key] *******************************************************************************************************************************************************************
changed: [worker2]
changed: [worker1]
changed: [master]
TASK [Add Docker Repository] ***************************************************************************************************************************************************************************
changed: [master]
changed: [worker2]
changed: [worker1]
TASK [Install containerd.] *****************************************************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [Configure containerd.] ***************************************************************************************************************************************************************************
ok: [worker1]
ok: [worker2]
ok: [master]
TASK [Configure containerd.] ***************************************************************************************************************************************************************************
changed: [worker1]
changed: [worker2]
changed: [master]
TASK [Enable containerd service, and start it.] ********************************************************************************************************************************************************
changed: [master]
changed: [worker2]
changed: [worker1]
TASK [Add Google official GPG key] *********************************************************************************************************************************************************************
changed: [worker1]
changed: [worker2]
changed: [master]
TASK [Add Kubernetes Repository] ***********************************************************************************************************************************************************************
changed: [master]
changed: [worker2]
changed: [worker1]
TASK [Installing Kubernetes Cluster Packages.] *********************************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [Enable service kubelet, and enable persistently] *************************************************************************************************************************************************
ok: [master]
ok: [worker1]
ok: [worker2]
TASK [Reboot all the kubernetes nodes.] ****************************************************************************************************************************************************************
changed: [master]
changed: [worker1]
changed: [worker2]
PLAY RECAP *********************************************************************************************************************************************************************************************
master : ok=20 changed=17 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker1 : ok=20 changed=17 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker2 : ok=20 changed=17 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Kubernetes Master
# k8s_master_init.yml
- hosts: masters
remote_user: k8s5gc
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: k8s5gc
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=30
- name: Remove the cache directory.
become_user: k8s5gc
become_method: sudo
become: yes
file:
path: /home/{{ ansible_user }}/.kube/cache
state: absent
- name: Create Pod Network & RBAC.
become_user: k8s5gc
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
...
# Execute k8s_master_init.yml
$ ansible-playbook k8s_master_init.yml -k -K
# OUTPUT
SSH password:
BECOME password[defaults to SSH password]:
Enter the Pod Network CIDR, example: 192.168.100.0/24: 192.168.3.0/24
Enter the Apiserver advertise address, example: 192.168.0.26: 192.168.1.108
Enter the Pod network manifest file URL, Your choice could be flannel, weave or calico, etc.: https://docs.projectcalico.org/archive/v3.19/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 [Gathering Facts] *********************************************************************************************************************************************************************************
ok: [master]
TASK [Intilizing Kubernetes Cluster] *******************************************************************************************************************************************************************
changed: [master -> 192.168.1.108]
TASK [pause] *******************************************************************************************************************************************************************************************
Pausing for 30 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [master]
TASK [Create directory for kube config.] ***************************************************************************************************************************************************************
changed: [master]
TASK [Copy /etc/kubernetes/admin.conf to user home directory /home/k8s5gc/.kube/config.] ***************************************************************************************************************
changed: [master]
TASK [pause] *******************************************************************************************************************************************************************************************
Pausing for 30 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [master]
TASK [Remove the cache directory.] *********************************************************************************************************************************************************************
ok: [master]
TASK [Create Pod Network & RBAC.] **********************************************************************************************************************************************************************
changed: [master] => (item=kubectl apply -f https://docs.projectcalico.org/archive/v3.19/manifests/calico.yaml)
changed: [master] => (item=kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml)
TASK [pause] *******************************************************************************************************************************************************************************************
Pausing for 30 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [master]
TASK [Get the token for joining the nodes with Kuberentes master.] *************************************************************************************************************************************
changed: [master]
TASK [debug] *******************************************************************************************************************************************************************************************
ok: [master] => {
"msg": "kubeadm join 192.168.1.108:6443 --token 6frq3s.s3vb10mk0mr8ptjz --discovery-token-ca-cert-hash sha256:e6adf7f44bf2469215050d8c184973a5c9dbebc9668800b610c6315f8536d74d "
}
TASK [Copy join command to local file.] ****************************************************************************************************************************************************************
changed: [master -> localhost]
PLAY RECAP *********************************************************************************************************************************************************************************************
master : ok=12 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Add Workers to the cluster
Next step is to add our worker nodes. As first step we have to get token from k8s master and will be use in the join command from the workers.
# k8s_workers.yml
---
- hosts: masters
remote_user: k8s5gc
become: yes
become_method: sudo
become_user: root
gather_facts: yes
connection: ssh
tasks:
- 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: k8s5gc
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: k8s5gc
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
...
# execute the yaml as follow:
ansible-playbook k8s_workers.yml -k -K
r$ ansible-playbook k8s_workers.yml -k -K
SSH password:
BECOME password[defaults to SSH password]:
PLAY [masters] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************
ok: [master]
TASK [Get the token for joining the nodes with Kuberentes master.] ************************************************************************************************************************************
changed: [master]
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [master] => {
"msg": "kubeadm join 192.168.1.108:6443 --token v19ipo.gte8b2vh2ed342sf --discovery-token-ca-cert-hash sha256:e6adf7f44bf2469215050d8c184973a5c9dbebc9668800b610c6315f8536d74d "
}
TASK [Copy join command to local file.] ***************************************************************************************************************************************************************
changed: [master -> localhost]
PLAY [workers] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************
ok: [worker2]
ok: [worker1]
ok: [worker3]
TASK [Copy join command to worker nodes.] *************************************************************************************************************************************************************
changed: [worker1]
changed: [worker2]
changed: [worker3]
TASK [Join the Worker nodes with the master.] *********************************************************************************************************************************************************
changed: [worker3]
changed: [worker1]
changed: [worker2]
TASK [debug] ******************************************************************************************************************************************************************************************
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 -o yaml'\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: [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 -o yaml'\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: [worker3] => {
"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 -o yaml'\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=6 changed=3 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
worker3 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
k8s5gc@k8s5gcans1:~/k8s5gc-cluster$
Although more than 20years working on Mobile Telecommunications – Core Network. Always wanting to learn and try new things.