Ansible – Configuring multiple instances through Ansible

Ansible:

Ansible is an open-source automation tool used for configuration management, application deployment, task automation, and orchestration. It employs declarative language to define the desired state of infrastructure, operates in an agentless manner, and uses simple YAML scripts called playbooks to execute tasks across multiple machines. Ansible is widely used in IT operations, DevOps, and system administration to automate routine tasks, enforce consistency, and streamline the management of infrastructure.

Flow Diagram

Steps:

Step 1: Launch ec2 instances

Step 2: Install Ansible in the Ansible control node

Step 3: Connect the ansible control node with the managed nodes and check for connectivity

Step 4: Perform some task , like:

   A) Ping           

   B) Run a command             

   C) Copy a File                   

   D) Install package           

   E) Execute a Shell Command              

Step 5: Ansible playbooks

Step 6: Ansible roles

Step 7: Ansible Galaxy

Step 8: LAMP stack

Step 9: Create encrypted files with ansible

Step 10: Setup Ansible Dynamic Inventory

 

Step 1: Launch ec2 instances

Launch ec2 instances: 1 for the Ansible control node and 2 as managed (target) node

Launch one instance with Amazon Linux OS as ansible master and 2 others as client machines. In the 2 client machine create one with Amazon Linux OS  and the other with Ubuntu. 

We will be installing Ansible in the master machine and configuring the other 2 as Ansible client machines.

 

Step 2: Install Ansible in the Ansible control node

SSH into the host machine and execute the below command to install Ansible:

sudo su

yum update -y

yum install ansible -y

 

Step 3: Connect the ansible control node with the managed nodes and check for connectivity

 

Ansible uses an inventory file that holds the data of worker machines(IPs) to be connected with the host machine.

— Let’s connect our host machine with client machine and check its status.

cd /etc/ansible/

mkdir .ssh

cd .ssh

vi my_key #Paste your private key value (.pem) to ssh

cd ..

chmod 600 ./.ssh/my_key

Create new host files (used as an inventory file) to store the IP addresses of client nodes.

vi hosts                              #here “hosts” file is the inventory file

#Paste the below content with ip of your worker machine
[workers]
worker1 ansible_host=23.22.80.52 ansible_user=ec2-user ansible_ssh_private_key_file=./.ssh/my_key
worker2 ansible_host=53.22.34.52 ansible_user=ubuntu ansible_ssh_private_key_file=./.ssh/my_key

 

To check for connectivity, run the ping command :

ansible all -i hosts -m ping 

 

Execution of tasks on machines through Ansible can be primarily done in two ways i.e. AdHoc Commands and Playbooks.

The Below table lists the common differences between ad-hoc commands and playbooks.

 

                                                                  1)Ad hoc                                                                    2) Playbooks

Aspect Ad Hoc Commands Playbooks
Purpose Quick tasks, one-off operations, testing. Configuration management, automation, complex tasks.
Execution Method Command line using ansible command. YAML file executed using ansible-playbook command.
Syntax Simple one-liners. Structured YAML with tasks, plays, and roles.
Control Flow Limited to simple tasks, less control flow capabilities. Supports advanced control flow, conditional statements.
Reusability Less reusable, designed for immediate use. Highly reusable, can be organized into roles.
Modularity Limited modularity. Highly modular with roles, tasks, and variables.
Examples ansible all -m ping ansible-playbook -i <inventory> example_playbook.yml
Parallel Execution Yes, can execute tasks on multiple hosts in parallel. Yes, tasks can run in parallel across different hosts.
Immediate Execution Suitable for immediate execution of tasks. Suitable for automation, ensuring consistency.
Task Complexity Simple, one-off tasks. Suitable for complex automation with multiple tasks.

 

Ad hoc commands in Ansible:

– Simple syntax:

ansible <host-pattern> -m <module> -a <module-arguments>

 

Step 4: Perform some tasks, like:

Ping:

A few flags are as:

-m – module

-a – arguments

-b – sudo privileges

 

ansible all -i hosts -m ping              #Tries to connect with registered nodes

 

Run a command:

Here command will be executed on worker machines directly

ansible all -i hosts -a "ls /path/to/directory" #give some path and verify

 

Copy a File:

Copy a file from your local machine to the managed nodes

-First, create a file from-master.txt in the master and run the below command to copy in nodes:

ansible all -i hosts -m copy -a "src=/etc/ansible/file_from_master.txt dest=/home/ec2-user/text.txt"

Here content in file from_master.txt from the master machine is copied as text.txt in the worker machine

 

Install a Package:

Install a package on the managed nodes, using the ansible package manager. Here we are using module

ansible all -i hosts -m apt -a "name=package-name state=present" # For Debian/Ubuntu

ansible all -i hosts -m yum -a "name=package-name state=present" # For RHEL/CentOS/Amazon linux

 

To install git in the managed nodes using package manager, use below commands:

ansible worker1 -i hosts -m yum -a "name=git state=present" -b

ansible worker2 -i hosts -m apt -a "name=git state=present" -b

 

Execute a Shell Command:

Run a shell command on the managed nodes

ansible all -i hosts -a "command-to-run"

ansible all -i hosts -a "sudo yum install docker -y"
#or
ansible all -i hosts -a "yum install docker -y" -b

 

Step 5: Ansible Playbook

 

A playbook is a structured and reusable configuration file that defines a set of tasks to be executed on a group of hosts. Playbooks are written in YAML (YAML Ain’t Markup Language) and serve as a human-readable and machine-readable way to describe automation tasks.

A playbook typically consists of the following components:

Hosts: Specifies the target hosts or groups of hosts on which the tasks in the playbook will be executed. Hosts can be defined using patterns or explicitly listed.

Tasks: Describes a series of steps or actions to be performed on the target hosts. Each task is a module invocation, and modules are Ansible’s units of work. Tasks can include actions such as installing packages, copying files, restarting services, etc.

Variables: Allows the definition of variables that can be used in the playbook. Variables can be specific to hosts, groups, or global in scope.

Roles: Organizes tasks, variables, and other files into a reusable structure. Roles are a way to modularize and share Ansible content. Playbooks can include roles, and roles can include other roles.

Playbooks are executed using the ansible-playbook command, and they provide a powerful and flexible way to automate infrastructure configuration and management.

#Playbook for reference

---
- hosts: webservers
  tasks:
    - name: Install Apache
      apt:
        name: apache2
        state: present

    - name: Start Apache service
      service:
        name: apache2
        state: started

 

1. Playbook to install Chrome in managed nodes.

vi chrome_install.yml
#Paste the below playbook
-------------------------------------------------
- hosts: workers
  become: true
  vars:
    ansible_become_method: sudo
    ansible_become: yes
    ansible_become_user: root

  tasks:
    - name: Import Google Chrome GPG key (Debian-based)
      apt_key:
        url: https://dl-ssl.google.com/linux/linux_signing_key.pub
        state: present
      when: ansible_pkg_mgr == 'apt'

    - name: Import Google Chrome GPG key (Red Hat-based)
      rpm_key:
        key: https://dl-ssl.google.com/linux/linux_signing_key.pub
        state: present
      when: ansible_pkg_mgr in ['yum', 'dnf']

    - name: Add Google Chrome repository (Debian-based)
      apt_repository:
        repo: deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main
        state: present
      when: ansible_pkg_mgr == 'apt'

    - name: Add Google Chrome repository (Red Hat-based)
      yum_repository:
        name: google-chrome
        description: Google Chrome Repository
        baseurl: http://dl.google.com/linux/chrome/rpm/stable/x86_64
        gpgkey: https://dl-ssl.google.com/linux/linux_signing_key.pub
        state: present
      when: ansible_pkg_mgr in ['yum', 'dnf']

    - name: Update package manager cache (Debian-based)
      apt:
        update_cache: yes
      when: ansible_pkg_mgr == 'apt'

    - name: Update package manager cache (Red Hat-based)
      dnf:
        update_cache: yes
      when: ansible_pkg_mgr == 'dnf'

    - name: Install Google Chrome (Debian-based)
      apt:
        name: google-chrome-stable
        state: present
      when: ansible_pkg_mgr == 'apt'

    - name: Install Google Chrome (Red Hat-based)
      dnf:
        name: google-chrome-stable
        state: present
      when: ansible_pkg_mgr == 'dnf'

    - name: Verify Chrome installation
      command: google-chrome --version
      register: chrome_version
      ignore_errors: true

    - name: Print Chrome version
      debug:
        var: chrome_version.stdout_lines
      when: "'Google Chrome' in chrome_version.stdout_lines[0]"


Run the playbook using the following command:

ansible-playbook -i hosts example_playbook.yml

 

This playbook does the following:

  1. Installs necessary dependencies based on the distribution (LSB for Ubuntu and redhat-lsb-core for CentOS).
  2. Determines the package manager (yum for CentOS, apt for Ubuntu).
  3. Downloads Google Chrome repository file for CentOS.
  4. Imports Google Chrome signing key for CentOS.
  5. Installs Google Chrome on CentOS using yum and on Ubuntu using the direct download link for the .deb package.
  6. Verifies that Google Chrome is installed by checking its version.

 

2. Playbook to Copy files to managed nodes from the control node

Create a file master in the control node

vi sscript.sh #for some commands
#Paste below commands


vi copy.yml #Playbook to copy file
#Use below playbook
-----------------------
- name: copy file to nodes
  hosts: workers
  become: true
  
  tasks:
    - name: copy files from ansible master to nodes
      copy: 
	src: /etc/ansible/sscript.sh/
	dest: /home/ec2-user/worker/shellscript.sh

ansible-playbook -i hosts copy.yml

 

3. Playbook to execute shell script in nodes

To execute shell script in managed nodes from control node using playbook, write the playbook as mentioned below:

vi shellscript.yml
#Use the below playbook
---------------------
- name: copy file to nodes
  hosts: workers
  become: true
  
  tasks:  
    - name: copy files from ansible master to nodes
      copy: 
	src: /etc/ansible/sscript.sh/
        dest: /home/ec2-user/worker/shellscript.sh

    - name: Execute shell scripts
      command: /home/ec2-user/worker/shellscript.sh

ansible-playbook -i hosts shellscript.yml

 

 

4. A playbook to backup a file in the remote servers before copying it into the server

touch helloworld.txt
 
vi copy.yml
---
- hosts: workers
  tasks:
    - name: ansible copy file backup example
      copy:
        src: /etc/ansible/helloworld.txt
        dest: /tmp
        backup: yes

ansible-playbook -i hosts copy.yml

The backup file will be created in the same directory as the destination file, and its name will have a timestamp appended to it.

 

5. Playbook to Install, start, enable the nginx service, and then grep the nginx version and check the nginx service status on the host machine using Ansible


vi nginix.yml
#Playbook to install Nginix server
---
- name: Setup Nginx server on myserver list
  hosts: workers
  become: true
  tasks:
    - name: Install the latest version of Nginx
      package:
        name: nginx
        state: latest
      when: ansible_distribution == 'Amazon'

    - name: Install Nginx on Ubuntu
      apt:
        name: nginx
        state: present
      when: ansible_distribution == 'Ubuntu'

    - name: Start Nginx
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Ensure nginx is at the latest version
      command: nginx -v

    - name: Get status of nginx installed
      command: systemctl status nginx

ansible-playbook -i hosts nginix.yml

 

Step 6: Ansible roles

 

Ansible Roles:

Ansible roles are a way to organize and package related tasks, handlers, variables, and files into a reusable structure. Roles make it easier to manage and share complex automation workflows. They provide a standardized and modular approach to organizing Ansible playbooks.

Here’s how to create a simple Ansible role:

Step 1: Directory Structure

Create the directory structure for a role. For example, let’s call the role “webserver.”

  1. Open a terminal.
  2. Run the following command to create a new Ansible role:  ansible-galaxy init webserver
webserver/
├── tasks/
│   └── main.yml
├── handlers/
│   └── main.yml
├── templates/
├── files/
├── vars/
│   └── main.yml
├── defaults/
│   └── main.yml
└── README.md
  • tasks/main.yml: Contains the main tasks for the role.
  • handlers/main.yml: Contains handlers for the role.
  • templates/: Directory for Jinja2 templates.
  • files/: Directory for static files to be copied to the target.
  • vars/main.yml: Contains variables for the role.
  • defaults/main.yml: Contains default values for variables.
  • README.md: Documentation for the role.

 

Step 2: Write Tasks

Edit the tasks/main.yml file with the main tasks you want the role to perform. For example, let’s create a role to install and start the Apache service.

# webserver/tasks/main.yml
vi webserver/tasks/main.yml
---
- name: Install Apache
  apt:
    name: apache2
    state: present

- name: Start Apache service
  service:
    name: apache2
    state: started

Step 3: Write Handlers

Edit the handlers/main.yml file with any handlers you need for the role. Handlers are tasks that respond to notifications from other tasks.

# webserver/handlers/main.yml
vi webserver/handlers/main.yml
---
- name: Restart Apache
  service:
    name: apache2
    state: restarted

Step 4: Write Variables

Edit the vars/main.yml file to define variables for the role.

# webserver/vars/main.yml
vi webserver/vars/main.yml
---
apache_port: 80

Step 5: Write Defaults

Edit the defaults/main.yml file to provide default values for variables.

# webserver/defaults/main.yml
vi webserver/defaults/main.yml
---
apache_port: 80

Step 6: Use the Role in a Playbook

You can now use your role in an Ansible playbook.

cd /etc/ansible/
vi playbook.yml
# playbook.yml
---
- hosts: worker2
  roles:
    - webserver

 

Step 7: Run the Playbook

Run the playbook using the following command from the ansible root directory:
ansible-playbook -i hosts playbook.yml -b

Browse the webpage with <ip> of ubuntu worker machine and should see apache server info on webpage

 

 

 

Step7: Ansible Galaxy

Ansible Galaxy is a platform for sharing, finding, and managing Ansible content. It provides a centralized hub where you can discover and share roles, collections, and other Ansible content. Ansible content available on Galaxy can be easily reused, which accelerates automation development.

Here are key components and concepts related to Ansible Galaxy:

  1. Roles:
    • Roles are a way of organizing and distributing Ansible content.
    • They provide a structured way to organize tasks, variables, and other content.
    • Roles can be used to encapsulate reusable functionality and share it across different projects.
    • Roles can be created manually or downloaded from Ansible Galaxy.
  2. Collections:
    • Collections are a more recent addition to Ansible and include roles, modules, and plugins.
    • Collections provide a way to organize and distribute Ansible content more flexibly.
    • Collections can be installed from Ansible Galaxy and used in your playbooks.
  3. Ansible Galaxy Command-Line Interface (CLI):
    • The ansible-galaxy command-line tool is used to interact with Ansible Galaxy.
    • It allows you to search, download, and install roles and collections.
  4. Ansible Galaxy Website:
    • The Ansible Galaxy website is the online platform where you can explore and search for roles and collections.
    • Roles and collections on Ansible Galaxy are versioned, making it easy to reference a specific version in your playbooks.

 

The ansible-galaxy init command is used to initialize a new Ansible role with a standardized directory structure, and it does not create an entire Ansible Galaxy. Roles created with ansible-galaxy init can be used within your Ansible projects and can also be shared with others through Ansible Galaxy if you choose to publish them.

 

 

Step 8: LAMP stack

LAMP stack

LAMP is an acronym that stands for Linux, Apache, MySQL, and PHP/Python/Perl. It represents a popular and widely used software stack for building and deploying web applications. Each component in the stack serves a specific role in web application development and hosting:

  1. Linux (Operating System):
    • The “L” in LAMP represents the Linux operating system. Linux is a widely used open-source Unix-like operating system that provides a stable and secure foundation for web applications.
  2. Apache (Web Server):
    • The “A” in LAMP represents the Apache HTTP Server. Apache is a robust and highly configurable open-source web server. It is one of the most widely used web servers globally and plays a crucial role in serving web pages to users.
  3. MySQL (Database):
    • The “M” in LAMP represents MySQL. MySQL is an open-source relational database management system (RDBMS). It is used for storing and managing the application’s data. MySQL is known for its reliability, performance, and ease of use.
  4. PHP/Python/Perl (Programming Language):
    • The “P” in LAMP represents a programming language used to build dynamic web applications. While PHP is the most common choice, alternatives like Python and Perl can also be used. These languages enable developers to embed dynamic content within web pages and interact with databases.

The LAMP stack provides a comprehensive environment for developing and deploying web applications. It has been widely adopted for its flexibility, cost-effectiveness, and the strong community support surrounding each of its components.

In addition to LAMP, variations such as MEAN (MongoDB, Express.js, AngularJS, Node.js) and MERN (MongoDB, Express.js, React, Node.js) have emerged, introducing different technologies to serve similar purposes. Each stack caters to different use cases and preferences.

Create a LAMP stack and deploy a webpage by using Ansible.

Here we will sample a webpage in Ubuntu server

In the ansible control node in the root directory create an index.html file.


cd /etc/ansible

mkdir index

vi /index/index.html

#paste any code, like

Hellow World

 

Create a playbook for LAMP

vi lamp.yml
---
- hosts: worker2
  tasks:
    - name: Add ppa repository
      become: yes
      apt_repository:
        repo: ppa:ondrej/php

    - name: Install lamp stack
      become: yes
      apt:
        pkg:
          - apache2
          - mysql-server
          - php7.0
          - libapache2-mod-php7.0   # Include libapache2-mod-php7.0 for Apache and PHP integration
          - php7.0-mysql
        state: present
        update_cache: yes

    - name: Start apache server
      become: yes
      service:
        name: apache2
        state: started
        enabled: yes

    - name: Start mysql service
      become: yes
      service:
        name: mysql
        state: started
        enabled: yes

    - name: Create target directory
      become: yes
      file:
        path: /var/www/html/index
        state: directory
        mode: 0755

    - name: Deploy index.html
      become: yes
      copy:
        src: /etc/ansible/index/index.html
        dest: /var/www/html/index.html
 Now access the webpage with <ip of ubuntu machine> you should see your webpage

eg: http://ec2-13-233-121-118.ap-south-1.compute.amazonaws.com/index.html

 

 

 

Step 9: Create encrypted files with ansible

 

Encrypted files in Ansible are useful for securing sensitive information such as passwords, private keys, or other confidential data that might be used within playbooks or roles. Ansible provides a way to encrypt files using the ansible-vault command, which allows you to protect sensitive information and store it in a secure manner.

Ansible provides the ansible-vault command for managing encrypted files. You can use ansible-vault to create, view, edit, and encrypt sensitive data such as passwords or secret keys within your Ansible projects.

Here are the basic steps to create an encrypted file using ansible-vault:

1. Create a New Encrypted File

To create a new encrypted file, you can use the following command:

ansible-vault create secret_file.yml

2. Edit an Existing Encrypted File

If you already have an encrypted file and need to edit it, you can use the following command:

ansible-vault edit secret_file.yml

This command decrypts the file, allowing you to edit its content. After saving and closing the editor, Ansible re-encrypts the file.

3. View an Encrypted File

To view the contents of an encrypted file without modifying it, you can use:
ansible-vault view secret_file.yml

4. Encrypt an Unencrypted File

If you have a plain text file and want to encrypt it, you can use:

ansible-vault encrypt plain_text_file.yml

5. Decrypt an Encrypted File

If you need to decrypt an encrypted file for editing or inspection, you can use:

ansible-vault decrypt secret_file.yml

6. Rekey the Vault

To change the password or rekey an existing vault file, you can use:
ansible-vault rekey secret_file.yml

 

Step 10: Setup Ansible AWS Dynamic Inventory

Ansible Dynamic Inventory For AWS or Any Cloud Services.

Using Ansible with AWS, maintaining the inventory file will be a hectic task as AWS has frequently changed IPs, auto-scaling instances, and much more. So having a static inventory will never help us.

There are two types of inventory:

Static Inventory:- The inventory in which we need to put the IP address manually. This will never help us in a complex environment where we have a large amount of systems running and we keep on installing and uninstalling the systems. And the IPs keep on changing.

Dynamic Inventory:- However, there is an easy solution called ansible dynamic inventory. In our case, for AWS, Dynamic Inventory is an ansible plugin that makes an API call to AWS to get the instance information in the run time. It gives you the ec2 instance details dynamically to manage the AWS infrastructure.

 

Step 1: Ensure you have python3 & pip3 installed in your Ansible control node.

Most Linux operating system comes with phyton3. You can validate it using the following command.

python3 --version

If you don’t have python3, you can install it using the following command.

For centos, Redhat

sudo yum -y install python3 
sudo yum –y install python3-pip

For Debian, Ubuntu,

sudo apt-get install python3 -y
sudo apt-get install python3-pip -y

Step 2: Install the boto3 library. Ansible uses the boot core to make API calls to AWS to retrieve ec2 instance details.

sudo pip3 install boto boto3

Step 3: Create a file named aws_ec2.yaml in the inventory directory.

sudo vim aws_ec2.yaml

Copy the following configuration to the file. If you are running an ansible server outside the AWS environment, replace add your AWS access key and secret to the config file.

---
plugin: aws_ec2
aws_access_key: <YOUR-AWS-ACCESS-KEY-HERE>
aws_secret_key: <YOUR-AWS-SECRET-KEY-HERE>
keyed_groups:
  - key: tags
    prefix: tag

If your ansible server is running inside the AWS environment, attach an ec2 instance role with the required AWS ec2 permissions (Mostly describe instances). This way you don’t have to add the access and secret key in the configuration. Ansible will automatically use the attached role to make the AWS API calls.

Step 4: Open /etc/ansible/ansible.cfg file.

sudo vi /etc/ansible/ansible.cfg

Find the [inventory] section or create by yourself and add the following line to enable the ec2 plugin.

enable_plugins = aws_ec2

It should look something like this.

[inventory]
enable_plugins = aws_ec2

If you want to use the dynamic inventory as a default Ansible inventory, edit the /etc/ansible/ansible.cfg file and search for inventory parameters under defaults. Change the inventory parameter value as shown below.

[inventory]
enable_plugins = aws_ec2

[defaults]
inventory      = /etc/ansible/inventory/aws_ec2.yaml
remote_user = ec2-user
private_key_file = /etc/ansible/ssh/my_key
ask_pass = False
deprecation_warnings = False

Make sure you have your private key placed at path provided above if not do that.

Now if you run the inventory list command without passing the inventory file, Ansible looks for the default location and picks up the aws_ec2.yaml inventory file.

Step 5: Now let’s test the dynamic inventory configuration by listing the ec2 instances.

ansible-inventory --list

Step 6: Execute the following command to test if Ansible can ping all the machines returned by the dynamic inventory.

ansible all -m ping

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *