Automate Kubernetes Cluster Using Ansible

Kubernetes

Ansible

WordPress

MySQL

Ansible Installation and Configuration

yum install python3 -y

pip3 install ansible -y

vim /etc/ansible/ansible.cfg
[defaults]
inventory=/root/ip.txt #inventory path
host_key_checking=False
command_warnings=False
deprecation_warnings=False
ask_pass=False
roles_path= /root/roles #roles path
force_valid_group_names = ignore
private_key_file= /root/arthkey.pem #your key-pair
remote_user=ec2-user

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

Create Ansible Roles

cd /roles
# ansible-galaxy init <role_name>

ansible-galaxy init kube_cluster
ansible-galaxy init k8s_master
ansible-galaxy init k8s_slave
ansible-galaxy init wordpress_mysql

Write role for Kubernetes Cluster

cd /roles/kube_cluster/tasksvim main.yml
- name: Installing boto & boto3 libraries
pip:
name: "{{ item }}"
state: present
loop: "{{ lib_names }}"

- name: Creating Security Group for K8s Cluster
ec2_group:
name: "{{ sg_name }}"
description: Security Group for allowing all port
region: "{{ region_name }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
rules:
- proto: all
cidr_ip: 0.0.0.0/0
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0

- name: Launching three EC2 instances on AWS
ec2:
key_name: "{{ keypair }}"
instance_type: "{{ instance_flavour }}"
image: "{{ ami_id }}"
wait: true
group: "{{ sg_name }}"
count: 1
vpc_subnet_id: "{{ subnet_name }}"
assign_public_ip: yes
region: "{{ region_name }}"
state: present
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
instance_tags:
Name: "{{ item }}"
register: ec2
loop: "{{ instance_tag }}"

- name: Add 1st instance to host group ec2_master
add_host:
hostname: "{{ ec2.results[0].instances[0].public_ip }}"
groupname: ec2_master

- name: Add 2nd instance to host group ec2_slave
add_host:
hostname: "{{ ec2.results[1].instances[0].public_ip }}"
groupname: ec2_slave

- name: Add 3rd instance to host group ec2_slave
add_host:
hostname: "{{ ec2.results[2].instances[0].public_ip }}"
groupname: ec2_slave

- name: Waiting for SSH
wait_for:
host: "{{ ec2.results[2].instances[0].public_dns_name }}"
port: 22
state: started
cd /roles/kube_cluster/varsvim main.yml
instance_tag:
- master
- slave1
- slave2
lib_names:
- boto
- boto3
sg_name: Allow_All_SG
region_name: ap-south-1
subnet_name: subnet-49f0e521
ami_id: ami-010aff33ed5991201
keypair: awskey
instance_flavour: t2.small

Write role for Kubernetes Master

cd /roles/k8s_master/tasksvim main.yml
- name: "Installing docker and iproute-tc"
package:
name:
- docker
- iproute-tc
state: present
- name: "Configuring the Yum repo for kubernetes"
yum_repository:
name: kubernetes
description: Yum for k8s
baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled: yes
gpgcheck: yes
repo_gpgcheck: yes
gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
- name: "Installing kubeadm,kubelet kubectl program"
yum:
name:
- kubelet
- kubectl
- kubeadm
state: present
- name: "Enabling the docker and kubenetes"
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- kubelet
- docker
- name: "Pulling the config images"
shell: kubeadm config images pull
- name: "Confuring the docker daemon.json file"
copy:
dest: /etc/docker/daemon.json
content: |
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
- name: "Restarting the docker service"
service:
name: docker
state: restarted
- name: "Configuring the Ip tables and refreshing sysctl"
copy:
dest: /etc/docker/daemon.json
content: |
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
- name: "systemctl"
shell: "sysctl --system"
- name: "Starting kubeadm service"
shell: "kubeadm init --ignore-preflight-errors=all"
- name: "Creating .kube Directory"
file:
path: $HOME/.kube
state: directory
- name: "Copying file config file"
shell: "cp -i /etc/kubernetes/admin.conf $HOME/.kube/config"
ignore_errors: yes
- name: "Installing Addons e.g flannel"
shell: "kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml"
- name: "Creating the token"
shell: "kubeadm token create --print-join-command"
register: token
- debug:
msg: "{{ token.stdout }}"

Write role for Kubernetes Slaves

cd /roles/k8s_slave/tasksvim main.yml
- name: "Installing docker and iproute-tc"
package:
name:
- docker
- iproute-tc
state: present
- name: "Configuring the Yum repo for kubernetes"
yum_repository:
name: kubernetes
description: Yum for k8s
baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled: yes
gpgcheck: yes
repo_gpgcheck: yes
gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
- name: "Installing kubeadm,kubelet kubectl program"
yum:
name:
- kubelet
- kubectl
- kubeadm
state: present
- name: "Enabling the docker and kubenetes"
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- kubelet
- docker
- name: "Pulling the config images"
shell: kubeadm config images pull
- name: "Confuring the docker daemon.json file"
copy:
dest: /etc/docker/daemon.json
content: |
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
- name: "Restarting the docker service"
service:
name: docker
state: restarted
- name: "Configuring the Ip tables and refreshing sysctl"
copy:
dest: /etc/sysctl.d/k8s.conf
content: |
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
- name: "systemctl"
shell: "sysctl --system"
- name: joining to Master
command: "{{ hostvars[groups['ec2_master'][0]]['token']['stdout'] }}"

Write role for Wordpress and MySQL Setup

cd /roles/wordpress_mysql/filesvim wordpress.ymlvim pvc_wordpress.ymlvim mysql.ymlvim pvc_mysql.ymlvim secret.yml
apiVersion: v1
kind: Service
metadata:
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
nodePort: 30333
selector:
app: wordpress
tier: frontend
type: LoadBalancer
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wordpress-pv-claim
containers:
- image: wordpress:4.8-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysqlsecret
key: password
ports:
- containerPort: 80
name: wordpress
volumes:
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pv-claim
labels:
app: wordpress
tier: frontend
spec:
storageClassName: ""
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: wordpress-pv
spec:
storageClassName: ""
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /wordpressdata
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysqlsecret
key: password
- name: MYSQL_USER
value: udit
- name: MYSQL_DATABASE
value: task23db
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: wordpress
tier: mysql
spec:
storageClassName: ""
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: msql-pv
spec:
storageClassName: ""
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /mysqldata
apiVersion: v1
kind: Secret
metadata:
name: Rutvik
data:
password: MySql@2021
cd /roles/wordpress_mysql/tasksvim main.yml
- name: Copying Wordpress and MySQL files to K8s Master Node
copy:
src: "{{ item }}"
dest: /root/
loop:
- mysql.yml
- pvc_mysql.yml
- pvc_wordpress.yml
- secret.yml
- wordpress.yml
- name: Creating directory over which MySQL container mounts the PersistentVolume at /var/lib/mysql.
file:
path: /mysqldata
state: directory
- name: Creating directory over which WordPress container mounts the PersistentVolume at /var/www/html.
file:
path: /wordpressdata
state: directory
- name: Configuration and Setup of Wordpress and MySQL
shell: "kubectl create -f /root/{{ item }}"
loop:
- mysql.yml
- pvc_mysql.yml
- pvc_wordpress.yml
- wordpress.yml

Write Ansible Vault Files

# ansible-vault create <filename>.ymlansible-vault create cred.yml
access_key: XXXXXXXXXXXXXXXXXXX
secret_key: XXXXXXXXXXXXXXXXXXX

Create Setup file

- hosts: localhost
gather_facts: no
vars_files:
- cred.yml
tasks:
- name: "Running kube_cluster role"
include_role:
name: kube_cluster
- hosts: ec2_master
gather_facts: no
tasks:
- name: Running K8s_Master Role
include_role:
name: k8s_master
- hosts: ec2_slave
gather_facts: no
tasks:
- name: Running K8s_Slave Role
include_role:
name: k8s_slave
- hosts: ec2_master
gather_facts: no
tasks:
- name: Running Wordpress-MySQL Role
include_role:
name: wordpress_mysql

Run Ansible Playbook

ansible-playbook setup.yml --ask-vault-pass

Testing

kubectl get nodes

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store