Last active
October 18, 2022 11:02
-
-
Save vsathyak/8850736e76ce80e34b89b5af79cf7a20 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Ansible Introduction and Architecture | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
Ansible is an automation engine that allows for agentless system configuration and deployment means it is simply a tool | |
that can execute tasks on remote or local system wherever you need to. It does this in a way that doesn't require any | |
real additional software outside of the ansible based binaries that you install on one server and runs Ansible modules | |
on remote system over SSH inorder to complete tasks. | |
Basic Components | |
---------------- | |
Control Node : Any machine with Ansible installed. You can run commands and playbooks, invoking /usr/bin/ansible or | |
/usr/bin/ansible-playbook, from any control node. | |
Managed Nodes : The network devices (and/or servers) you manage with Ansible. Managed nodes are also sometimes called | |
“hosts”. Ansible is not installed on managed nodes. | |
Inventory : A list of managed nodes. An inventory file is also sometimes called a “hostfile”. Your inventory can | |
specify information like IP address for each managed node. | |
Modules : The units of code Ansible executes. Each module has a particular use, from administering users on a | |
specific type of database to managing VLAN interfaces on a specific type of network device. | |
Tasks : The units of action in Ansible. You can execute a single task once with an ad-hoc command. | |
Playbooks : Ordered lists of tasks, saved so you can run those tasks in that order repeatedly. Playbooks can | |
include variables as well as tasks. | |
________________________________________________________________________________________________________________________ | |
Ansible Installation and Configuration Part 1 & 2 | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
To install Ansible you must configure EPEL repository in your system first. Once the EPEL repository is configured, your | |
package manager install Ansible and manages the dependencies. | |
(Note:EPEL repo stands for Extra Packages for Enterprise Linux Repository. It is a free and open source repository project | |
made available to everybody by Fedora. It is well known for providing 100% high quality add-ons for Linux based software’s | |
including CentOs and RHEL. These packages are needed to be enabled separately for CentOS with a unique set of commands. | |
The reason for adding them separately is because they are not included in the standard software package yet they are very | |
useful.) | |
Verify epel-release installed, if not, install | |
---------------------------------------------- | |
>> yum list epel-release | |
>> yum install epel-release(do it only if not installed) | |
Install Ansible | |
--------------- | |
>> sudo yum install ansible | |
Install Git | |
----------- | |
>> sudo yum install git | |
Configure Ansible | |
----------------- | |
>> vim /etc/ansible/ansible.cfg (Primary Ansible Configuration File) | |
The commented line is simply the default value here and if you want to change the default value, uncomment and update. | |
Configure Ansible Inventory(An inventory is a list of hosts that Ansible manages) | |
--------------------------- | |
>> vim /etc/ansible/hosts (Default Ansible Inventory File) | |
vsathyak5 ansible_host=vsathyak5c.mylabserver.com | |
vsathyak6 ansible_host=vsathyak6c.mylabserver.com | |
Ansible is best implemented using a common user across all Ansible controlled systems. | |
Create a user 'ansible' in Control node | |
------------------------------------- | |
>> sudo useradd ansible | |
Create a user 'ansible' and set password in Host node | |
----------------------------------------------------- | |
>> Connect over ssh to host node from control node | |
>> sudo useradd ansible (adding user ansible) | |
>> sudo passwd ansible (learn@123) | |
Reason for setting password in host nodes and not in control node is that we need to login from control node to host | |
node later using to set up ssh preshared key. So we need password in host nodes. | |
Sharing preshared key from Control node to Host node | |
--------------------------------------------------- | |
>> sudo su - ansible (switching to ansible user) | |
>> ssh-keygen (generate ssh keys) | |
>> ssh-copy-id vsathyak5c.mylabserver.com | |
>> Enter ansible user password | |
Giving sudo privilege to 'ansible' user in Host nodes | |
----------------------------------------------------- | |
>> ssh [email protected] from control node or access it from terminal directly. | |
Note :: /etc/sudoers may be edited to allow 'ansible' user to sudo any commandwithout a password | |
>> sudo visudo | |
Find the line | |
# %wheel ALL=(ALL) NOPASSWD: ALL | |
Add the following | |
ansible ALL=(ALL) NOPASSWD: ALL | |
________________________________________________________________________________________________________________________ | |
Where to Find Documentation | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
Reference >> docs.ansible.com | |
List specific ansible module >> ansible-doc -s <module_name> Eg: ansible-doc -s lineinfile | |
>> ansible-doc <module_name> Eg: ansible-doc lineinfile | |
List all ansible module >> ansible-doc -l | |
________________________________________________________________________________________________________________________ | |
Ad-hoc Ansible Commands | |
~~~~~~~~~~~~~~~~~~~~~~~ | |
An ad-hoc command is something that you might type in to do something really quick, but don’t want to save for later and | |
is executed on any target hosts or group of target hosts where as Playbooks are more like a scripts. | |
Syntax : ansible <HOST> -m <MODULE> -a "<ARG1 ARG2 ARG3>" | |
Eg : ansible vsathyak5 -m setup | |
Note : Please make sure you are using the correct user to execute the commands. In our case, its 'ansible'. | |
>> sudo su - ansible | |
Return info regarding the host vsathyak5 | |
---------------------------------------- | |
>> ansible vsathyak5 -m setup | |
Try to connect to host, verify a usable python and return pong on success | |
------------------------------------------------------------------------- | |
>> ansible vsathyak6 -m ping | |
Install httpd on host vsathyak5c | |
-------------------------------- | |
>> ansible vsathyak5 -m yum -a "name=httpd state=latest" | |
This will return the error "You need to be root to perform this command.\n" | |
You need to use -b flag to get the sudo privilege and this will install httpd package in host : vsathyak5c | |
>> ansible vsathyak5 -b -m yum -a "name=httpd state=latest" | |
Controls services on remote hosts | |
--------------------------------- | |
>> ansible vsathyak5 -b -m service -a "name=httpd state=started" | |
>> Login to the host machine | |
>> sudo systemctl status httpd (Will return the status running) | |
________________________________________________________________________________________________________________________ | |
Ansible Playbooks | |
~~~~~~~~~~~~~~~~~ | |
As ad-hoc commands are to bash commands, playbooks are to bash scripts. Playbooks run using 'ansible-playbook' command | |
and not the ansible command. Playbooks are written in YAML. It contain different elements called plays. Plays contain | |
list of host and at minimum one task. | |
You can use default host inventory or you can create a new inventory file. | |
>> sudo su - ansible | |
>> pwd ==> /home/ansible | |
Create user defined inventory file | |
---------------------------------- | |
>> vim inv | |
[webservers] --> this defines a group of hosts in ansible called 'webservers' | |
vsathyak5 ansible_host=vsathyak5c.mylabserver.com | |
vsathyak6 ansible_host=vsathyak6c.mylabserver.com | |
>> Save it. | |
Create playbook | |
--------------- | |
>> vim web.yml | |
--- # Loading Webservers | |
- hosts: webservers | |
become: yes | |
tasks: | |
- name: install latest httpd # Plain English | |
yum: | |
name: httpd | |
state: latest | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line: "Here is some text..." | |
path: /var/www/html/index.html | |
- name: start httpd | |
service: | |
name: httpd | |
state: started | |
Run Playbook | |
------------ | |
>> ansible-playbook -i inv web.yml (-i is to pass the user defined inventory file.) | |
PLAY [webservers] ********************************************************************************* | |
TASK [Gathering Facts] **************************************************************************** | |
ok: [vsathyak5] | |
ok: [vsathyak6] | |
TASK [install latest httpd] *********************************************************************** | |
ok: [vsathyak5] | |
changed: [vsathyak6] | |
TASK [create index.html file] ********************************************************************* | |
changed: [vsathyak5] | |
TASK [add web content] **************************************************************************** | |
changed: [vsathyak6] | |
changed: [vsathyak5] | |
TASK [start httpd] ******************************************************************************** | |
changed: [vsathyak6] | |
changed: [vsathyak5] | |
PLAY RECAP **************************************************************************************** | |
vsathyak5 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 | |
vsathyak6 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 | |
Check Mode | |
---------- | |
>> ansible-playbook -i inv web.yml --check | |
Retry file : If playbook fails, a retry file is generated and contain the list of hosts where the playbook | |
failed : playbook-name.retry | |
The file may be specified using --limit with the same playbook to reattempt the playbook at a | |
later time. | |
________________________________________________________________________________________________________________________ | |
Ansible Variables | |
~~~~~~~~~~~~~~~~~ | |
Variable names should be letters, numbers and underscores. | |
Eg: foobar, foo_bar, foo5 | |
Passing Variables via Command line : using --extra-vars or -e flag | |
Eg : ansible-playbook web.yml -e "target_host=localhost target_service=httpd" | |
--- | |
hosts: webservers | |
become: yes | |
vars: | |
target_service: httpd | |
target_state: started | |
tasks: | |
- name: Ensure target service | |
service: | |
name: "{{ target_service }}" | |
state: "{{ target_state }}" | |
Run Playbook | |
------------ | |
>> ansible-playbook -i inv web_var.yml | |
Create playbook with vars | |
------------------------- | |
>> vim web.yml | |
--- | |
- hosts: webservers | |
become: yes | |
tasks: | |
- name: install latest httpd | |
yum: | |
name: "{{ target_service }}" | |
state: latest | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line: "Here is some text..." | |
path: /var/www/html/index.html | |
- name: start httpd | |
service: | |
name: "{{ target_service }}" | |
state: started | |
Run Playbook and passing value to variable on runtime | |
----------------------------------------------------- | |
>> ansible-playbook -i inv web_var.yml -e "target_service=httpd" | |
________________________________________________________________________________________________________________________ | |
Ansible Facts | |
~~~~~~~~~~~~~ | |
Facts are properties regarding a given remote sytem. The 'setup' module can retrieve facts. The filter parameter | |
takes regex to allow you to prune fact output. | |
Eg: ansible vsathyak5 -m setup retrieves fact about the node vsathyak5 | |
Eg: ansible vsathyak5 -m setup -a filter=*ipv4* retrieves ipv4 facts of the node vsathyak5 | |
Writing Playbook with content to be shown is the name of the host | |
----------------------------------------------------------------- | |
--- | |
- hosts: webservers | |
become: yes | |
tasks: | |
- name: install latest httpd | |
yum: | |
name: "{{ target_service }}" | |
state: latest | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line:"{{ ansible_hostname }}" | |
path: /var/www/html/index.html | |
- name: start httpd | |
service: | |
name: "{{ target_service }}" | |
state: started | |
Run playbook | |
------------ | |
>> ansible-playbook -i inv web_fact.yml -e "target_service=httpd" | |
Setting up gather_facts = false in playbook | |
------------------------------------------- | |
--- | |
- hosts: webservers | |
become: yes | |
gather_facts: no ===> This will result in not gathering facts and returns error on task 'name: add web content' | |
vars: | |
tasks: | |
- name: install latest httpd | |
yum: | |
name: "{{ target_service }}" | |
state: latest | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line:"{{ ansible_hostname }}" | |
path: /var/www/html/index.html | |
- name: start httpd | |
service: | |
name: "{{ target_service }}" | |
state: started | |
Run playbook | |
------------ | |
>> ansible-playbook -i inv web_nofact.yml -e "target_service=httpd" | |
This will return error since gather_facts is set no and so the variable 'ansible_hostname' become undefined. | |
And it results in auto creation of creation of file web.retry | |
>> ls -la | |
web_var_nofact.yml web_var_nofact.retry | |
>> cat web_var_nofact.retry | |
vsathyak5 | |
vsathyak6 | |
________________________________________________________________________________________________________________________ | |
Troubleshooting and Debugging Ansible | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
There are couple of ways to troubleshoot and debug ansible. | |
1. Debug Module | |
2. Registry keyword | |
Debug Module | |
------------ | |
Debug module takes two parameter. | |
a. msg: A message that is printed to STDOUT | |
b. var: A variable whose content is printed to stdout | |
Register Module/Keyword | |
----------------------- | |
Register module is used to store task output | |
>> vim web_debug.yml | |
--- # Bootstrap webservers | |
- hosts: webservers | |
become: yes | |
gather_facts: yes | |
tasks: | |
- debug: | |
var: target_service # Print the value of target_service variable. | |
- name: install latest httpd | |
yum: | |
name: " {{ target_service }} " | |
state: latest | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line: "{{ ansible_hostname }}" | |
path: /var/www/html/index.html # What happens in lineinfile task is stored in task_debug register. | |
register: task_debug # Also the location of the register tag is same as parent tag. | |
- debug: | |
msg: "Output of lineinfile is: {{ task_debug }}" # What is stored in the register is printed out here. | |
- name: start httpd | |
service: | |
name: "{{ target_service }}" | |
state: started | |
Run playbook | |
------------ | |
>> ansible-playbook -i inv web_debug.yml -e "target_service=httpd" | |
________________________________________________________________________________________________________________________ | |
Ansible Handlers | |
~~~~~~~~~~~~~~~~ | |
Ansible provide a mechanism that allows an action to be flagged for execution when a tasks performs a change. By only | |
executing certain tasks during a change, plays are more efficient. This mechanism is known as Handler. | |
Also even if the handler is flagged multiple times in a play, it only runs during a plays final phase. | |
'notify' will only flag a handler if tasks blocks make a change. | |
>> vim web_handler.yml | |
--- # Bootstrap webservers | |
- hosts: webservers | |
become: yes | |
gather_facts: yes | |
tasks: | |
- name: install latest httpd | |
yum: | |
name: " {{ target_service }} " | |
state: latest | |
notify: | |
- restart httpd # A change in task yum will call the handler restart httpd | |
- name: create index.html file | |
file: | |
name: /var/www/html/index.html | |
state: touch | |
- name: add web content | |
lineinfile: | |
line: "{{ ansible_hostname }}" | |
path: /var/www/html/index.html | |
notify: | |
- restart httpd # A change in task yum will call the handler restart httpd | |
handlers: | |
- name: Attempt to restart httpd | |
service: | |
name: httpd | |
state: restarted | |
listen: "restart httpd" | |
Run playbook | |
------------ | |
>> ansible vsathyak5 -b -m yum -a "name=httpd state=absent" (Remove httpd from vsathyak5) | |
>> ansible-playbook -i inv web_handler.yml -e "target_service=httpd" | |
________________________________________________________________________________________________________________________ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment