Skip to main content

K8s Cluster on AWS Using Ansible

This project consists of using only Ansible to create a Kubernetes cluster on AWS and utilize essential resources to know for those who work directly with Ansible. Although Terraform in my opinion is the best tool for cloud provisioning, we can also do this via Ansible. Of course, we could combine the best of both tools along with Packer, but we'll stick with Ansible only to gain more knowledge.

For this project, we'll learn how to create a good directory structure for your playbooks and how to separate files in order to make it very practical to manage and maintain. For this, Ansible provides a command called ansible-galaxy that helps create a very good directory structure. Additionally, ansible-galaxy is used to install module collections developed by the community.

Requirements​

Project Phases​

  • 1 Provisioning => In this phase we need to build the infrastructure on AWS
  • 2 Setup => We need to install and configure the cluster
  • 3 Deploy => We'll deploy an example application on the cluster
  • 4 Monitoring => We'll install Prometheus and Grafana to monitor our cluster

Directory Structure​

Inside the ./src/ folder is where the project will actually happen. This directory will contain the phase directories.

Inside each phase we'll have the following files.

  • the hosts, our inventory for each phase
  • The ansible.cfg file to have our Ansible configurations for each phase
  • The roles directory that will actually have our playbooks
  • A README.md explaining each phase of the project
~/projects/ansible/study-ansible/Projeto K8S Cluster main !5 ?2                                                                                                                    1.1.7 11:51:00
❯ touch ansible.cfg hosts main.yml

We're going to create a folder called roles that will contain our playbooks, our tasks. For this, we'll use the binary called ansible-galaxy. Along with Ansible come several binaries that help us besides galaxy, worth checking out.

![Ansible Binaries](./docs/iac/ansible/Projeto K8S Cluster/pics/binarios%20ansibles.jpg)

Let's set up the directories referring to the phases.

~/projects/ansible/study-ansible/Projeto K8S Cluster main !5 ?2                                                                                                                    1.1.7 11:41:43
❯ cd roles

~/projects/ansible/study-ansible/Projeto K8S Cluster/roles main !5 ?2 1.1.7 11:41:48
❯ ansible-galaxy init provisioning
- Role provisioning was created successfully

~/projects/ansible/study-ansible/Projeto K8S Cluster/roles main !5 ?2 1.1.7 11:41:59
❯ ansible-galaxy init setup
- Role setup was created successfully

~/projects/ansible/study-ansible/Projeto K8S Cluster/roles main !5 ?2 1.1.7 11:42:05
❯ ansible-galaxy init deploy_app
- Role deploy_app was created successfully

~/projects/ansible/study-ansible/Projeto K8S Cluster/roles main !5 ?2 1.1.7 11:42:21
❯ ansible-galaxy init deploy_monitoring
- Role deploy_monitoring was created successfully

~/projects/ansible/study-ansible/Projeto K8S Cluster/roles main !5 ?2 1.1.7 11:42:28

Inside each of our tasks can exist sub-tasks, or even sub-sub-tasks. So it will be necessary to create a roles folder inside each of our initial roles, but we'll do this along the way as needed.

~/projects/ansible/study-ansible/Projeto K8S Cluster main !5 ?2                                                                                                                    1.1.7 11:51:11
❯ tree
.
β”œβ”€β”€ ansible.cfg
β”œβ”€β”€ hosts
β”œβ”€β”€ main.yml
β”œβ”€β”€ pics
β”‚ └── binarios ansibles.jpg
β”œβ”€β”€ README.md
└── roles
β”œβ”€β”€ deploy_app
β”‚ β”œβ”€β”€ defaults
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ files
β”‚ β”œβ”€β”€ handlers
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ meta
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ README.md
β”‚ β”œβ”€β”€ tasks
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ templates
β”‚ β”œβ”€β”€ tests
β”‚ β”‚ β”œβ”€β”€ inventory
β”‚ β”‚ └── test.yml
β”‚ └── vars
β”‚ └── main.yml
β”œβ”€β”€ deploy_monitoring
β”‚ β”œβ”€β”€ defaults
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ files
β”‚ β”œβ”€β”€ handlers
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ meta
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ README.md
β”‚ β”œβ”€β”€ tasks
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ templates
β”‚ β”œβ”€β”€ tests
β”‚ β”‚ β”œβ”€β”€ inventory
β”‚ β”‚ └── test.yml
β”‚ └── vars
β”‚ └── main.yml
β”œβ”€β”€ provisioning
β”‚ β”œβ”€β”€ defaults
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ files
β”‚ β”œβ”€β”€ handlers
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ meta
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ README.md
β”‚ β”œβ”€β”€ tasks
β”‚ β”‚ └── main.yml
β”‚ β”œβ”€β”€ templates
β”‚ β”œβ”€β”€ tests
β”‚ β”‚ β”œβ”€β”€ inventory
β”‚ β”‚ └── test.yml
β”‚ └── vars
β”‚ └── main.yml
└── setup
β”œβ”€β”€ defaults
β”‚ └── main.yml
β”œβ”€β”€ files
β”œβ”€β”€ handlers
β”‚ └── main.yml
β”œβ”€β”€ meta
β”‚ └── main.yml
β”œβ”€β”€ README.md
β”œβ”€β”€ tasks
β”‚ └── main.yml
β”œβ”€β”€ templates
β”œβ”€β”€ tests
β”‚ β”œβ”€β”€ inventory
β”‚ └── test.yml
└── vars
└── main.yml

38 directories, 37 files

Hosts - Details​

About hosts it's worth learning some things https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html

If you see the documentation you'll notice that it's possible to pass variables to all hosts or specific hosts.

Define what the Python interpreter path is, this prevents it from searching around and if it's not in the path giving some kind of error for this we define ansible_python_interpreter

let's start with a hosts like this:

# global variables
[all:vars]
ansible_python_interpreter=/usr/bin/python
ntp_server=br.pool.ntp.org

[local]
localhost

# local group variables
[local:vars]
ansible_connection=local
gather_facts=false

# will be filled later automatically
[kubernetes]

Main.yml - Details​

This will only serve to make includes (call another file) of our phases according to what we're doing, so it will be filled according to our development, but let's leave the first call as an example.

---
# Only includes here of the tasks
- include: provisioning

Learning During the Project​

The use of tags is interesting because you can execute only a specific playbook, or even deny some.

will only execute tagA and tagB

ansible-playbook -i hosts main.yml --tags "tagA,tagB"

won't execute tagA and tagB

ansible-playbook -i hosts main.yml --skip-tags "tagA,tagB"