How to install Ansible

Installing Ansible

Ansible by default manages machines over the SSH protocol. Once Ansible is installed, it will not add a database, and there will be no daemons to start or keep running. You only need to install it on one machine (which could easily be a laptop) and it can manage an entire fleet of remote machines from that central point. 

Latest Release Via Yum

RPMs are available from yum for EPEL 6, 7, and currently supported Fedora distributions. Ansible itself can manage earlier operating systems that contain Python 2.6 or higher (so also EL6). Fedora users can install Ansible directly, though if you are using RHEL or CentOS and have not already done so, configure EPEL 

# install the epel-release RPM if needed on CentOS, RHEL, or Scientific Linux
$ sudo yum install ansible  

Latest Releases Via Apt (Ubuntu)

Ubuntu builds are available in a PPA here. (Windows isn’t supported for the control machine). To configure the PPA on your machine and install ansible run these commands:

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible  

Some Quick Notes:

1. Machine, where ansible is installed is called as Control Machine.
2. Ansible is written in Python Language.
3. You should have python 2.6/2.7 to install ansible on control machine.
4. Windows isn’t supported for the control machine.
5. Ansible can automate tasks on Linux and windows Machines

Inventory

Inventory is a text file where you define the host information that you want to manage with ansible. The default inventory file location is /etc/ansible/hosts. You can specify a different inventory file using the -i <-path>option on the command line.
For this exercise we need two Linux servers, you can spin two centos vm or ec2 instance for practice. 

Hosts and Groups

Create a file named inventory-dev(name can be anything) and add below mentioned entry.
web1 ansible_ssh_host=192.168.1.13   ansible_ssh_user=vagrant  ansible_ssh_pass='vagrant'
db1    ansible_ssh_host=192.168.1.14   ansible_ssh_user=vagrant  ansible_ssh_pass='vagrant'[webservers] 
web1
[dbservers] 
db1   

Explanation

1. web1 and db1 are the names that we have given to the hosts.
2. ansible_ssh_host is the variable and its value is the IP address of the server.
3. ansible_ssh_user variable holds the username
4. ansible_ssh_password holds the password
5. [webserver] & [dbservers] is the name of the group which can contain n number hosts. Groupnames are enclosed in square brackets [] .

Note: Mentioning password in the inventory file is not recommended, it’s just for initial learning later we will do ssh key exchange

Inventory for Production systems/Real Time

As we have seen above we put the password in clear text and IP address information also in the inventory. This is a real concern for security, you cannot share this inventory with anyone and also cannot track it in VCS like git. We have better ways to deal with this situation.
1. Since ansible uses SSH, its always recommended to do SSH key exchange and authorize ansible server login to the nodes its managing.
Note: Refer Bash Scripting chapter to learn SSH key exchange.
This way we don’t need to mention username and password in the inventory file.
2. Next thing is the IP address, we can manage that with the /etc/hosts file. Map IP to hostname in /etc/hosts file and you can then mention the hostname directly in the inventory. 

HOSTS File

$ cat /etc/hosts
192.168.1.13 web1
192.168.1.14 db1  

INVENTORY File
$ cat inventory-dev
[webservers]
web1
[dbservers]
db1  

So now our inventory is very simple and just contain the group and hostname, which is safe.

Adhoc command

Ansible gives a quick method to communicate and execute commands on remote/local machines through Adhoc commands. 

imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m ping web1
web1 | SUCCESS =>{
"changed": false, 
"ping": "pong"
}
imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m ping db1
db1 | SUCCESS =>{
"changed": false, 
"ping": "pong"
}
imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m ping webservers
web1 | SUCCESS =>{
"changed": false, 
"ping": "pong"
}
imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m ping dbservers
db1 | SUCCESS =>{
"changed": false, 
"ping": "pong"
}
imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m ping all
web1 | SUCCESS =>{
"changed": false, 
"ping": "pong"
}
db1 | SUCCESS =>{
"changed": false, 
"ping": "pong"

 
Explanations
1. Adhoc commands are executed by specifying “ansible” command.
2. -i <- inventory name> tells ansible to pick up host information from this file, if not specified ansible will look for the host information in /etc/ansible/hosts
3. -m means the module name. ping is a module which will login to the host and check the connectivity.
4. Web1, db1, webservers, dbservers are the host and group name where we want to execute the task, “all” means all the hosts from the inventory file

Host key checking Error
"msg": "ERROR! Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass 
does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}  

Solution: 
Open /etc/ansible/ansible.cfg file and uncomment “#host_key_checking = False” by removing # sudo vi /etc/ansible/ansible.cfg 

Group of Groups and Group Variables
Variables can be applied to an entire group 

[webservers]
web1
[dbservers]
db1
[datacenter:children]
webservers
dbservers
[datacenter:vars]
ansible_ssh_user=vagrant
ansible_ssh_pass='vagrant'  

Explanation
1. [datacenter:children] tells datacenter is a master group and underneath we specify other group names
2. [datacenter:vars] is used to define variable at the group level, you can specify variable on any group by specifying [groupname:vars]. 

General for all connections:

ansible_host

The name of the host to connect to, if different from the alias you wish to give to it.

ansible_port
The ssh port number, if not 22

ansible_user
The default ssh user name to use. Specific to the SSH connection:

ansible_ssh_pass
The ssh password to use (never store this variable in plain text; always use a vault. See Variables and Vaults)

ansible_ssh_private_key_file
Private key file used by ssh. Useful if using multiple keys and you don’t want to use SSH agent. 

About Modules
Modules (also referred to as “task plugins” or “library plugins”) are the ones that do the actual work in ansible, they are what gets executed in each playbook task. But you can also run a single one using the ‘ansible’ command. 
List of all the modules
https://docs.ansible.com/ansible/list_of_all_modules.html

imran@DevOps:~/.../exercise1$ ansible-doc -l
 

Let’s review how we execute three different modules from the command line:

ansible webservers -m service -a "name=httpd state=started"
ansible webservers -m ping
ansible webservers -m command -a "/sbin/reboot -t now"  

Installing package

imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m yum -a "name=httpd state=installed"web1 --sudo
web1 | SUCCESS =>{
"changed": false, 
"msg": "", 
"rc": 0, 
"results": [
"httpd-2.2.15-59.el6.centos.x86_64 providing httpd is already installed"
]
}  

Explanation
1. “yum” is a ansible module that manages packages on red hat based systems, for Debian based we use module named “apt”. 
2. -a is used to provide arguments for the module like name=httpd(key=value). Majority of the modules will have arguments, some arguments are mandatory like “name” argument for “yum”. $ ansible-doc yum will show you list of all the arguments for yum module.
3. --sudo tells ansible to execute the module with root privileges, user should have the sudo privileges or else the module will fail.

Starting service.

imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m service -a "name=httpd state=started"web1 --sudo
web1 | SUCCESS =>{
"changed": true,
"name": "httpd", 
"state": "started"
}  


Output of adhoc commands
ansible command return output is json format

web1 | SUCCESS =>{
"changed": true, 
"name": "httpd",
"state": "started"
}  


1. web1 is the name of the hosts on which module got executed.
2. Status is SUCCESS that means it got executed successfully.
3. changed: true means that the module execution made some changes in web1.
4. changed: false means that the system is in the same desired state as shown below.

imran@DevOps:~/.../exercise1$ ansible -i inventory-dev -m service -a "name=httpd state=started"web1 --sudo
web1 | SUCCESS =>{
"changed": false,
"name": "httpd", 
"state": "started"
}  

1.httpd service was already running on web1 so even executing the adhoc command again will not make any changes this is called the IDEMPOTENT behaviour.

Few more sample modules with adhoc commands.
To transfer a file directly to many servers:

$ ansible -i inventory-dev -m copy -a "src=/etc/hosts dest=/tmp/hosts"datacenter  

The file module allows changing ownership and permissions on files. These same options can be passed directly to the copy module as well:

$ ansible webservers -m file -a "dest=/opt/info.txt mode=600"
$ ansible webservers -m file -a "dest=/opt/info.txt mode=600 owner=devops group=devops"  

Ensure a package is installed, but don’t update it:

$ ansible webservers -m yum -a "name=acme state=present"  

Ensure a package is installed to a specific version:

$ ansible webservers -m yum -a "name=acme-1.5 state=present"  

Ensure a package is at the latest version:

$ ansible webservers -m yum -a "name=acme state=latest"  

Ensure a package is not installed:

$ ansible webservers -m yum -a "name=acme state=absent"

For more information about Visualpath, visit www.visualpath.in and follow the company on Facebook and Twitter.


Comments