Friday, May 31, 2019

Ansible installation and configuration

Purpose of the configuration management tool

Configuration changes in a large environment is a challenge for  complex IT architectures where manual alterations are not practical in many cases. Initially we  were using the customised images for the installation purpose for our organisation needs which was the first approach to the configuration management . But later where the changes are more after the installation or during the operation period we may need specific tools for the configuration management . Below are the some of the configuration management tools available in the market

ToolLanguageFLOSS version
CFEngineCCFEngine Community
PuppetRubyOpen Source Puppet
ChefRubyChef
AnsiblePythonAnsible
SaltStackPythonSaltOpen

What is ansible & Why is ansible  

Ansible is a simple and efficient automation tool for cloud provisioning , configuration management, application deployment , intra-service orchestration and many more. Designed for multi-tier deployments since day one, Ansible models your IT infrastructure by describing how all of your systems inter-relate, rather than just managing one system at a time.
It uses no agents and no additional custom security infrastructure, so it's easy to deploy - and most importantly, it uses a very simple language (YAML, in the form of Ansible Playbooks) that allow you to describe your automation jobs in a way that approaches plain English.


  • Ansible is an open source tool
  • Ansible is a agent less tool which is not a server client architecture (unlike puppet,chef, salt)  
  • It uses ssh protocol to connect to the nodes
  • Enterprise version is supported by redhat 
  • We can manage the inventory using simple text files 



Difference between Ansible & Ansible tower `

Ansible, an open source product is available on Windows, Linux/Unix Operating systems. Because of the inefficiencies in the then CM tools, the Ansible was developed. The features that are the main focus of Ansible are as follows:

Causing Of the Overheads by the Agents

Ansible is a unique tool that uses an agentless architecture. To deploy the modules to the nodes it generally relies on the tested SSH. The modules are stored temporarily in the nodes and thus help in controlling the machines over a standard protocol through JSON protocol. When the nodes are not being managed by it the resources are also not consumed because no daemons or programs are executed in the background.

No Dependence on Ruby

Other CM apps were dependent on Ruby, but, Ansible is not. Thus, to create commands in Puppet and Chef one needs to have knowledge of Ruby. As the creators have made Ansible in python, it is relatively easy to write the commands. The added advantage is that they can be written in any programming language. So, there is no requirement for one to learn Ruby.

Features of Ansible tower

  • Role-based access control: you can set up teams and users in various roles. These can integrate with your existing LDAP or AD environment
  • Job scheduling: schedule your jobs and set repetition option
  • Portal mode: this is a simplified view of automation jobs for newbies and less experienced Ansible users. This is an excellent feature as it truly lowers the entry barriers to starting to use Ansible.
  • Fully documented REST API: allows you to integrate Asible into your existing toolset and environment
  • Tower Dashboard: use this to quickly view a summary of your entire environment. Simplifies things for sysadmins while sipping their coffee
  • Cloud integration: Tower is compatible with the major cloud environments: Amazon EC2, Rackspace, Azure.

Installing the ansible 

I have configured centOS 7 as ansible server and ubuntu 16.4 as client , below are the steps of the configuration

1. First we need to install epel-release on the centos7

[root@unixchips-server ~]# yum install epel-release

Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile epel/x86_64/metalink | 7.2 kB 00:00 * base: mirror.dhakacom.com * epel: download.nus.edu.sg * extras: mirror.dhakacom.com * updates: centos-hcm.viettelidc.com.vn base | 3.6 kB 00:00 docker-ce-edge | 3.5 kB 00:00 docker-ce-stable | 3.5 kB 00:00

*******************<output is omitted>*****************

2. Now we need to install the ansible

[root@unixchips-server ~]# yum install ansible

(as i have already installed the ansible i am getting the below output)

[root@unixchips-server ~]# yum install ansible Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: mirror.dhakacom.com * epel: download.nus.edu.sg * extras: mirror.horizon.vn * updates: centos-hcm.viettelidc.com.vn Package ansible-2.8.0-2.el7.noarch already installed and latest version Nothing to do

3. Next step is to configure the ansible hosts .we have to move to /etc/ansible/hosts and configure the client details as below , where unixchips is the ubuntu client 

[ansible-test]
unixchips

4. Now login to the client machine and install the ansible as below 

unixchips@unixchips:~$ sudo apt-add-repository ppa:ansible/ansible

[sudo] password for unixchips: Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy. Avoid writing scripts or custom code to deploy and update your applications— automate in a language that approaches plain English, using SSH, with no agents to install on remote systems. http://ansible.com/ More info: https://launchpad.net/~ansible/+archive/ubuntu/ansible Press [ENTER] to continue or ctrl-c to cancel adding it
gpg: keyring `/tmp/tmpmyotgwkm/secring.gpg' created gpg: keyring `/tmp/tmpmyotgwkm/pubring.gpg' created gpg: requesting key 7BB9C367 from hkp server keyserver.ubuntu.com gpg: /tmp/tmpmyotgwkm/trustdb.gpg: trustdb created gpg: key 7BB9C367: public key "Launchpad PPA for Ansible, Inc." imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) OK

5. We have to update the packages and then install the ansible

unixchips@unixchips:~$ sudo apt-get update Hit:1 http://download.virtualbox.org/virtualbox/debian xenial InRelease Hit:2 http://ppa.launchpad.net/ansible/ansible/ubuntu xenial InRelease Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB] Hit:4 http://in.archive.ubuntu.com/ubuntu xenial InRelease Get:5 http://in.archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] Hit:6 http://in.archive.ubuntu.com/ubuntu xenial-backports InRelease Get:7 http://in.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [957 kB] Get:8 http://in.archive.ubuntu.com/ubuntu xenial-updates/main i386 Packages [824 kB] Get:9 http://in.archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [748 kB] Get:10 http://in.archive.ubuntu.com/ubuntu xenial-updates/universe i386 Packages [685 kB] Fetched 3,433 kB in 3s (1,109 kB/s)

unixchips@unixchips:~$ sudo apt-get install ansible 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
ansible is already the newest version (2.8.0-1ppa~xenial).
The following packages were automatically installed and are no longer required:
  linux-headers-4.10.0-28 linux-headers-4.10.0-28-generic linux-headers-4.13.0-32 linux-headers-4.13.0-32-generic linux-headers-4.13.0-36
  linux-headers-4.13.0-36-generic linux-headers-4.13.0-37 linux-headers-4.13.0-37-generic linux-headers-4.13.0-38
  linux-headers-4.13.0-38-generic linux-headers-4.13.0-39 linux-headers-4.13.0-39-generic linux-headers-4.13.0-41
  linux-headers-4.13.0-41-generic linux-headers-4.13.0-43 linux-headers-4.13.0-43-generic linux-headers-4.15.0-29
  linux-headers-4.15.0-29-generic linux-headers-4.15.0-30 linux-headers-4.15.0-30-generic linux-headers-4.15.0-32
  linux-headers-4.15.0-32-generic linux-headers-4.15.0-33 linux-headers-4.15.0-33-generic linux-headers-4.15.0-34
  linux-headers-4.15.0-34-generic linux-headers-4.15.0-36 linux-headers-4.15.0-36-generic linux-headers-4.15.0-39
  linux-headers-4.15.0-39-generic linux-headers-4.15.0-42 linux-headers-4.15.0-42-generic linux-image-4.10.0-28-generic
  linux-image-4.13.0-32-generic linux-image-4.13.0-36-generic linux-image-4.13.0-37-generic linux-image-4.13.0-38-generic
  linux-image-4.13.0-39-generic linux-image-4.13.0-41-generic linux-image-4.13.0-43-generic linux-image-4.15.0-24-generic
  linux-image-4.15.0-29-generic linux-image-4.15.0-30-generic linux-image-4.15.0-32-generic linux-image-4.15.0-33-generic
  linux-image-4.15.0-34-generic linux-image-4.15.0-36-generic linux-image-4.15.0-39-generic linux-image-4.15.0-42-generic
  linux-image-extra-4.10.0-28-generic linux-image-extra-4.13.0-32-generic linux-image-extra-4.13.0-36-generic
  linux-image-extra-4.13.0-37-generic linux-image-extra-4.13.0-38-generic linux-image-extra-4.13.0-39-generic
  linux-image-extra-4.13.0-41-generic linux-image-extra-4.13.0-43-generic linux-image-extra-4.13.0-45-generic linux-modules-4.15.0-24-generic
  linux-modules-4.15.0-29-generic linux-modules-4.15.0-30-generic linux-modules-4.15.0-32-generic linux-modules-4.15.0-33-generic
  linux-modules-4.15.0-34-generic linux-modules-4.15.0-36-generic linux-modules-4.15.0-39-generic linux-modules-4.15.0-42-generic
  linux-modules-extra-4.15.0-33-generic linux-modules-extra-4.15.0-39-generic

6. Once the ansible is installed we can check the version details using below command

unixchips@unixchips:~$ ansible --version 
ansible 2.8.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/unixchips/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Nov 12 2018, 14:36:49) [GCC 5.4.0 20160609]

7. Now we need a dedicated user for ansible operations for both the server and client, i have created a user called "unixchips" in both the nodes as ansible is communicating through simple ssh protocol . We need to configure passwordless authentication for both the nodes using "unixchips" user 

unixchips@unixchips:~$ id unixchips 
uid=1000(unixchips) gid=1000(unixchips) groups=1000(unixchips),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)

  [root@unixchips-server ~]# id unixchips 
uid=1000(unixchips) gid=1000(unixchips) groups=1000(unixchips),995(docker)

8. Now create a public key using the below steps and copy that to the client machine 

[unixchips@unixchips-server ~]$ ssh-keygen -t rsa

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/vivek/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /Users/vivek/.ssh/id_rsa.
Your public key has been saved in /Users/vivek/.ssh/id_rsa.pub.
The key fingerprint is:
80:5f:25:7c:f4:90:aa:e1:f4:a0:01:43:4e:e8:bc:f5 vivek@desktop01
The key's randomart image is:
+--[ RSA 2048]----+
| oo    ...+.     |
|.oo  .  .ooo     |
|o .o. . .o  .    |
| o ...+o.        |
|  o .=.=S        |
| .  .Eo .        |
|                 |
|                 |
|                 |
+-----------------+

ssh-copy-id -i $HOME/.ssh/id_rsa.pub unixchips@unixchips

Now we can login to the node with out the password 

9. Let's test the ansible configuration using the ping command 

[unixchips@unixchips-server ~]$ ansible all --list-hosts
[DEPRECATION WARNING]: The TRANSFORM_INVALID_GROUP_CHARS settings is set to allow bad characters in group names by default, this will change, 
but still be user configurable on deprecation. This feature will be removed in version 2.10. Deprecation warnings can be disabled by setting 
deprecation_warnings=False in ansible.cfg.
 [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details

  hosts (1):
    unixchips
[unixchips@unixchips-server ~]$ ansible all -m ping
[DEPRECATION WARNING]: The TRANSFORM_INVALID_GROUP_CHARS settings is set to allow bad characters in group names by default, this will change, 
but still be user configurable on deprecation. This feature will be removed in version 2.10. Deprecation warnings can be disabled by setting 
deprecation_warnings=False in ansible.cfg.
 [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details

[DEPRECATION WARNING]: Distribution Ubuntu 16.04 on host unixchips should use /usr/bin/python3, but is using /usr/bin/python for backward 
compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See 
https://docs.ansible.com/ansible/2.8/reference_appendices/interpreter_discovery.html for more information. This feature will be removed in 
version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
unixchips | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

We have successfully installed the ansible and setup is working as expected .

Thank you for the reading   








Tuesday, May 14, 2019

How to create an ansible playbook and roles

Ansible is an open source platform which helps to automate the configuration management , application deployment in complex IT environment which includes linux,windows based systems . Ansible is commonly known as infrastructure as a code. 

Designed for multi tier deployments Ansible models our IT infrastructure by designing how all our systems are inter related rather than just managing them  .It uses no agents and no additional custom security infrastructure, so it's easy to deploy - and most importantly, it uses a very simple language (YAML, in the form of Ansible Playbooks) that allow you to describe your automation jobs in a way that approaches plain English.

Ansible uses following components to work
  • Inventory file(s)
  • Group vars
  • Host vars
  • Playbooks
  • Roles
  • Tasks
Inventory files are the list of hosts which ansible trying to interact . The default location of the ansible  host file is /etc/ansible/hosts . Group vars and Host vars are the hosts specified in the inventory file. Roles are the ways of automatically loading certain variables and files and handlers as per the known file structure.

Ansible playbooks are the organised group of scripts that defines work for a server configuration managed by the ansible platform. Ansible plays are written by using yamal format.

Directory layout of ansible playbook 

Below is the basic directory layout of ansible playbook 

####################################################
production                # inventory file for production servers
staging                   # inventory file for staging environment

group_vars/
   group1                 # here we assign variables to particular groups
   group2                 # ""
host_vars/
   hostname1              # if systems need specific variables, put them here
   hostname2              # ""

library/                  # if any custom modules, put them here (optional)
filter_plugins/           # if any custom filter plugins, put them here (optional)

site.yml                  # master playbook
webservers.yml            # playbook for webserver tier
dbservers.yml             # playbook for dbserver tier

roles/
    common/               # this hierarchy represents a "role"
        tasks/            #
            main.yml      #
#########################################################

A sample playbook is given below (which we are not using any roles to split up.)


########################################################

# site.yml
---
- hosts: all    # The hosts which the playbook is going to interact #
  vars:
  remote_user: user  # User details which is used to execute this playbook#
  become: yes # Need sudo password for execution #

  tasks: # This task is used to install the ntp package from the yum repository #
  - name: Install ntp
    yum: name=ntp state=present
    tags: ntp

  - name: Configure ntp file # If we want to copy some pre configured file we need to use this session      with template #
    template: src=ntp.conf.j2 dest=/etc/ntp.conf
    tags: ntp
    notify: restart ntp

  - name: Start the ntp service # to start and enable the ntp service after the configuration #
    service: name=ntpd state=started enabled=yes
    tags: ntp

  - name: test to see if selinux is running   # check whether the selinux is enabled and disable it if it is      enabled#
    command: getenforce
    register: sestatus
    changed_when: false

  -hosts: web # This session will install the apache in web servers
  tasks:
  - name: Install httpd Package
    yum: name=httpd state=latest
  - name: Copy httpd configuration file
    copy: src=/data/httpd.original dest=/etc/httpd/conf/httpd.conf
  - name: Copy index.html file
    copy: src=/data/index.html dest=/var/www/html
    notify:
    - restart apache
  - name: Start and Enable httpd service
    service: name=httpd state=restarted enabled=yes
  handlers:
  - name: restart apache
    service: name=httpd state=restarted


- hosts: database   # This session will install the mysql package with below mentioned variables #
  vars:
    mysql_port: 3306
    dbname: somedb
    dbuser: someuser
    dbpass: somepass
  remote_user: user
  become: yes

    tasks:  # if we need to install multiple packages we can use the item method #
  - name: Install Mysql package
    yum: name={{ item }} state=installed
    with_items:
     - mysql-server
     - MySQL-python
     - libselinux-python
     - libsemanage-python

  - name: Configure SELinux to start mysql on any port
    seboolean: name=mysql_connect_any state=true persistent=yes
    when: sestatus.rc != 0

  - name: Create Mysql configuration file
    template: src=my.cnf.j2 dest=/etc/my.cnf
    notify:
    - restart mysql

  - name: Start Mysql Service
    service: name=mysqld state=started enabled=yes

  - name: insert iptables rule     #configure IP tables rule for mysql #
    lineinfile: dest=/etc/sysconfig/iptables state=present regexp="{{ mysql_port }}" insertafter="^:OUTPUT " line="-A INPUT -p tcp --dport {{ mysql_port }} -j ACCEPT"
    notify: restart iptables

  - name: Create Application Database
    mysql_db: name={{ dbname }} state=present

  - name: Create Application DB User
    mysql_user: name={{ dbuser }} password={{ dbpass }} priv=*.*:ALL host='%' state=present
#########################################################################

We can split the above playbook to short and structured way as below 

######################################################################

# site.yml
---
# This playbook deploys the whole application stack in this site.

- name: apply common configuration to all nodes
  hosts: all
  remote_user: user

  roles:
    - common

- name: configure and deploy the webservers and application code
  hosts: webservers
  remote_user: user

  roles:
    - web

- name: deploy MySQL and configure the databases
  hosts: dbservers
  remote_user: user

  roles:
    - db
#####################################################################

We can create the roles using the ansible galaxy command which will be installed along with the ansible.

#ansible-galaxy init web

This will create follwoing directories inside the ansible/role /web directory


  • files: This directory contains regular files that need to be transferred to the hosts you are configuring for this role. This may also include script files to run.
  • handlers: All handlers that were in your playbook previously can now be added into this directory.
  • meta: This directory can contain files that establish role dependencies. You can list roles that must be applied before the current role can work correctly.
  • templates: You can place all files that use variables to substitute information during creation in this directory.
  • tasks: This directory contains all of the tasks that would normally be in a playbook. These can reference files and templates contained in their respective directories without using a path.
  • vars: Variables for the roles can be specified in this directory and used in your configuration files.

structure of a role

Each folder will contain main.yml file with necessary information

├── README.md

├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
└── vars
└── main.yml

I will explain the web role with the yml file detail separately fro better understanding

Tasks directory : 

Edit the main.yml inside the task directory as below We can split the main task in to 3 files 

root@unixchips web]# cat tasks/main.yml
---
# tasks file for /etc/ansible/roles/apache
- import_tasks: install.yml
- import_tasks: configure.yml
- import_tasks: service.yml
***************************************** 
root@unixchips apache]# cat tasks/install.yml
---
- name: Install httpd Package
  yum: name=httpd state=latest
******************************************* 
[root@unixchips web]# cat tasks/configure.yml
---
- name: Copy httpd configuration file
  copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: Copy index.html file
  copy: src=files/index.html dest=/var/www/html
  notify:
  - restart apache
**********************************************
[root@unixchips web]# cat tasks/service.yml
---
- name: Start and Enable httpd service
  service: name=httpd state=restarted enabled=yes

Files directory:

Copy the required files ( index.html and httpd.conf) to this directory

[root@unixchips web]# ll files/*
-rw-r--r-- 1 root root 11753 May  4 10:01 files/httpd.conf
-rw-r--r-- 1 root root    66    May  4 10:02 files/index.html
[root@unixchips web]# cat files/index.html
This is a homepage created by unixchips for ansible roles.
[root@unixchips web]#

Handlers directory:

The main.yml file in this directory contains the code to restart the apache whenever any change is executed 

[root@unixchips web]# cat handlers/main.yml
---
# handlers file for /etc/ansible/roles/apache
- name: restart apache
  service: name=httpd state=restarted

Meta directory :

Edit the main.yml in meta directory as below to update the author and other details 

root@unixchips web# cat meta/main.yml
galaxy_info:
  author:unixchips
  description: Apache Webserver Role
  company: unixchips
  # If the issue tracker for your role is not on github, uncomment the
  # next line and provide a value
  # issue_tracker_url: http://example.com/issue/tracker
  # Some suggested licenses:
  # - BSD (default)
  # - MIT
  # - GPLv2
  # - GPLv3
  # - Apache
  # - CC-BY
  license: license (GPLv2, CC-BY, etc)
  min_ansible_version: 1.2
  # If this a Container Enabled role, provide the minimum Ansible Container version.
------skipped

When we check the directory structure in detail we will bet the output as below using the tree command 

root@unixchips web]# tree
.
|-- README.md
|-- defaults
|   `-- main.yml
|-- files
|   |-- httpd.conf
|   `-- index.html
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- tasks
|   |-- configure.yml
|   |-- install.yml
|   |-- main.yml
|   `-- service.yml
|-- templates
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
    `-- main.yml
8 directories, 13 files

Now we need to create the main playbook as below 

[root@unixchips web]# cat /etc/ansible/runsetup.yml
---
 - hosts: node2
   roles:
   - apache

If we run the playbook using the ansible command we will get the output as below 

root@unixchips web]# ansible-playbook /etc/ansible/runsetup.yml
PLAY [node2] ***************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************
ok: [node2]
TASK [apache : Install httpd Package] **************************************************************************
changed: [node2]
TASK [apache : Copy httpd configuration file] ******************************************************************
Changed: [node2]
TASK [apache : Copy index.html file] ***************************************************************************
changed: [node2]
TASK [apache : Start and Enable httpd service] *****************************************************************
changed: [node2]
RUNNING HANDLER [apache : restart apache] **********************************************************************
changed: [node2]
PLAY RECAP *****************************************************************************************************
node2                      : ok=6    changed=5    unreachable=0    failed=0


Login to the node and check the apache status 

root@node2 ~]# rpm -q httpd
httpd-2.4.6-67.el7.centos.6.x86_64
[root@node2 ~]# systemctl status httpd
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
   Active: active (running) since Sat 2018-05-04 10:23:44 IST; 1min 58s ago
     Docs: man:httpd(8)
           man:apachectl(8)

We have succesfully installed the apache web server using ansible code. 

Thank you for the reading