Home » Installing Kubernetes using Ansible on Ubuntu 20.04

Installing Kubernetes using Ansible on Ubuntu 20.04

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$

Leave a Reply

Your email address will not be published. Required fields are marked *