Skip to content
All essays
ArchitectureJanuary 20, 202416 min

Ansible Basics: Automation and Configuration Management

Learn Ansible fundamentals from scratch. Understand automation concepts, inventory management, ad-hoc commands, and core features for configuration management.

Ü
Ümit Uz
Mobile & Full Stack Developer

Introduction to Ansible

Ansible is an open-source automation tool that simplifies configuration management, application deployment, and task automation. Unlike other configuration management tools, Ansible uses a simple, agentless architecture powered by SSH.

What is Ansible?

Ansible is:

  • Configuration Management: Maintain consistent system configurations
  • Application Deployment: Automate application deployments
  • Orchestration: Coordinate multi-machine deployments
  • Provisioning: Set up infrastructure and services

Why Ansible?

Key Benefits:

  • Agentless: No agents to install on managed nodes
  • Simple: Uses YAML for configuration
  • Powerful: Complex automation with minimal code
  • Reliable: Idempotent operations ensure consistency
  • Fast: Parallel execution across multiple hosts

Installing Ansible

Installation Methods

1. pip (Python Package Manager):

bash
pip install ansible

2. Package Managers:

macOS:

bash
brew install ansible

Ubuntu/Debian:

bash
sudo apt update
sudo apt install ansible

RHEL/CentOS:

bash
sudo yum install ansible

3. pipx (Recommended for development):

bash
pipx install ansible

Verifying Installation

bash
ansible --version
ansible 2.15.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/user/.ansible/collections

Ansible Architecture

Control Node vs Managed Nodes

Control Node:

  • Runs Ansible
  • Manages configuration
  • Executes playbooks

Managed Nodes:

  • Systems being configured
  • Only require Python and SSH
  • No agent installation needed

Architecture Diagram

┌──────────────┐         SSH          ┌──────────────┐
│ Control Node │ ─────────────────────▶│ Managed Node │
│              │    SSH Keys/Password  │              │
│ - Ansible    │                       │ - Python     │
│ - Playbooks  │                       │ - Services   │
│ - Modules    │◀───────────────────── │              │
└──────────────┘    Connection         └──────────────┘
                       Established

Inventory

What is Inventory?

Inventory defines the hosts that Ansible manages. It's a list of target systems grouped logically.

INI Format Inventory

ini
# inventory.ini

[webservers]
web1.example.com
web2.example.com
web3.example.com

[dbservers]
db1.example.com
db2.example.com

[production]
web1.example.com
db1.example.com

[staging]
web2.example.com
db2.example.com

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_rsa

YAML Format Inventory

yaml
# inventory.yaml

all:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
        web3.example.com:
    dbservers:
      hosts:
        db1.example.com:
        db2.example.com:
    production:
      children:
        webservers:
        dbservers:
  vars:
    ansible_user: ubuntu
    ansible_ssh_private_key_file: ~/.ssh/id_rsa

Dynamic Inventory

bash
# AWS EC2 dynamic inventory
ansible-inventory -i ec2.yaml --list

# Kubernetes dynamic inventory
ansible-inventory -i kubernetes.yaml --list

Ad-Hoc Commands

Basic Syntax

bash
ansible [pattern] -m [module] -a "[module arguments]"

Common Ad-Hoc Commands

1. Ping Check:

bash
ansible all -m ping

2. Check Uptime:

bash
ansible webservers -m command -a "uptime"

3. Install Package:

bash
ansible webservers -m apt -a "name=nginx state=present" -b

4. Start Service:

bash
ansible webservers -m service -a "name=nginx state=started" -b

5. Copy Files:

bash
ansible webservers -m copy -a "src=./index.html dest=/var/www/html/" -b

6. Gather Facts:

bash
ansible all -m setup
ansible webservers -m setup -a "filter=ansible_distribution*"

Useful Modules

Command Modules:

  • command: Execute commands (default)
  • shell: Execute shell commands with pipes/redirection
  • raw: Execute via SSH without Python

File Modules:

  • copy: Copy files to hosts
  • file: Set file attributes
  • fetch: Copy files from hosts
  • template: Deploy template files

Package Modules:

  • apt: Debian/Ubuntu packages
  • yum: RHEL/CentOS packages
  • dnf: Fedora packages
  • pip: Python packages

Service Modules:

  • service: Manage services
  • systemd: Manage systemd services

Modules

Understanding Modules

Modules are the building blocks of Ansible. Each module performs a specific task.

Using Modules

1. Command Module:

bash
ansible webservers -m command -a "ls -l /var/www"

2. Shell Module:

bash
ansible all -m shell -a "echo $HOME >> /tmp/test.txt"

3. Copy Module:

bash
ansible webservers -m copy -a \
  "src=/etc/hosts dest=/tmp/hosts backup=yes"

4. Template Module:

bash
ansible webservers -m template -a \
  "src=index.j2 dest=/var/www/html/index.html"

5. File Module:

bash
ansible all -m file -a \
  "path=/tmp/myfile state=touch mode=0600"

6. Service Module:

bash
ansible webservers -m service -a \
  "name=nginx state=started enabled=yes"

7. Apt Module:

bash
ansible webservers -m apt -a \
  "name=nginx state=present update_cache=yes"

8. User Module:

bash
ansible all -m user -a \
  "name=john state=present shell=/bin/bash groups=sudo"

9. Git Module:

bash
ansible webservers -m git -a \
  "repo=https://github.com/user/repo.git dest=/var/www/myapp version=main"

10. Cron Module:

bash
ansible all -m cron -a \
  "name='daily backup' job='/backup.sh' hour=2 minute=0"

Configuration

ansible.cfg

ini
# ansible.cfg

[defaults]
# Inventory location
inventory = ./inventory

# Remote user
remote_user = ubuntu

# Private key file
private_key_file = ~/.ssh/id_rsa

# Host key checking
host_key_checking = False

# Timeout
timeout = 30

# Number of parallel processes
forks = 5

# Display task timing
callback_whitelist = timer, profile_tasks

# Gather facts
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/facts_cache
fact_caching_timeout = 86400

# Disable retry files
retry_files_enabled = False

# Log path
log_path = ./ansible.log

[inventory]
# Enable inventory plugins
enable_plugins = host_list, script, auto, yaml, ini, toml

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

[ssh_connection]
# SSH connection settings
pipelining = True
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

Environment Variables

bash
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_INVENTORY=./inventory
export ANSIBLE_REMOTE_USER=ubuntu
export ANSIBLE_PRIVATE_KEY_FILE=~/.ssh/id_rsa

SSH Setup

SSH Key Authentication

1. Generate SSH Key:

bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

2. Copy Public Key to Managed Nodes:

bash
ssh-copy-id ubuntu@web1.example.com
ssh-copy-id ubuntu@web2.example.com

3. Test Connection:

bash
ssh ubuntu@web1.example.com

SSH Agent

bash
# Start SSH agent
eval "$(ssh-agent -s)"

# Add key to agent
ssh-add ~/.ssh/id_rsa

# Test with Ansible
ansible all -m ping

SSH Config

# ~/.ssh/config

Host *.example.com
  User ubuntu
  IdentityFile ~/.ssh/id_rsa
  StrictHostKeyChecking no
  UserKnownHostsFile=/dev/null

Facts Gathering

What are Facts?

Facts are system information collected by Ansible from managed nodes.

Disabling Facts

yaml
---
- name: Play without facts
  hosts: webservers
  gather_facts: no
  tasks:
    - name: Task without facts
      debug:
        msg: "Facts gathering disabled"

Gathering Specific Facts

yaml
---
- name: Play with specific facts
  hosts: webservers
  gather_facts: yes

  vars:
    ansible_facts_modules:
      - setup
      - ansible.builtin.setup

  tasks:
    - name: Use gathered facts
      debug:
        msg: "OS: {{ ansible_distribution }}"

Fact Caching

ini
# ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/facts_cache
fact_caching_timeout = 86400

Idempotency

Understanding Idempotency

Idempotency ensures that running the same task multiple times produces the same result without side effects.

Idempotent Example

yaml
- name: Ensure nginx is installed
  apt:
    name: nginx
    state: present
  become: yes

This task:

  • Installs nginx if not present
  • Does nothing if already installed
  • Never attempts to reinstall

Non-Idempotent Commands

Avoid:

yaml
- name: Bad example
  command: apt-get install nginx

Prefer:

yaml
- name: Good example
  apt:
    name: nginx
    state: present

Best Practices

1. Use Version Control

bash
git init
git add .
git commit -m "Initial Ansible setup"

2. Organize Playbooks

project/
├── inventory/
│   ├── production
│   └── staging
├── playbooks/
│   ├── web.yml
│   └── db.yml
├── roles/
│   ├── web/
│   └── db/
├── files/
├── templates/
└── ansible.cfg

3. Use Inventory Groups

ini
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com
db2.example.com

[production:children]
webservers
dbservers

4. Enable Verbosity for Debugging

bash
ansible-playbook playbook.yml -v      # Verbose
ansible-playbook playbook.yml -vv     # More verbose
ansible-playbook playbook.yml -vvv    # Debug

5. Use Check Mode

bash
ansible-playbook playbook.yml --check

6. Run on Specific Hosts

bash
ansible-playbook playbook.yml -l webservers
ansible-playbook playbook.yml -l web1.example.com

7. Use Tags

bash
ansible-playbook playbook.yml --tags "nginx,mysql"
ansible-playbook playbook.yml --skip-tags "debug"

8. Enable Diff Output

bash
ansible-playbook playbook.yml --diff

Common Tasks

System Updates

yaml
---
- name: Update all packages
  hosts: all
  become: yes
  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Upgrade all packages
      apt:
        upgrade: dist

User Management

yaml
---
- name: Manage users
  hosts: all
  become: yes
  tasks:
    - name: Create user
      user:
        name: deploy
        shell: /bin/bash
        groups: sudo,docker
        append: yes

    - name: Add SSH key
      authorized_key:
        user: deploy
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

File Management

yaml
---
- name: Manage files
  hosts: all
  become: yes
  tasks:
    - name: Create directory
      file:
        path: /opt/myapp
        state: directory
        mode: '0755'

    - name: Copy configuration
      copy:
        src: config.ini
        dest: /opt/myapp/config.ini
        mode: '0644'

    - name: Create symlink
      file:
        src: /opt/myapp/config.ini
        dest: /etc/myapp.conf
        state: link

Troubleshooting

Common Issues

1. Connection Issues:

bash
# Check SSH connection
ssh ubuntu@web1.example.com

# Verbose output
ansible webservers -m ping -vvv

2. Permission Issues:

bash
# Use become for privilege escalation
ansible-playbook playbook.yml -b

# Specify sudo user
ansible-playbook playbook.yml -b --become-user=root

3. Python Issues:

bash
# Specify Python interpreter
ansible-playbook playbook.yml -e "ansible_python_interpreter=/usr/bin/python3"

Debug Mode

yaml
- name: Debug task
  debug:
    msg: "Variable value: {{ my_variable }}"
    verbosity: 1

Next Steps

Now that you understand Ansible basics, explore:

  • Playbooks for complex automation
  • Roles for reusability
  • Ansible Galaxy for sharing
  • Ansible Vault for secrets
  • Advanced patterns and best practices

Ansible basics provide the foundation for automating your infrastructure efficiently and reliably.

Enjoyed this essay? Share it.

Related essays

Next essay
Terraform Providers: Understanding and Using Providers