Skip to content

Ansible

Ansible is an open-source IT Configuration Management, Deployment & Orchestration tool. It aims to provide large productivity gains to a wide variety of automation challenges. This tool is very simple to use yet powerful enough to automate complex multi-tier IT application environments.

Installing Ansible

sudo apt update
sudo apt install software-properties-common -y
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible -y
ansible --version

sudo yum install epel-release -y
sudo yum install ansible -y
ansible --version

SCP Commands

To Copy files From Localmachine to Remote machine

scp -i <private-key-file-path> <files to copy> <user>@<IP>:<Remote-machine-path>

Example

scp -i Downloads/control.pem sample.txt ubuntu@54.165.128.104:/home/ubuntu/

To Copy Files from Remotemachine to Local machine

scp -i <private-key-file-path> <user>@<IP>:<remote-files-path> <Localmachine-path>

Example

scp -i Downloads/control.pem ubuntu@54.165.128.104:/home/ubuntu/sample.txt Desktop/

Sample Inventory File

##Host Level

webserver01    ansible_host=<Private IP>
webserver02    ansible_host=<Private IP>
webserver03    ansible_host=<Private IP>      
dbserver01     ansible_host=<Private IP>
dbserver02     ansible_host=<Private IP>      ansible_user=ubuntu

##Group Level 

[Group1]
webserverserver01
webserverserver02
webserverserver03

[Group2]
dbserver01
dbserver02

##Parent Level

[dc_mumbai:children] 
webservergrp
dbsrvgrp

##Variables

[dc_mumbai:vars]
ansible_user=<user>
ansible_ssh_private_key_file=<key-path>

Info

Host level has the highest priority, If you mention anything like username or Keyfile etc. It will take only, which are mentioned at the host level.

Ansible Commands

To test the connection of a particular Remote Machine

ansible -i <Inventoryfile path> -m ping <hostname>
To test the connection of a particular Group of Remote Machines
ansible -i <Inventoryfile path> -m ping <Groupname>
To test the connection of All Remote Machine
ansible -i <Inventoryfile path> -m ping all
To see details about the machine
ansible -i <Inventoryfile path> -m setup <hostname>

Some Example Ad hoc Commands

Copy files to Remote machines name start with web

ansible -i <Inventoryfile path> -m copy -a "src=index.html dest=/var/www/html/index.html" 'web*' --become
Installing httpd in centos Remote machine
ansible -i <Inventoryfile path> -m yum -a "name=httpd state=present" websrvgrp --become
Start & Enable httpd in centos Remote machine
ansible -i <Inventoryfile path> -m service -a "name=httpd state=started enabled=yes" websrvgrp --become

Info

Ansible Playbooks should be with .yml or .yaml Extension for example vim sample.yml

Playbook For Creating Files & Directories

- name: Creating Files & Directories
  hosts: <host>
  become: yes
  tasks:
     - name: Creating a Directory
         file:
           path: /tmp/welcome
           state: directory

     - name: Creating a File
         file:
           path: /tmp/sample.txt
           state: touch
To Execute the playbook
ansible-playbook -i <Inventory file path> sample.yml

Writing Playbook For Installing Httpd service in remote machines with start and enable and copying index.html files from local machine to the remote machine

- name: Install httpd and start the service
  hosts: all
  tasks:
     - name: Installing the Apache package
       yum:
         name: httpd
         state: present


     - name: Starting service
       service:
         name: httpd
         state: started
         enabled: yes

     - name: Copy file with owner and permissions
       copy:
         src: ./index.html
         dest: /var/www/html/index.html

     - name: Restarting service
       service:
         name: httpd
         state: restarted

Writing Playbook for Setting Up Website in Remote Machine

- name: Setting up Website
  hosts: websrv
  gather_facts: False
  become: True

  tasks:
    - name: Installing Packages in CentOS
      yum:
        name: "{{item}}"
        state: present
      when: ansible_distribution == "CentOS"
      loop:
        - httpd
        - wget
        - unzip

    - name: Start & Enable httpd
      service:
        name: httpd
        state: started
        enabled: yes   

    - name: Downloading Source code
      get_url:
        url: https://www.tooplate.com/zip-templates/2114_pixie.zip
        dest: /opt

    - name: Unarchive a file that is already on the remote machine
      unarchive:
        src: /opt/2114_pixie.zip
        dest: /opt
        remote_src: yes

    - name : Deploy Website
      copy:
        src: /opt/2114_pixie/
        dest: /var/www/html/
        remote_src: yes


    - name: Restarting httpd service
      service:
        name: httpd
        state: restarted

Writing Playbook for Setting Up Website in Remote Machine with Conditions & Handlers.

- name: Writing playbook for loops and conditions
  hosts: all
  tasks:
    - name: Install packages on centos
      yum:
        name: "{{item}}"
        state: present
      when: ansible_distribution == "CentOS"
      loop:
        - httpd
        - wget
        - unzip
        - zip
        - git           

    - name: Install packages on Ubuntu 
      apt:
        name: "{{item}}"
        state: present
        update_cache: yes
      when: ansible_distribution == "Ubuntu"
      loop:
        - apache2
        - wget
        - unzip
        - zip
        - git


    - name: Start & enable service on CentOS
      service:
       name: httpd
       state: started
       enabled: yes
      when: ansible_distribution == "CentOS"

    - name: Start & enable service on Ubuntu
      service:
       name: apache2
       state: started
       enabled: yes
      when: ansible_distribution == "Ubuntu"


    - name: Push index.html on centos
      copy:
        src: index.html
        dest: /var/www/html/
        backup: yes
      when: ansible_distribution == "CentOS"
      notify:
        - Restart service on CentOS

    - name: Push index.html on ubuntu
      copy:
        src: index.html
        dest: /var/www/html/
        backup: yes
      when: ansible_distribution == "Ubuntu"
      notify:
        - Restart service on Ubuntu

  handlers:
    - name: Restart service on CentOS
      service:
        name: httpd
        state: restarted
        enabled: yes
      when: ansible_distribution == "CentOS"

    - name: Restart service on Ubuntu
      service:
        name: apache2
        state: restarted
        enabled: yes
      when: ansible_distribution == "Ubuntu"

Writing Playbook to Create VPC in AWS Cloud and Including Variables from different File

Requirements
  • python >= 3.6

  • boto3 >= 1.15.0

  • botocore >= 1.18.0

apt install python3-pip
pip install boto
pip install boto3
pip install botocore
Creating File to store Variables
vim vpc_setup.txt
vpc_name: "Vprofile-vpc"

#Vpc-range
vpcrange: '172.21.0.0/16'

#subnet range
pubip1: '172.21.1.0/24'
pubip2: '172.21.2.0/24'
pubip3: '172.21.3.0/24'
pvtip1: '172.21.4.0/24'
pvtip2: '172.21.5.0/24'
pvtip3: '172.21.6.0/24'

#region
region: 'us-east-2'

#zone names
zone1: us-east-2a
zone2: us-east-2b
zone3: us-east-2c


state: present

- hosts: localhost
  connection: local
  gather_facts: False
  tasks:
    - name: Import vpc variables
      include_vars: /path/vpc_setup

    - name: create vpc
      ec2_vpc_net:
          name: "{{vpc_name}}"
          cidr_block: "{{vpcrange}}"
          region: "{{region}}"
          dns_support: yes
          dns_hostnames: yes
          tenancy: default
          state: "{{state}}"
      register: vpcout


    - name: Create a public subnet for zone1
      ec2_vpc_subnet:
          vpc_id: "{{vpcout.vpc.id}}"
          region: "{{region}}"
          az: "{{zone1}}"
          state: "{{state}}"
          cidr: "{{pubip1}}"
          map_public: yes
          tags:
            Name: vprofile_pubsub1
      register: pubsub1_out

    - name: Create a public subnet for zone2
      ec2_vpc_subnet:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         az: "{{zone2}}"
         state: "{{state}}"
         cidr: "{{pubip2}}"
         map_public: yes
         tags:
           Name: vprofile_pubsub2
      register: pubsub2_out

    - name: Create a public subnet for zone3
      ec2_vpc_subnet:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         az: "{{zone3}}"
         state: "{{state}}"
         cidr: "{{pubip3}}"
         map_public: yes
         tags:
           Name: vprofile_pubsub3
      register: pubsub3_out

    - name: Create a private subnet for zone1
      ec2_vpc_subnet:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         az: "{{zone1}}"
         state: "{{state}}"
         cidr: "{{pvtip1}}"
         map_public: yes
         tags:
           Name: vprofile_pvtsub1
      register: pvtsub1_out

    - name: Create a private subnet for zone2
      ec2_vpc_subnet:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         az: "{{zone2}}"
         state: "{{state}}"
         cidr: "{{pvtip2}}"
         map_public: yes
         tags:
           Name: vprofile_pvtsub2
      register: pvtsub2_out

    - name: Create a private subnet for zone3
      ec2_vpc_subnet:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         az: "{{zone3}}"
         state: "{{state}}"
         cidr: "{{pvtip3}}"
         map_public: yes
         tags:
           Name: vprofile_pvtsub3
      register: pvtsub3_out

    - name: Internet gateway setup
      ec2_vpc_igw:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         state: "{{state}}"
         tags:
           Name: vprofile_IGW
      register: igw_out



    - name: public subnet route table
      ec2_vpc_route_table:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         tags:
           Name: vprofile_Public
         subnets:
           - "{{pubsub1_out.subnet.id}}"
           - "{{pubsub2_out.subnet.id}}"
           - "{{pubsub3_out.subnet.id}}"
         routes:
           - dest: 0.0.0.0/0
             gateway_id: "{{ igw_out.gateway_id }}"
      register: public_route_table


    - name: Create a new nat gateway and allocate a new EIP if a nat gateway does not yet exist in the subnet.
      ec2_vpc_nat_gateway:
         state: "{{state}}"
         subnet_id: "{{pubsub1_out.subnet.id}}"
         wait: true
         region: "{{region}}"
         if_exist_do_not_create: true
      register: nat_out

    - name: private subnet route table
      ec2_vpc_route_table:
         vpc_id: "{{vpcout.vpc.id}}"
         region: "{{region}}"
         tags:
           Name: vprofile_Private
         subnets:
           - "{{pvtsub1_out.subnet.id}}"
           - "{{pvtsub2_out.subnet.id}}"
           - "{{pvtsub3_out.subnet.id}}"
         routes:
           - dest: 0.0.0.0/0
             gateway_id: "{{nat_out.nat_gateway_id}}"
      register: private_route_table


    - debug:
        var: "{{item}}"
      loop:
         - vpcout.vpc.id
         - pubsub1_out.subnet.id
         - pubsub2_out.subnet.id
         - pubsub3_out.subnet.id
         - pvtsub1_out.subnet.id
         - pvtsub2_out.subnet.id
         - pvtsub3_out.subnet.id
         - igw_out.gateway_id
         - public_route_table.route_table.id
         - nat_out.nat_gateway_id
         - private_route_table.route_table.id

    - set_fact:
        vpcid: "{{vpcout.vpc.id}}"
        pubsublid: "{{ pubsub1_out.subnet.id }}"
        pubsub2id: "{{ pubsub2_out.subnet.id }}"
        pubsub3id: "{{ pubsub3_out.subnet.id }}"
        privsublid: "{{ pvtsub1_out.subnet.id }}"
        privsub2id: "{{ pvtsub2_out.subnet.id }}"
        privsub3id: "{{ pvtsub3_out.subnet.id }}"
        igwid: "{{ igw_out.gateway_id }}"
        pubRTid: "{{ public_route_table.route_table.id }}"
        NATGWid: "{{ nat_out.nat_gateway_id }}"
        privRTid: "{{ private_route_table.route_table.id }}"
        cacheable: yes

    - name: creating file for vpc output
      copy:
        content: "vpcid: {{vpcout.vpc.id}}\n pubsublid: {{ pubsub1_out.subnet.id }}\npubsub2id: {{ pubsub2_out.subnet.id }}\npubsub3id: {{ pubsub3_out.subnet.id }}\nprivsublid: {{ pvtsub1_out.subnet.id }}\nprivsub2id: {{ pvtsub2_out.subnet.id }}\nprivsub3id: {{ pvtsub3_out.subnet.id }}\nigwid: {{ igw_out.gateway_id }}\npubRTid: {{ public_route_table.route_table.id }}\nNATGWid: {{ nat_out.nat_gateway_id }}\nprivRTid: {{ private_route_table.route_table.id }}"
        dest: /home/ubuntu/Vprofile/vars/output_vars

Launching Ec2 Instance in AWS Cloud

Requirements
  • python >= 3.6

  • boto3 >= 1.15.0

  • botocore >= 1.18.0

apt install python3-pip
pip install boto
pip install boto3
pip install botocore

- name: Launching Ec2 Instance
  hosts: localhost
  connection: local
  tasks:
     - name: Creating Key pair
       amazon.aws.ec2_key:
         name: samplekey
         region: us-west-1
       register: key

     - debug:
        var: key

     - name: Storing private key into a file
       copy:
          content: "{{key.key.private_key}}"
          dest: "./sample.pem"
          mode: 0600
       when: key.changed


     - name: Creating Security Group
       amazon.aws.ec2_group:
         name: mysg
         description: Allowing 22 and 80
         vpc_id: vpc-0c8e70cf05b1342ac
         region: us-west-1
         rules:
           - proto: tcp
             from_port: 22
             to_port: 22
             cidr_ip: 0.0.0.0/0
             rule_desc: allow all on port 80 & 22
       register: sg_out

     - name: Launching bastion_host
       ec2:
          key_name: "samplekey"
          region: us-west-1
          instance_type: t2.micro
          image: ami-0573b70afecda915d
          wait: yes
          wait_timeout: 300
          instance_tags:
            name: "Ansible Instance"
            project: vprofile
            owner: devops team
          exact_count: 1
          count_tag:
            name: "Ansible Instance"
            project: vprofile
            owner: devops team
          group_id: "{{sg_out.group_id}}"
          vpc_subnet_id: subnet-0c4734c845e549cda
       register: instance

Ansible Configuration File

Note

You should save the configuration file with name ansible.cfg

vim ansible.cfg
[defaults]
host_key_checking=False
inventory=<Inventory File Path>
timeout=20
log_path=/var/log/ansible_world.log
remote_port=22
remote_user=<username>

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False