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:
-
AWS Account: You need an active AWS account with necessary permissions to create resources like Ec2 Instances, IAM roles, VPC, etc.
-
AWS CLI: Install and configure the AWS Command Line Interface (CLI) on your local machine. You can download it from the AWS CLI Documentation.
-
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 📋¶
##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>
ansible -i <Inventoryfile path> -m ping <Groupname>
ansible -i <Inventoryfile path> -m ping all
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
ansible -i <Inventoryfile path> -m yum -a "name=httpd state=present" websrvgrp --become
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
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
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