In this project you will continue working with ansible-config-mgt
repository and make some improvements of your code. Now you need to refactor your Ansible code, create assignments, and learn how to use the imports functionality. Imports allow to effectively re-use previously created playbooks in a new playbook – it allows you to organize your tasks and reuse them when needed.
Before we begin, let us make some changes to our Jenkins job – now every new change in the codes creates a separate directory which is not very convenient when we want to run some commands from one place. Besides, it consumes space on Jenkins serves with each subsequent change. Let us enhance it by introducing a new Jenkins project/job – we will require Copy Artifact plugin
-
Go to your
Jenkins-Ansible
server and create a new directory calledansible-config-artifact
– we will store there all artifacts after each build. -
Change permissions to this directory, so Jenkins could save files there –
chmod -R 0777 /home/ubuntu/ansible-config-artifact
-
Go to Jenkins web console -> Manage Jenkins -> Manage Plugins -> on Available tab search for Copy Artifact and install this plugin without restarting Jenkins
-
Create a new Freestyle project (you have done it in Project 9) and name it
save_artifacts
. -
This project will be triggered by completion of your existing ansible project. Configure it accordingly:
Note: You can configure number of builds to keep in order to save space on the server, for example, you might want to keep only last 2 or 5 build results. You can also make this change to your
ansible
job. -
The main idea of
save_artifacts
project is to save artifacts into/home/ubuntu/ansible-config-artifact
directory. To achieve this, create a Build step and chooseCopy artifacts from other project
, specifyansible
as a source project and/home/ubuntu/ansible-config-artifact
as a target directory. -
Test your set up by making some change in README.MD file inside your
ansible-config-mgt
repository (right inside master branch).If both Jenkins jobs have completed one after another – you shall see your files inside
/home/ubuntu/ansible-config-artifact
directory and it will be updated with every commit to your master branch.Now your Jenkins pipeline is more neat and clean.
Before starting to refactor the codes, ensure that you have pulled down the latest code from master (main) branch, and created a new branch, name it refactor.
Let see code re-use in action by importing other playbooks.
-
Within
playbooks
folder, create a new file and name itsite.yml
– This file will now be considered as an entry point into the entire infrastructure configuration. Other playbooks will be included here as a reference. In other words,site.yml
will become a parent to all other playbooks that will be developed. Includingcommon.yml
that you created previously. Dont worry, you will understand more what this means shortly. -
Create a new folder in root of the repository and name it
static-assignments
. Thestatic-assignments
folder is where all other children playbooks will be stored. This is merely for easy organization of your work. It is not an Ansible specific concept, therefore you can choose how you want to organize your work. You will see why the folder name has a prefix of static very soon. For now, just follow along. -
Move
common.yml
file into the newly createdstatic-assignments
folder. -
Inside
site.yml
file, importcommon.yml
playbook.--- - hosts: all - import_playbook: ../static-assignments/common.yml
The code above uses built in import_playbook Ansible module.
-
Run
ansible-playbook
command against thedev
environmentSince you need to apply some tasks to your
dev
servers andwireshark
is already installed – you can go ahead and create another playbook understatic-assignments
and name itcommon-del.yml
. In this playbook, configure deletion ofwireshark
utility.--- - name: update web, nfs and db servers hosts: webservers, nfs, db remote_user: ec2-user become: yes become_user: root tasks: - name: delete wireshark yum: name: wireshark state: removed - name: update LB server hosts: lb remote_user: ubuntu become: yes become_user: root tasks: - name: delete wireshark apt: name: wireshark-qt state: absent autoremove: yes purge: yes autoclean: yes
NOTE: You may have to follow the steps below to configure the ansible inventory path
- Change the inventory file path in the
/etc/ansible/ansible.cfg
file, to correct folder containing all hosts
- Test to see if ansible can connect to all hosts
ansible all -m ping
update
site.yml
with -import_playbook: ../static-assignments/common-del.yml
instead ofcommon.yml
and run it againstdev
servers:cd /home/ubuntu/ansible-config-artifact/ ansible-playbook -i inventory/dev.yml playbooks/site.yml
Make sure that
wireshark
is deleted on all the servers by runningwireshark --version
Now you have learned how to use
import_playbooks
module and you have a ready solution to install/delete packages on multiple servers with just one command. - Change the inventory file path in the
We have our nice and clean dev
environment, so let us put it aside and configure 2 new Web Servers as uat
. We could write tasks to configure Web Servers in the same playbook, but it would be too messy, instead, we will use a dedicated role to make our configuration reusable.
-
Launch 2 fresh EC2 instances using RHEL 8 image, we will use them as our
uat
servers, so give them names accordingly –Web1-UAT
andWeb2-UAT
. -
To create a role, you must create a directory called
roles/
, relative to the playbook file or in/etc/ansible/
directory.There are two ways how you can create this folder structure:
-
Use an Ansible utility called
ansible-galaxy
insideansible-config-mgt/role
s directory (you need to createroles
directory upfront)mkdir roles cd roles ansible-galaxy init webserver
-
Create the directory/files structure manually
Note: You can choose either way, but since you store all your codes in GitHub, it is recommended to create folders and files there rather than locally on
Jenkins-Ansible
server.The entire folder structure should look like below, but if you create it manually – you can skip creating
tests
,files
, andvars
or remove them if you usedansible-galaxy
└── webserver ├── README.md ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
After removing unnecessary directories and files, the roles structure should look like this
└── webserver ├── README.md ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── tasks │ └── main.yml └── templates
-
-
Update your inventory
ansible-config-mgt/inventory/uat.yml
file with IP addresses of your 2 UAT Web serversNOTE: Ensure you are using ssh-agent to ssh into the Jenkins-Ansible instance just as you have done in project 11;
To learn how to setup SSH agent and connect VS Code to your Jenkins-Ansible instance, please see this video:
For Windows users – ssh-agent on windows
For Linux users – ssh-agent on linux
[uat-webservers] <Web1-UAT-Server-Private-IP-Address> ansible_ssh_user='ec2-user' <Web2-UAT-Server-Private-IP-Address> ansible_ssh_user='ec2
-
In
/etc/ansible/ansible.cfg
file uncommentroles_path
string and provide a full path to your roles directoryroles_path = /home/ubuntu/ansible-config-mgt/roles
, so Ansible could know where to find configured roles. -
It is time to start adding some logic to the webserver role. Go into
tasks
directory, and within themain.yml
file, start writing configuration tasks to do the following:-
Install and configure Apache (
httpd
service) -
Clone Tooling website from GitHub
https://github.com/<your-name>/tooling.git
. -
Ensure the tooling website code is deployed to /var/www/html on each of 2 UAT Web servers. = Make sure
httpd
service is startedYour
main.yml
may consist of following tasks:--- - name: install apache become: true ansible.builtin.yum: name: "httpd" state: present - name: install git become: true ansible.builtin.yum: name: "git" state: present - name: clone a repo become: true ansible.builtin.git: repo: https://github.com/<your-name>/tooling.git dest: /var/www/html force: yes - name: copy html content to one level up become: true command: cp -r /var/www/html/html/ /var/www/ - name: Start service httpd, if not started become: true ansible.builtin.service: name: httpd state: started - name: recursively remove /var/www/html/html/ directory become: true ansible.builtin.file: path: /var/www/html/html state: absent
-
Within the static-assignments
folder, create a new assignment for uat-webservers uat-webservers.yml
. This is where you will reference the role.
---
- hosts: uat-webservers
roles:
- webserver
Remember that the entry point to our ansible configuration is the site.yml
file. Therefore, you need to refer your uat-webservers.yml
role inside site.yml
.
So, we should have this in site.yml
---
- hosts: all
- import_playbook: ../static-assignments/common.yml
- hosts: uat-webservers
- import_playbook: ../static-assignments/uat-webservers.yml
Commit your changes, create a Pull Request and merge them to master / main
branch, make sure webhook triggered two consequent Jenkins jobs, they ran successfully and copied all the files to your Jenkins-Ansible
server into /home/ubuntu/ansible-config-mgt/ & /home/ubuntu/ansible-config-artifact/
directory.
Now run the playbook against your uat
inventory and see what happens:
ansible-playbook -i /home/ubuntu/ansible-config-mgt/inventory/uat.yml /home/ubuntu/ansible-config-mgt/playbooks/site.yaml
You should be able to see both of your UAT Web servers configured and you can try to reach them from your browser:
NOTE: Do not forget to open http port 80
on 2 fresh EC2 instances
http://<Web1-UAT-Server-Public-IP-or-Public-DNS-Name>/index.php
or
http://<Web2-UAT-Server-Public-IP-or-Public-DNS-Name>/index.php
Your Ansible architecture now looks like this: