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

Prerequisites

Before you begin, ensure you have the following prerequisites in place:

  1. AWS Account: You need an active AWS account with necessary permissions to create resources like Ec2 Instances, IAM roles, VPC, etc.

  2. AWS CLI: Install and configure the AWS Command Line Interface (CLI) on your local machine. You can download it from the AWS CLI Documentation.

  3. IAM User: Create an AWS IAM user with programmatic access and necessary permissions (e.g., Ec2 Full Access, S3 Full Access). Note down the user's access key ID and secret access key. Reference Document Link

Warning

Utilize Role-Based Authentication when working with Terraform on AWS Instances or Services, as it offers a higher level of security compared to using access keys.

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 📋

inventory
##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

Command Line
ansible -i <Inventoryfile path> -m copy -a "src=index.html dest=/var/www/html/index.html" 'web*' --become
Installing httpd in centos Remote machine
Command Line
ansible -i <Inventoryfile path> -m yum -a "name=httpd state=present" websrvgrp --become
Start & Enable httpd in centos Remote machine
Command Line
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 📚

1st_playbook.yaml
- 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 🌐

installation_service.yaml
- 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 🌐

website.yaml
- 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.🌐

loops_conditions_handlers.yaml
- 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

aws_vpc.yaml
- 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

aws_ec2.yaml
- 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
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