Getting Started with Ansible: Your First Automated Deployment

If you’ve ever found yourself manually configuring servers, installing packages, or deploying applications across multiple machines, you know how tedious and error-prone this process can be. Enter Ansible – a powerful automation tool that can transform your infrastructure management from a manual chore into an elegant, repeatable process.

What is Ansible?

Ansible is an open-source automation platform that simplifies complex tasks such as configuration management, application deployment, and orchestration. Unlike other automation tools, Ansible is agentless, which means you don’t need to install any software on the machines you want to manage. Furthermore, it uses SSH for Linux/Unix systems and WinRM for Windows, making it lightweight and easy to adopt. As a result, teams can implement automation quickly and efficiently.

Why Choose Ansible?

Simple and Human-Readable: Ansible uses YAML syntax, which reads almost like plain English. No complex programming knowledge required.

Agentless Architecture: No need to install agents on target machines – just SSH access is enough.

Idempotent Operations: Run the same playbook multiple times safely. Ansible only makes changes when necessary.

Extensive Module Library: Over 3,000+ modules covering everything from cloud providers to network devices.

Installing Ansible

Let’s get Ansible installed on your control machine (the computer you’ll run Ansible from).

On Ubuntu/Debian:

sudo apt update
sudo apt install ansible

CentOS/RHEL:

sudo yum install epel-release
sudo yum install ansible

macOS:

brew install ansible

Using pip (any OS):

pip install ansible

Verify your installation:

ansible --version

Key Concepts

Before diving into our first deployment, let’s understand some core concepts:

Inventory: A file that defines the hosts and groups of hosts you want to manage.

Playbooks: YAML files containing a series of tasks to execute on your hosts.

Tasks: Individual actions like installing packages, copying files, or starting services.

Modules: Pre-built code that performs specific tasks (like apt package management or copy file operations).

Roles: Reusable collections of tasks, files, templates, and variables.

Setting Up Your First Project

Let’s create a simple project structure:

mkdir ansible-tutorial
cd ansible-tutorial
mkdir -p group_vars host_vars roles
touch inventory.ini ansible.cfg site.yml

Your directory should look like this:

ansible-tutorial/
├── ansible.cfg
├── group_vars/
├── host_vars/
├── inventory.ini
├── roles/
└── site.yml

Creating Your Inventory

The inventory file tells Ansible which servers to manage. Create a simple inventory.ini:

[webservers]
web1 ansible_host=192.168.1.100 ansible_user=ubuntu
web2 ansible_host=192.168.1.101 ansible_user=ubuntu

#webservers databases
[databases]
db1 ansible_host=192.168.1.200 ansible_user=ubuntu
[production:children]

This inventory defines:

  • Two web servers in the webservers group
  • One database server in the databases group
  • A parent group production containing both groups

Your First Playbook

Now let’s create a playbook to deploy a simple web application. Edit site.yml:

---
- name: Deploy Simple Web Application
  hosts: webservers
  become: yes
  vars:
    app_name: "my-web-app"
    app_port: 8080
    
  tasks:
    - name: Update package cache
      apt:
        update_cache: yes
        cache_valid_time: 3600
        
    - name: Install required packages
      apt:
        name:
          - nginx
          - python3
          - python3-pip
          - git
        state: present
        
    - name: Create application directory
      file:
        path: "/opt/{{ app_name }}"
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'
        
    - name: Clone application repository
      git:
        repo: "https://github.com/your-username/simple-flask-app.git"
        dest: "/opt/{{ app_name }}"
        version: main
      notify: restart application
      
    - name: Install Python dependencies
      pip:
        requirements: "/opt/{{ app_name }}/requirements.txt"
        executable: pip3
        
    - name: Create systemd service file
      template:
        src: app.service.j2
        dest: "/etc/systemd/system/{{ app_name }}.service"
      notify: restart application
      
    - name: Configure Nginx
      template:
        src: nginx.conf.j2
        dest: "/etc/nginx/sites-available/{{ app_name }}"
      notify: restart nginx
      
    - name: Enable Nginx site
      file:
        src: "/etc/nginx/sites-available/{{ app_name }}"
        dest: "/etc/nginx/sites-enabled/{{ app_name }}"
        state: link
      notify: restart nginx
      
    - name: Start and enable services
      systemd:
        name: "{{ item }}"
        state: started
        enabled: yes
        daemon_reload: yes
      loop:
        - "{{ app_name }}"
        - nginx
        
  handlers:
    - name: restart application
      systemd:
        name: "{{ app_name }}"
        state: restarted
        
    - name: restart nginx
      systemd:
        name: nginx
        state: restarted

Creating Templates

Ansible uses Jinja2 templates to create dynamic configuration files. Create a templates directory and add these files:

templates/app.service.j2

[Unit]
Description={{ app_name }} Web Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/{{ app_name }}
ExecStart=/usr/bin/python3 app.py
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

templates/nginx.conf.j2

server {
    listen 80;
    server_name {{ ansible_host }};
    
    location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Configuration File

Create an ansible.cfg file to set some defaults:

[defaults]
inventory = inventory.ini
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml


[ssh_connection]
pipelining = True

Running Your First Deployment

Before running the full playbook, test connectivity to your hosts:

ansible all -m ping

If that works, you can run your playbook:

ansible-playbook site.yml

For a dry run to see what would change without actually making changes:

ansible-playbook site.yml --check

To run only specific tasks with tags:

ansible-playbook site.yml --tags "packages"

Advanced Tips

Using Vault for Secrets

Never store passwords or API keys in plain text. Use Ansible Vault:

ansible-vault create group_vars/all/vault.yml

Organizing with Roles

For larger projects, organize your tasks into roles:

ansible-galaxy init roles/webserver

This creates a structured role directory with tasks, handlers, templates, and variables.

Testing Your Playbooks

Consider using tools like Molecule to test your playbooks:

pip install molecule[docker]
molecule init scenario --driver-name docker

Troubleshooting Common Issues

SSH Connection Issues: Ensure SSH keys are set up or use --ask-pass the flag.

Permission Denied: Use --ask-become-pass for sudo password or configure passwordless sudo.

Module Not Found: Check if the required Python modules are installed on target hosts.

Idempotency Issues: Always use appropriate modules and parameters to ensure tasks are idempotent.

Next Steps

Now that you’ve completed your first automated deployment, consider exploring:

  • Dynamic Inventories: Pull inventory from cloud providers
  • Ansible Galaxy: Use community roles and collections
  • AWX/Tower: Web-based UI for Ansible automation
  • Integration: Connect Ansible with CI/CD pipelines
  • Custom Modules: Write your own modules for specific needs

Conclusion

Ansible transforms infrastructure management from a manual, error-prone process into reliable, repeatable automation. With just YAML and SSH, you can manage everything from a single server to thousands of machines across multiple cloud providers.

Start small, automate one task at a time, and gradually build more complex playbooks. Before you know it, you’ll wonder how you ever managed infrastructure without Ansible.

Leave a Comment

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

Scroll to Top