Table of Contents

What are Kubernetes and Ansible? Kubernetes is the most popular opensource container orchestration platform built to host microservices and containers with platform functions such as high availability and self-healing and Ansible is a configuration management tool to automate steps to perform a series of code execution that sets up a virtual machine for example with usernames and ssh keys configured. In this tutorial, we're going to use Ansible to script playbooks to completely automate the setup of a Kubernetes cluster with 4 virtual machines.

Prerequisite Initial Steps

The initial first step would be to set up Ansible and your Ansible repository where you will run your Ansible playbooks from. In the inventory file set the ansible_user var the same as the user account you are going to use to set up the Kubernetes cluster. Follow the steps in this article to setup Ansible inside a Git repository:

How To Set Up Ansible Inside A Github Repository And Automate Your Workloads
Ansible is an open-source configuration management and IT automation platform. Let’s jump in and set up our Ansible Github repository and run an example automation playbook.

The next step is to install the Ubuntu Linux systems and my choice was to create 4 virtual machines on my Proxmox Virtual Host which can be done with Terraform by following the steps in the tutorial below or you can set them up manually. This step will be different depending on where you install your virtual machines and what virtualization platform you use:

How To Deploy Virtual Machines To Proxmox With Terraform
How to build out multiple virtual machines on your proxmox virtual host with terraform.

Once both these steps are completed ensure that you set up your SSH key pairs on each virtual machine for ssh connection with Ansible.  Now we are ready to start scripting the Ansible playbooks and automate our Kubernetes Cluster setup.

Ansible Automated Deployment Setup For Kubernetes

Our first step is to check that Ansible can communicate and connect with all the virtual machines for the Kubernetes cluster. We will add the IP addresses of all the virtual machines in our inventory file like in the example below:

[k8s-master]
192.168.1.30

[k8s-workers]
192.168.1.31
192.168.1.32
192.168.1.33

Next, we will run a ping playbook to test the connection to all the virtual machines. The output of this step should look similar to the example below. Run the following command - ansible --key-file ~/.ssh/kube_rsa -i inventory all -m ping

192.168.1.32 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.1.33 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.1.30 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.1.31 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Set Up Kubernetes User Accounts

Ensure that your public ssh key id_rsa.pub is copied to each of the 4 virtual machines. Next, add  users.yml to your k8s directory in your Ansible repository and copy the playbook below.

- hosts: k8s-master, k8s-workers
  become: yes
  become_user: root
  vars_files:
    - ../../vars.yml
  tasks:
    - name: Create the kube user
      user: name=kube append=yes state=present createhome=yes shell=/bin/bash

    - name: Add kube user to sudo profiles and enable no password
      lineinfile:
        dest: /etc/sudoers
        line: 'kube ALL=(ALL) NOPASSWD: ALL'
        validate: 'visudo -cf %s'

    - name: Set ssh key for kube user
      authorized_key: user=kube key="{{item}}"
      with_file:
        - ~/.ssh/kube_rsa.pub

Execute this playbook by running the following command in your ansible terminal - ansible-playbook --key-file ~/.ssh/kube_rsa -i inventory  playbooks/k8s/users.yml. You should see an output upon success similar to the below output.

PLAY RECAP ******************************************************************************
192.168.1.30               : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.1.31               : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.1.32               : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.1.33               : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Install Kubernetes On All Nodes

The next step of this process is to set up  k8s-install.yml in the k8s directory in your ansible repo. This step will install Kubernetes, the container runtime containerd, and set the system settings for Kubernetes on each of the nodes.

---
- hosts: k8s-master, k8s-workers
  become: yes
  become_user: root
  become_method: sudo
  gather_facts: yes
  vars_files:
    - ../../vars.yml
  tasks:
    - name: Create containerd config file
      ansible.builtin.file:
        path: "/etc/modules-load.d/containerd.conf"
        state: "touch"

    - name: Add config for containerd
      blockinfile:
        path: "/etc/modules-load.d/containerd.conf"
        block: |
              overlay
              br_netfilter

    - name: modprobe
      shell: |
              sudo modprobe overlay
              sudo modprobe br_netfilter


    - name: Set system configs for Kubernetes networking
      file:
        path: "/etc/sysctl.d/99-kubernetes-cri.conf"
        state: "touch"

    - name: Add config for containerd
      blockinfile:
        path: "/etc/sysctl.d/99-kubernetes-cri.conf"
        block: |
              net.bridge.bridge-nf-call-iptables = 1
              net.ipv4.ip_forward = 1
              net.bridge.bridge-nf-call-ip6tables = 1

    - name: Apply new settings
      command: sudo sysctl --system

    - name: Install containerd
      shell: |
              sudo apt-get update && sudo apt-get install -y containerd
              sudo mkdir -p /etc/containerd
              sudo containerd config default | sudo tee /etc/containerd/config.toml
              sudo systemctl restart containerd

    - name: Disable swap
      shell: |
              sudo swapoff -a
              sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

    - name: Install and config dependencies
      shell: |
              sudo apt-get update && sudo apt-get install -y apt-transport-https curl
              curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

    - name: Create kubernetes repo file
      file:
        path: "/etc/apt/sources.list.d/kubernetes.list"
        state: "touch"

    - name: Add K8s source
      blockinfile:
        path: "/etc/apt/sources.list.d/kubernetes.list"
        block: |
              deb https://apt.kubernetes.io/ kubernetes-xenial main

    - name: Install kubernetes
      shell: |
              sudo apt-get update
              sudo apt-get install -y kubelet=1.20.1-00 kubeadm=1.20.1-00 kubectl=1.20.1-00
              sudo apt-mark hold kubelet kubeadm kubectl

Run the following command - ansible-playbook --key-file ~/.ssh/kube_rsa -i inventory  playbooks/k8s/k8s-install.yml to execute this playbook which should give you an output displayed below if all steps are completed successfully:

K8s Installation

Set Up The Kubernetes Master Node

The master node commonly referred to as the control plane is what we are going to set up with this playbook called master.yml. We will use flannel for our pod network and initialize the Kubernetes cluster.

---
- hosts: k8s-master
  become: yes
  vars_files:
    - ../../vars.yml
  tasks:
    - name: Initialize k8s cluster
      shell: kubeadm init --pod-network-cidr=10.244.0.0/16
      args:
        chdir: $HOME
        creates: cluster_initialized.txt

    - name: Set firewall rules UFW
      become: yes
      ansible.builtin.shell:  |
          sudo ufw allow 6443/tcp
          sudo ufw allow 2379/tcp
          sudo ufw allow 2380/tcp
          sudo ufw allow 10250/tcp
          sudo ufw allow 10251/tcp
          sudo ufw allow 10252/tcp
          sudo ufw allow 10255/tcp
          sudo ufw reload

    - name: Create .kube directory
      become_user: kube
      become: yes
      ansible.builtin.file:
        path: $HOME/.kube
        state: directory
        mode: '0755'

    - name: Copy admin.conf to user kube config
      copy:
        src: /etc/kubernetes/admin.conf
        dest: /home/kube/.kube/config
        remote_src: yes
        owner: kube

    - name: Install Pod network
      become: yes
      become_user: kube
      shell: kubectl apply -f https://github.com/coreos/flannel/raw/master/Documentation/kube-flannel.yml
      args:
        chdir: $HOME
        
    - name: Get token to join worker nodes to k8s cluster
      become: yes
      become_user: kube
      ansible.builtin.shell: kubeadm token create  --print-join-command
      register: kubernetes_join_command

    - name: Display k8s join command
      ansible.builtin.debug:
        msg: "{{ kubernetes_join_command.stdout }}"

    - name: Copy join command to local file on Ansible host
      become: yes
      local_action: copy content="{{ kubernetes_join_command.stdout_lines[0] }}" dest="/tmp/kubernetes_join_command" mode=0777

Run the following command - ansible-playbook --key-file ~/.ssh/kube_rsa -i inventory  playbooks/k8s/master.yml. Once the steps are complete the control plane or master node will be set up and you should see an output like this:

K8s Master

Join Worker Nodes To Kubernetes Cluster

Once the master node is ready the worker nodes should be joined to the Kubernetes cluster. Copy the playbook below which will set the firewall rules on the worker nodes and join the worker nodes to the Kubernetes cluster.

---
- hosts: k8s-workers
  become: yes
  gather_facts: yes
  vars_files:
    - ../../vars.yml
  tasks:
    - name: Set firewall rules UFW
      become: yes
      ansible.builtin.shell:  |
          sudo ufw allow 10251/tcp
          sudo ufw allow 10255/tcp
          sudo ufw reload

    - name: Copy join command from Ansible host to the worker nodes.
      become: yes
      copy:
        src: /tmp/kubernetes_join_command
        dest: /tmp/kubernetes_join_command
        mode: 0777

    - name: Join the Worker nodes to the cluster.
      become: yes
      command: sh /tmp/kubernetes_join_command
      register: joined_or_not

    - name: Node join status
      ansible.builtin.debug:
        msg: "{{ joined_or_not.stdout }}"

Run this command - ansible-playbook --key-file ~/.ssh/kube_rsa -i inventory  playbooks/k8s/workers.yml to join all the worker nodes. Once the playbook is executed successfully log into the master node and run kubectl get nodes which should display the following output. If some of your node show not ready give it a couple of minutes to get ready.

K8s Workers
NAME         STATUS   ROLES                  AGE     VERSION
k8s-master   Ready    control-plane,master   6m22s   v1.20.1
k8s-node1    Ready    <none>                 5m52s   v1.20.1
k8s-node2    Ready    <none>                 5m52s   v1.20.1
k8s-node3    Ready    <none>                 5m52s   v1.20.1

Automate This Process With One Playbook

If you created all the playbooks and do not want to execute the above playbooks one by one then you can additionally create the bootstrap.yml playbook and run it to perform all the above steps in sequence. Copy the below playbook and in your k8s directory name it bootstrap.yml.

K8s Ansible Repo
---
- name: Install kubernetes
  import_playbook: k8s-install.yml

- name: Bootstrap master node
  import_playbook: master.yml

- name: Join worker nodes to kube cluster
  import_playbook: workers.yml

Run the following command to automate all the playbooks' execution with one playbook - ansible-playbook --key-file ~/.ssh/kube_rsa -i inventory  playbooks/k8s/bootstrap.yml. Once completed login to the master node and run kubectl get nodes to see if your Kubernetes cluster is up and the worker nodes joined to the cluster.

NAME         STATUS   ROLES                  AGE     VERSION
k8s-master   Ready    control-plane,master   6m22s   v1.20.1
k8s-node1    Ready    <none>                 5m52s   v1.20.1
k8s-node2    Ready    <none>                 5m52s   v1.20.1
k8s-node3    Ready    <none>                 5m52s   v1.20.1

Once you confirm that the cluster is up and running and all the worker nodes are joined to the Kubernetes cluster you can go ahead and deploy a pod and start running applications on your Kubernetes cluster.

Conclusion

In conclusion, Kubernetes is the most popular container orchestration platform in the world and comes with support from a large open-source community. If you enjoyed this article consider signing up for our newsletter and don't forget to share it with people that would find it useful. Leave a comment below with a tutorial you would like us to cover.

Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Opensource Geeks.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.