03_01 – Creating and Working with Ansible Roles
Role Directory Structure
# Create role structure
mkdir -p roles/webserver/{defaults,files,handlers,meta,tasks,templates,vars}
Basic Role Components
# filepath: roles/webserver/tasks/main.yml
---
- name: Install required packages
dnf:
name:
- httpd
- php
- php-mysql
state: present
- name: Configure Apache
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: restart apache
- name: Start services
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- httpd
- php-fpm
# filepath: roles/webserver/handlers/main.yml
---
- name: restart apache
service:
name: httpd
state: restarted
- name: reload apache
service:
name: httpd
state: reloaded
# filepath: roles/webserver/defaults/main.yml
---
http_port: 80
doc_root: /var/www/html
max_clients: 150
php_version: "7.4"
# filepath: roles/webserver/meta/main.yml
---
dependencies:
- role: common
vars:
packages:
- epel-release
- firewalld
# filepath: roles/webserver/templates/httpd.conf.j2
ServerRoot "/etc/httpd"
Listen {{ http_port }}
ServerAdmin root@localhost
DocumentRoot "{{ doc_root }}"
MaxClients {{ max_clients }}
Using the Role
# filepath: site.yml
---
- hosts: webservers
roles:
- role: webserver
vars:
http_port: 8080
max_clients: 200
Role Dependencies Example
# filepath: roles/webapp/meta/main.yml
---
dependencies:
- role: webserver
- role: database
vars:
mysql_databases:
- name: webapp_db
encoding: utf8
- role: php
vars:
php_version: "7.4"
Complete Role Example
# filepath: roles/webapp/tasks/main.yml
---
- name: Include OS-specific variables
include_vars: "{{ ansible_os_family }}.yml"
- name: Install dependencies
package:
name: "{{ webapp_packages }}"
state: present
- name: Deploy application files
git:
repo: "{{ webapp_repo }}"
dest: "{{ webapp_root }}"
version: "{{ webapp_version }}"
notify: restart webapp
- name: Configure application
template:
src: config.php.j2
dest: "{{ webapp_root }}/config.php"
notify: restart webapp
- name: Set permissions
file:
path: "{{ webapp_root }}"
owner: "{{ webapp_user }}"
group: "{{ webapp_group }}"
mode: '0755'
recurse: yes
# filepath: roles/webapp/defaults/main.yml
---
webapp_repo: https://github.com/company/webapp.git
webapp_version: main
webapp_root: /var/www/webapp
webapp_user: apache
webapp_group: apache
Remember to test roles in development before deploying to production.
03_02 Installing and Using Ansible Roles
Installing Roles
# filepath: /examples/commands.sh
# Install role from Galaxy
ansible-galaxy install geerlingguy.nginx
# Install specific version
ansible-galaxy install geerlingguy.mysql,2.9.0
# Install multiple roles from requirements file
ansible-galaxy install -r requirements.yml
# filepath: /examples/requirements.yml
---
- src: geerlingguy.nginx
version: 3.1.0
name: nginx
- src: geerlingguy.mysql
version: 3.3.0
- src: https://github.com/company/ansible-role-app.git
scm: git
version: main
name: custom_app
Using Roles in Playbooks
# filepath: /examples/site.yml
---
- hosts: webservers
roles:
- role: nginx
vars:
nginx_port: 8080
- role: mysql
vars:
mysql_databases:
- name: webapp
encoding: utf8
- role: custom_app
Complete Production Example
# filepath: /examples/production.yml
---
- name: Configure Production Environment
hosts: prod_servers
pre_tasks:
- name: Update package cache
dnf:
update_cache: yes
changed_when: false
roles:
- role: common
tags: always
- role: nginx
vars:
nginx_vhosts:
- listen: "80"
server_name: "example.com"
root: "/var/www/example"
tags: webserver
- role: mysql
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
mysql_databases:
- name: production_db
encoding: utf8mb4
collation: utf8mb4_general_ci
tags: database
- role: php
vars:
php_memory_limit: "256M"
php_max_execution_time: 60
tags: php
post_tasks:
- name: Verify services
service:
name: "{{ item }}"
state: started
loop:
- nginx
- mysql
- php-fpm
# filepath: /examples/group_vars/prod_servers/vars.yml
---
nginx_worker_processes: auto
mysql_max_connections: 200
php_version: "7.4"
# filepath: /examples/group_vars/prod_servers/vault.yml
---
vault_mysql_root_password: secure_password_here
Remember to encrypt sensitive variables using ansible-vault.
03_03 Installing and Using Ansible Collections
Installation Commands
# filepath: /examples/collection_commands.sh
# Install single collection
ansible-galaxy collection install community.general
# Install from requirements file
ansible-galaxy collection install -r requirements.yml
# Install specific version
ansible-galaxy collection install community.mysql:2.3.0
Requirements File
# filepath: /examples/requirements.yml
---
collections:
- name: community.general
version: '>=3.0.0'
- name: ansible.posix
version: '>=1.0.0'
- name: community.mysql
version: '>=2.0.0'
Using Collections
# filepath: /examples/playbook.yml
---
- hosts: webservers
collections:
- community.general
- ansible.posix
tasks:
- name: Configure firewall
ansible.posix.firewalld:
service: http
permanent: yes
state: enabled
- name: Install package
community.general.pacman:
name: nginx
state: present
Complete Production Example
# filepath: /examples/production_stack.yml
---
- name: Deploy Production Stack
hosts: production
collections:
- community.general
- community.mysql
- ansible.posix
tasks:
- name: Configure MySQL
community.mysql.mysql_db:
name: production_db
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: Setup user
community.mysql.mysql_user:
name: webapp
password: "{{ mysql_password }}"
priv: 'production_db.*:ALL'
state: present
- name: Configure SELinux
ansible.posix.seboolean:
name: httpd_can_network_connect_db
state: yes
persistent: yes
- name: Setup firewall
ansible.posix.firewalld:
port: 3306/tcp
permanent: yes
state: enabled
Using Multiple Collections
# filepath: /examples/multi_collection.yml
---
- name: System Configuration
hosts: all
collections:
- ansible.posix
- community.general
- community.docker
tasks:
- name: Install Docker
community.general.dnf:
name: docker-ce
state: present
- name: Start Docker
ansible.builtin.service:
name: docker
state: started
enabled: yes
- name: Deploy container
community.docker.docker_container:
name: webapp
image: nginx:latest
ports:
- "80:80"
Remember to verify collection compatibility with your Ansible version.
03_04 Using Related Roles and Collections
Requirements Setup
# filepath: requirements.yml
---
collections:
- name: redhat.rhel_system_roles
version: '>=1.0.0'
- name: ansible.posix
version: '>=1.0.0'
roles:
- name: geerlingguy.mysql
version: '3.3.0'
- name: geerlingguy.apache
version: '3.1.0'
Installation Commands
# filepath: install_commands.sh
# Install collections and roles
ansible-galaxy collection install -r requirements.yml
ansible-galaxy role install -r requirements.yml
Complete Production Example
# filepath: site.yml
---
- name: Configure Production Environment
hosts: production_servers
collections:
- redhat.rhel_system_roles
- ansible.posix
pre_tasks:
- name: Check requirements
ansible.builtin.assert:
that:
- ansible_distribution == "RedHat"
- ansible_distribution_major_version == "8"
roles:
- role: redhat.rhel_system_roles.storage
vars:
storage_pools:
- name: data
disks:
- /dev/sdb
volumes:
- name: mysql
size: 10g
fs_type: xfs
mount_point: /var/lib/mysql
- role: geerlingguy.mysql
vars:
mysql_databases:
- name: webapp
encoding: utf8mb4
collation: utf8mb4_general_ci
mysql_users:
- name: webapp_user
password: "{{ vault_mysql_password }}"
priv: "webapp.*:ALL"
- role: redhat.rhel_system_roles.network
vars:
network_connections:
- name: eth0
type: ethernet
ip:
address:
- 192.168.1.100/24
- role: geerlingguy.apache
vars:
apache_vhosts:
- servername: "example.com"
documentroot: "/var/www/html"
tasks:
- name: Configure SELinux
ansible.posix.seboolean:
name: httpd_can_network_connect_db
state: yes
persistent: yes
- name: Configure Firewall
ansible.posix.firewalld:
service: "{{ item }}"
permanent: yes
state: enabled
loop:
- http
- https
- mysqlDiscover more from Altgr Blog
Subscribe to get the latest posts sent to your email.
