Showing posts with label vars. Show all posts
Showing posts with label vars. Show all posts

Sunday, March 6, 2022

Ansible (Intro, Install Steps, Architecture, Adhoc Commands/Playbooks with examples)

 



Summary:
  1. Introduction
  2. Installation (step-by-step)
  3. Architecture
  4. Modules
  5. Ad-hoc commands/Playbooks with examples



1. Ansible Introduction

Ansible is a RedHat product. It is a configuration management tool. It is one of the many IaC (infrastructure as Code). It is agentless (means only have it in the master node and it can modify/configure other system through a script/playbook or Ansible Adhoc Commands). Ansible is also a push-based mechanism.

Why ansible? 
For example:
To install java in 3 servers is easy but to install java in 100 servers, needs a lot of time.
When you installed already, then your boss ask you to update the java, cause you installed java 7, but he wanted java 11.
So use Ansible (you write one script, edit one script and fire to several servers).

Another example: Whatsapp
Whatsapp server (master) and  Whatsapp mobile app (client/agent machine)

Whatsapp mobile app update will pull from  Whatsapp server or Whatsapp server will push updates to Whatsapp mobile app.
So what is happening is pull based and push based.

Pull based: client asking from master to change
Push based: master deciding a particular script will be installed in the client

Example of pull based:- Chef, Puppet
Example of push based:- Ansible, Terraform


2. Ansible Installation (on Ubuntu)

Prerequisite: 
Python need to be installed in all nodes
passwd need to be changed

Step 1:- On the machine with Ansible (Master Server), generate the SSH key
            Syntax: ssh-keygen

Step 2:- Copy the generated SSH keys onto the hosts using copy id command

Step 3:- Before installing Ansible package, add Ansible repository to your system
            Syntax: sudo apt-add-repository ppa:ansible/ansible

Step 4:- Run the update command before installing to update existing packages
            Syntax: sudo apt-get update

Step 5:- Now install the Ansible package
            Syntax: sudo apt-get install ansible

Step 6:- You can check if you’re on the latest version of Ansible by running the version command
            Syntax: ansible --version


3. Ansible Architecture

Ansible is run on the ssh(secure shell) layer
What is ssh layer? see the other post for a step-by-step implementation of communicating with different servers via ssh.

Master Server

The Server where Ansible is installed and using Ansible you are managing the configuration on host machines (Agent machine)

Host servers/machines

These are agent machines where you need to change the configuration using Ansible. For example, if you need to change the configuration on webservers and DB servers then webservers and DB servers are host servers.

Inventory or host file. 

It is a file where it contains information of all host machines' IP addresses or FQDN (Fully Qualified Domain Name).

By default the path is:  /etc/ansible/hosts

Below are the formats by which we can configure hosts machines IP or FQDN in the hosts file:

a) IP Addresses:- You can specify the IP addresses of your host machine.

b) Group:- You can add IP address which is relevant to a group. For example, if you have 2 IPs 192.168.10.10 and 192.168.10.11 are web servers then you can specify a group called webservers

    [webservers]

      192.168.10.10

      192.188.10.11

c) Range:- You can also define a range of domain names in the host file. In below example, we are specifying domain names like db-99.mydomain to db-110.mydomain.com

     db-[99-110].mydomain.com

EXAMPLE:
Prerequisite:
  • Ansible should be installed on the master node.
  • Should have root access to Master and other nodes
  • Not mandatory but In my example, I am working as a root user
  • Master node and Managed Nodes ( Agent nodes) should be configured and in the network.
  • Master node's public key and private key ssh should be generated (ssh-keygen)
  • Master node's public key is to be shared with Agent nodes ( /root/.ssh/authorized_keys ) file

Current Setup: 3 Ubuntu Servers ( 1 master and 2 agent nodes)\

Master server is also a dbserver.
Master IP: 192.168.33.10

Webserver1 IP: 192.168.33.11
Webserver2 IP: 192.168.33.12

Host file Setup
Goto /etc/ansible/hosts file and add below entries

[dbservers]
192.168.33.10

[webservers]
192.168.33.11
192.168.33.12

Edit Ansible Configuration file:
        /etc/ansible/ansible.cfg

        uncomment(remove '#') from host file path
                inventory = /etc/ansible/hosts


4. Ansible Modules

Ansible has 1000s of modules!
to read and display all the modules:
        ansible-doc -l

to search anything specific in the modules list:
        ansible-doc -s  <yoursearch>
  • Modules are used to accomplish automation tasks in Ansible. These programs are written to be resource models of the desired state of the system. Ansible then executes these modules and removes them when finished. Without modules, you'd have to rely on ad-hoc commands and scripting to accomplish tasks.
  • Modules are used with Adhoc commands as well as with playbooks.
  • Modules are having attributes or properties which help to define the desired state of a given task.
  • For example, if you want to install an apache server on a Ubuntu machine then the apt module has a property called name and state where name indicates package name (apache2) and state indicates installed, removed etc.
Example:
  1. yum module represents yum package manager for RedHat-based OS.
  2. apt module represents apt package manager for Debian-based OS.

Ansible configuration file (ansible.cfg). It is the file that has settings related to the Ansible package.

For example:
Change the inventory path
Change role path


5. Ansible Ad-hoc Commands/Playbooks(Script files)

Ad-hoc Commands
Ansible commands to manage the IaC.
If the configuration is not complex (do not have conditional statements or loops etc.) then we can use the Ad-hoc commands.

Ansible Ad-hoc Commands:

An Ansible ad hoc command uses the /usr/bin/ansible command-line tool to automate a single task on one or more managed nodes. ad-hoc commands are quick and easy, but they are not reusable. So why learn about ad hoc commands first? ad-hoc commands demonstrate the simplicity and power of Ansible.
            
There are around 1000s modules for Ansible Ad-hoc commands!
             Examples:
      • ping module
      • service module
      • shell module
      • apt/yum module
      • copy module

Ansible PlayBooks:

Ansible playbooks are the script files that are used for managing the infrastructure on host machines that are configured in the inventory file. For example if you want to install a package on Webservers then you can write a yaml script (playbook) to install package on webservers.

Playbook (file name)
It is an ansible script name which is having extension either .yml or .yaml
---
    - name:
In Playbook we can define one or more plays and these plays represents a set of tasks that you need to execute on a set of host machines.
    hosts:
in which servers will this ansible script take place
    vars:
Plays can have some variables which you can use in the tasks.
    tasks:
Plays consist of tasks and each task is having a set of modules definition which need to execute at run time.
                command:
                copy:
                shell:


Example 1: Create a playbook to run an echo "Hello World" command on dbservers.

Create a hello.yaml in /etc/ansible folder. ( you can give any primary name but the extension should be .yaml or .yml).
        
     touch /etc/ansible/hello.yaml
     vi hello.yaml

In the .yaml file,
Type in:
---
 - name: play for running shell commands
   hosts: dbservers
   tasks:
         - name: Executing command module
           command: echo "Hello World"
Execute:
    ansible-playbook hello.yaml


BUT this does not show the output!!

So to remedy this, the hello.yaml file needs to add some more lines of codes:

register: output
- name:
  debug:
        msg: "{{ output.stdout }}"


now it will show as per picture below!

 



Example 2: Create a playbook to read a file (/tmp/status.txt) using the command module.

---
   - name: play for running shell commands
     hosts: dbservers
     tasks:
             - name: Executing cat command
               command: cat /tmp/status.txt
               register: output
             - name: Printing output of cat command
               debug:
                       msg: "{{ output.stdout }}"


Example 3: Create MULTIPLE plays in a playbook.

  • playbook: multiple.yaml
  • play1: run on dbservers and create a file /tmp/local.txt
  • play2: run on webservers and create a file /tmp/webserver.txt

---

 - name: running shell commands on dbservers

   hosts: dbservers

   tasks:

           - name: creating local.txt on dbservers

             command: touch /tmp/local.txt


 - name: running shell commands on webservers

   hosts: webservers

   tasks:

           - name: creating webservers.txt on webservers

             command: touch /tmp/webservers.txt



done!


Example 4: Create a yaml file called (mul.yaml) and make a script such that it will create a file (testansible.txt) in /tmp and add content ("Hello World") in that .txt file and read it.


touch /etc/ansible/mul.yaml

vi /etc/ansible/mul.yaml

---

 - name: running shell command on dbservers

   hosts: dbservers

   tasks:

           - name: creating a file in /tmp/

             command: touch /tmp/testansible.txt

           - name: adding text in the .txt file (you can use copy module or shell module)

             copy:

                     content: "Hello World"

                     dest: /tmp/testansible.txt

            shell: echo "Hello World2" >> /tmp/testansible.txt

           - name: executing cat command on content of .txt file

             command: cat /tmp/testansible.txt

             register: output

           - name: printing out the content

             debug:

                     msg: "{{ output.stdout }}"


ansible-playbook mul.yaml


Example 5: Create a variable and store "Hello World" then print it out using the same mul.yaml file as example 4 above.

vi mul.yaml

---

 - name: running shell command on dbservers

   hosts: dbservers

   vars:

           string: "Hello World!"

   tasks:

           - name: creating a file in /tmp/

             command: touch /tmp/testansible.txt

           - name: adding text in the .txt file

             copy:

                     content: "{{ string }}"

                     dest: /tmp/testansible.txt

           - name: executing cat command on content of .txt file

             command: cat /tmp/testansible.txt

             register: output

           - name: printing out the content

             debug:

                     msg: "{{ output.stdout }}"


Example 6: use vars_prompt 

---
 - name: running shell command on dbservers
   hosts: dbservers
   vars_prompt:
           name: data
           prompt: Enter the value
   tasks:
           - name: creating a file in /tmp/
             command: touch /tmp/testansible.txt

           - name: adding text in the .txt file
             copy:
                     content: "{{ data }}"
                     dest: /tmp/testansible.txt

           - name: executing cat command on content of .txt file
             command: cat /tmp/testansible.txt
             register: output

           - name: printing out the content
             debug:
                     msg: "{{ output.stdout }}"


Example 7: Dry Run with --check and check mode

Dry Run

When ansible-playbook is executed with --check it will not make any changes on remote systems. Instead, any module instrumented to support ‘check mode’ (which contains most of the primary core modules, but it is not required that all modules do this) will report what changes they would have made rather than making them. Other modules that do not support check mode will also take no action, but just will not report what changes they might have made.

Example 7.1: Dry Run with --check
Below script is copying /tmp/testing.txt file to webservers /tmp/test.txt. but if you use --check option with ansible-playbook execution it will only do the dry run not actually running the command to copy to webservers.

touch /tmp/testing.txt
touch dryrun.yaml
vi dryrun.yaml
--- 
 - name: play for dry run 
   hosts: webservers 
   tasks: 
         - name: Copying testing.txt file to webservers 
           copy: 
                    src=/tmp/testing.txt 
                    dest=/tmp/test.txt


ansible-playbook dryrun.yml --check


Example 7.2: Dry Run with check_mode

touch dryruncheckmode.yaml
vi dryruncheckmode.yaml
--- 
 - name: play for dbservers multiple tasks 
   hosts: dbservers 
   vars_prompt: 
             name: data 
             prompt: Enter the value 
   tasks: 

        # Task1 
         - name: create a file 
           command: touch /tmp/myfile.txt 
           check_mode: no          (this will not apply dry run) 

         # Task2 
         - name: Add content to the file 
           copy: 
                 content: "{{ data }}" 
                 dest: /tmp/myfile.txt 
           check_mode: yes          (this will apply dry run) 

         # Task 3 
         - name: Read the content 
           command: cat /tmp/myfile.txt     
           register: output 

         # Task 4 
         - name: Print the content 
           debug: 
                 var: output.stdout


ansible-playbook dryruncheckmode.yaml


Example 10: logging with log_path

Playbook:- dryrun.yaml

uncomment log_path in ansible.cfg file to store the log output in /var/log/ansible.log

--- 
 - name: play for dry run 
   hosts: webservers 
   tasks: 
         - name: Copying testing.txt file to webservers 
           copy: src=/tmp/testing.txt 
          dest=/tmp/test.txt

ansible-playbook dryrun.yaml


After execution check /var/log/ansible.log file it should have the log of this file execution.


Example 11: no_log attribute

if no_log =True then no log information is recorded in the log file for that particular module.


Example 12: Error handling ( ignore_errors: True)

Playbook: error.yaml
In the below code, Task3 will be executed because Task2 is having the exception handling.

--- 
 - hosts: webservers 
   tasks: 
        - name: Task1 
          command: date 

        - name: Task2 
          command: date1 
          ignore_errors: True 

        - name: Task3 
          command: ls

ansible-playbook error.yaml



Example 13: Magic variables (Ansible Facts)

Playbook: facts.yaml
Run the below command to find the facts of a host, it also returns the in-built ansible variables. In below command stores the output of these inbuilt variables in facts.log file


ansible dbservers -m ansible.builtin.setup > facts.log

to read the log:
vi facts.log

vi facts.yaml
---
 - name: play for finding the facts using ansible magic variables 
   hosts: webservers 
   tasks: 
             - name: Print some facts 
               debug: 
                             msg: "{{ ansible_facts['os_family'], ansible_facts['nodename'] }}"


ansible-playbook facts.yaml

It should print the OS Name and node name of web servers.


Example 14: create a conditional statement (when) if the server is using the os_family of RedHat.

vi conditional.yaml
---
 - name: play for conditional statements
   hosts: webservers
   tasks:
           - name: install httpd (apache server on CentOS)
             yum:
                     name: httpd
                     state: present
             when: ansible_facts['os_family']=='RedHat'

It should skip for the webservers cause they are debian-based systems.

Example 15: (!= operator)
Create a playbook to install apache2 on OS which doesn't belong to RedHat family

vi conditionnotequals.yaml
---
- name: play for conditonal statements
  hosts: webservers
  tasks:
        - name: install apache2
          apt:
                name: apache2
                state: present
          when: ansible_facts['os_family']!="RedHat"

ansible-playbook conditionnotequals.yaml



Example 16: (or logical operator)
Create a playbook to install apache2 on OS which doesn't belong to RedHat family or belongs to Debian OS family

vi conditionor.yaml
---
- name: play for conditonal statements
  hosts: webservers
  tasks:
        - name: install apache2
          apt:
                name: apache2
                state: present
          when: ansible_facts['os_family']!="RedHat" or ansible_facts['os_family']=="Debian"

ansible-playbook conditionor.yaml



Example 17: (and logical operator)
Create a playbook to install apache2 on OS which doesn't belong to Debian OS family and OS is Ubuntu

vi conditionand.yaml
---
- name: play for conditonal statements
  hosts: webservers
  tasks:
        - name: install apache2
          apt:
                name: apache2
                state: present
          when: ansible_facts['os_family']=="Debian" and ansible_distribution=="Ubuntu"


ansible-playbook conditionand.yaml



Example 18: Loops part 1 (iterate through item)

vi loops1.yaml
---
- name: playbook for loops example
  hosts: dbservers
  tasks:
        - name: print values using loops
          debug:
                msg: "{{ item }}"
          with_items / loop:
                - 1
                - 2
                - 3
                - 4


ansible-playbook loops1.yaml

Example 19: Loops part 2 (iterate through making directories)
Create some directories under /tmp using loop statement

vi loop2.yaml
---
 - name: play for loops
   hosts: dbservers
   tasks:
    - name: Create Multiple directories
      command: mkdir "{{ item }}"
      loop / with_items:
           - /tmp/1
           - /tmp/2
           - /tmp/3
           - /tmp/4

ansible-playbook loops2.yaml

Example 20: Loops part3 (remove directories created on example 19 using loops)

vi loop3.yaml

---
 - name: play for loops
   hosts: dbservers
   vars:
       dirs:
          - /tmp/1
          - /tmp/2
          - /tmp/3
   tasks:
     - name: removing directories
       command: rmdir "{{ item }}"
       with_items / loop: "{{ dirs }}"

ansible-playbook loop3.yaml


Fluentd

Open-source log data collector > why logs? - for compliance (auditing, company, business) - for security (transparency, monitoring, admin...