Ansible III (Running playbooks)
I started a series discussing the major things you need to know about Ansible, you can check this for the first and this for the second. In this series, I will explain how to create and run playbooks.
Create and run playbooks
Creating, organizing, and running Ansible playbooks involves defining the automation tasks, structuring the playbook in YAML format, and executing it to automate actions on target hosts. Here’s how to do it:
1. Creating Playbooks:
- Create a new file with a
.yml
extension to serve as your playbook, e.g.,my_playbook.yml
. - Define the playbook structure:
- Begin with
---
to indicate the start of a YAML document. - Specify the playbook name using the
name
field. - Define the target hosts using the
hosts
field. - List the tasks to be executed within the
tasks
section.
Here’s an example of a simple playbook:
---
- name: My First Playbook
hosts: web
tasks:
- name: Ensure Nginx is installed
apt:
name: nginx
state: present
- name: Start Nginx service
service:
name: nginx
state: started
2. Running Playbooks: Execute a playbook using the ansible-playbook
command followed by the playbook filename.
ansible-playbook my_playbook.yml
- You can specify extra variables with
-e
and limit playbooks to specific hosts or groups with-l
. - To check a playbook without making changes, use the
--check
option:
ansible-playbook --check my_playbook.yml
- To view the changes that would be made, use the
--diff
option:
ansible-playbook --diff my_playbook.yml
Ansible will execute the tasks defined in the playbook against the specified target hosts, applying the desired configurations and changes.
Using Ansible modules for various task
Ansible provides a wide range of modules for various tasks, such as package management, file operations, services, and user management. I will explain them below.
- Package Management (apt/yum): We can use Ansible to install or update a package using the
apt
module (Debian/Ubuntu) oryum
module (RHEL/CentOS). See the usage below.
---
- name: Install Apache on Ubuntu
hosts: webserver
tasks:
- name: Install Apache
apt:
name: apache2
state: present
We can also equally remove package managers. We use the example below to explain that.
---
- name: Remove Apache on CentOS
hosts: webserver
tasks:
- name: Remove Apache
yum:
name: httpd
state: absent
2. File Operations (copy/template): Another operation we can perform with Ansible is the copying of files from one environment to another, we show the usage below.
---
- name: Copy Config File
hosts: webserver
tasks:
- name: Copy nginx.conf
copy:
src: /path/to/local/nginx.conf
dest: /etc/nginx/nginx.conf
In the example above, we copied a file from the control machine to remote hosts using the copy
module. We can also use the template module to copy a template file and replace variables. See its usage below.
---
- name: Copy Template
hosts: webserver
tasks:
- name: Deploy Apache Virtual Host
template:
src: templates/vhost.conf.j2
dest: /etc/apache2/sites-available/mywebsite.conf
3. Services Management (service/systemd): We can also use Ansible modules to start or restart a service using the service
module (for SysVinit) or systemd
module (for systemd-based systems). See its usage below.
---
- name: Start Apache Service
hosts: webserver
tasks:
- name: Start Apache
service:
name: apache2
state: started
4. User Management (user/group): Ansible modules can be used to create a user or group. See usage below.
- To create a user;
---
- name: Create User
hosts: webserver
tasks:
- name: Create a new user
user:
name: alex
state: present
- To create a group;
---
- name: Add User to Group
hosts: webserver
tasks:
- name: Add user to 'developers' group
user:
name: alex
groups: developers
append: yes
These are just a few examples of the many Ansible modules available for various tasks. Ansible modules are versatile and can be combined in playbooks to automate complex workflows.
Installing & starting Nginx and Docker using Ansible
Below is a comprehensive Ansible playbook that installs Nginx, Docker, and starts both services. I’ll explain each component of the playbook afterward:
---
- name: Install Nginx and Docker
hosts: webserver
become: yes
vars:
packages_to_install:
- nginx
- docker.io
tasks:
- name: Update APT package cache
apt:
update_cache: yes
when: ansible_os_family == 'Debian'
- name: Update YUM package cache
yum:
name: "*"
state: latest
when: ansible_os_family == 'RedHat'
- name: Install required packages
package:
name: "{{ item }}"
state: present
loop: "{{ packages_to_install }}"
- name: Start and enable Nginx service
service:
name: nginx
state: started
enabled: yes
- name: Start and enable Docker service
service:
name: docker
state: started
enabled: yes
Explanation of the Playbook:
name: Install Nginx and Docker
: This is a description of the playbook.hosts: webserver
: It specifies the target hosts or group (make sure to definewebserver
in your inventory).become: yes
: This instructs Ansible to become a superuser (usually by usingsudo
) to execute tasks that require elevated privileges.vars:
: Here, we define a variable calledpackages_to_install
, which is a list of packages to install.
tasks:
: This is where you define the tasks to be executed.
- The first task updates the package cache using the
apt
module for Debian-based systems or theyum
module for RedHat-based systems. It uses conditional execution based on the OS family. - The second task installs the required packages listed in the
packages_to_install
variable using thepackage
module. - The next two tasks start and enable the Nginx and Docker services using the
service
module, ensuring that both services are running and configured to start at boot.
To run the playbook, use the ansible command below.
ansible-playbook playbook.yml
Replace playbook.yml
with your file name.
Using dependencies like handlers
and notify
In complex infrastructure setups, you may need to enforce certain conditions where one component must be installed or running before another. To achieve this, Ansible allows you to define dependencies and conditions using handlers
and notify
. Here's a playbook that installs Nginx and Docker while ensuring that Nginx is installed and running before Docker.
---
- name: Install Nginx and Docker with Dependencies
hosts: webserver
become: yes
vars:
packages_to_install:
- nginx
- docker.io
tasks:
- name: Update APT package cache
apt:
update_cache: yes
when: ansible_os_family == 'Debian'
- name: Update YUM package cache
yum:
name: "*"
state: latest
when: ansible_os_family == 'RedHat'
- name: Install Nginx
package:
name: nginx
state: present
- name: Ensure Nginx service is started and enabled
service:
name: nginx
state: started
enabled: yes
notify: Start Docker
- name: Install Docker
package:
name: docker.io
state: present
when: docker_status.stat.exists is not defined or docker_status.stat.exists == false
notify: Start Docker
handlers:
- name: Start Docker
service:
name: docker
state: started
enabled: yes
Explanation of the Playbook:
- This playbook installs Nginx and Docker on a target host.
- It first updates the package cache using the appropriate module for the OS family (Debian or RedHat).
- It installs Nginx, ensuring that it is present on the system.
- It checks if the Nginx service is already started and enabled. If not, it notifies the
Start Docker
handler to ensure Docker is only started once Nginx is running. - It then installs Docker but only if Docker is not already installed (checked using a condition in the
when
statement). It also notifies theStart Docker
handler to ensure Docker is started after installation. - Finally, there’s a
handlers
section that defines theStart Docker
handler. This handler will start and enable the Docker service when notified.
By using handlers and notify
, you can define and enforce dependencies and conditions between tasks in your Ansible playbooks, ensuring that tasks are executed in the correct order.
Summarizing
In summary, we have looked at creating and running playbooks, using Ansible modules for various tasks, and using Ansible to install Nginx and Docker even with dependencies.