Ansible Run a Specifc Task Again
tutorial series
How To Write Ansible Playbooks
Introduction
Ansible is a modern configuration management tool that doesn't crave the employ of an agent software on remote nodes. Instead, information technology uses only SSH and Python to communicate and execute commands on managed servers.
Ansible allows users to manage servers in two different means: via ad hoc commands, and via playbooks. Playbooks are YAML files containing a list of ordered tasks that should exist executed on a remote server to consummate a task or reach a certain goal, such as to set a LEMP surroundings. Ansible playbooks allow y'all to fully automate server setup and application deployment, using an attainable syntax and an extensive library of built-in resources.
This series will walk y'all through some of Ansible's main features which you tin utilize to write playbooks for server automation. At the terminate, you'll create a playbook to automate setting up a remote Nginx web server and deploy a static HTML website to it. The playbook examples used in this serial tin be found in our ansible-practice repository at the DigitalOcean Community organization on GitHub.
Prerequisites
In order to follow along with the applied examples in this series, y'all'll demand:
- One Ansible Control Node: The Ansible control node is the car we'll use to connect to and control the Ansible hosts over SSH. Your Ansible control node can either be your local machine or a server dedicated to running Ansible, though this serial assumes your control node is an Ubuntu twenty.04 system. Make sure the control node has a non-root user with sudo privileges. To set this upwards, you can follow Steps two and 3 of our Initial Server Setup Guide for Ubuntu 20.04. Withal, please note that if you lot're using a remote server every bit your Ansible Control node, you should follow every footstep of this guide. Doing so will configure a firewall on the server with
ufw
and enable external access to your non-root user profile, both of which volition assist keep the remote server secure. - An SSH keypair associated with your control node's not-root user. To set this up, you tin follow Step 1 of our guide on How to Fix SSH Keys on Ubuntu 20.04.
- One or more than Ansible Hosts: An Ansible host is any machine that your Ansible control node is configured to automate. This guide assumes your Ansible hosts are remote Ubuntu 20.04 servers. Make sure each Ansible host has the Ansible control node's SSH public central added to the
authorized_keys
of a organization user. This user can be either root or a regular user withsudo
privileges. To set this upwardly, y'all tin follow Step 2 of How to Gear up SSH Keys on Ubuntu twenty.04. - Ansible installed and configured on your control node. To gear up upwards Ansible, please follow our guide on How to Install and Configure Ansible on Ubuntu twenty.04.
- A working Ansible inventory file. This inventory file should exist ready on your control node and should incorporate all of your Ansible hosts. The guide How To Set Upwards Ansible Inventories explains in item how you can create an Ansible inventory file.
One time you have met these prerequisites, run a connection examination as outlined in our guide on How To Manage Multiple Servers with Ansible Advertising Hoc Commands to make sure y'all're able to connect and execute Ansible instructions on your remote nodes.
Published on April xv, 2021 · Updated on April 14, 2021
Playbooks use the YAML format to ascertain 1 or more than plays. A play is a ready of ordered tasks that are arranged in a style to automate a process, such as setting up a web server or deploying an application to product.
In a playbook file, plays are divers as a YAML listing. A typical play starts off past determining which hosts are the target of that item setup. This is washed with the hosts
directive.
Setting the hosts
directive to all
is a mutual selection because you can limit the targets of a play at execution fourth dimension by running the ansible-playbook
control with the -l
parameter. That allows you to run the aforementioned playbook on unlike servers or groups without the need to change the playbook file every fourth dimension.
Beginning past creating a new directory on your home binder where you can save your practice playbooks. Kickoff, make certain you're in your Ubuntu user's dwelling house directory. From there, create a directory named ansible-do
and and then navigate into that directory with the cd
control:
- cd ~
- mkdir ansible-practice
- cd ansible-practice
If you followed all prerequisites, you should already have a working inventory file. Yous tin re-create that file into your new ansible-do
directory at present. For instance, if you created your test inventory file in an ansible
directory in your home folder, you could copy the file to the new directory with:
- cp ~/ansible/inventory ~/ansible-exercise/inventory
Next, create a new playbook file:
- nano playbook-01.yml
The post-obit playbook defines a play targeting all
hosts from a given inventory. It contains a unmarried task to print a debug message.
Annotation: We'll larn more almost tasks in the adjacent department of this serial.
Add the following content to your playbook-01.yml
file:
~/ansible-exercise/playbook-01.yml
--- - hosts : all tasks : - name : Print message debug : msg : Hello Ansible World
Salve and close the file when you're done. If y'all're using nano
, you lot can practice that by typing CTRL+X
, and then Y
and ENTER
to confirm.
To endeavor this playbook on the server(south) that you ready in your inventory file, run ansible-playbook
with the aforementioned connection arguments you used when running a connection examination inside the introduction of this serial. Here, we'll be using an inventory file named inventory
and the sammy user to connect to the remote server, only be sure to change these details to align with your own inventory file and administrative user:
- ansible-playbook -i inventory playbook-01.yml -u sammy
You'll see output like this:
Output
PLAY [all] *********************************************************************************** Job [Gathering Facts] *********************************************************************** ok: [203.0.113.10] Job [Update apt cache] ********************************************************************** ok: [203.0.113.x] => { "msg": "Hello Ansible World" } PLAY Epitomize *********************************************************************************** 203.0.113.10 : ok=two changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You lot might accept noticed that even though you have defined but one task inside your playbook, two tasks were listed in the play output. At the kickoff of each play, Ansible executes by default an additional task that gathers information — referred to as facts — about the remote nodes. Because facts can exist used on playbooks to amend customize the behavior of tasks, the fact-gathering task must happen earlier any other tasks are executed.
We'll larn more nigh Ansible facts in a afterward section of this series.
Published on April fifteen, 2021 · Updated on April 14, 2021
A job is the smallest unit of activity you can automate using an Ansible playbook. Playbooks typically comprise a series of tasks that serve a goal, such as to set up a web server, or to deploy an application to remote environments.
Ansible executes tasks in the same guild they are defined inside a playbook. Earlier automating a process such every bit setting up a LEMP server, you'll need to assess which manual steps are necessary and the social club in which they must be completed to get everything done. Then, you'll be able to decide which tasks you'll need and which modules you can employ to reach your goals in less steps.
Modules offer shortcuts to execute operations that you would otherwise have to run as raw bash commands. These are also often used to abstract commands across unlike operating systems.
When you created your get-go playbook in a previous part of this guide, you defined a single task that outputs a message using debug
. Allow's have a look at that playbook once over again. You can apply the true cat
command to print the contents of that file for exam:
- cat ~/ansible-practice/playbook-01.yml
This playbook contains a single job that prints a bulletin in the output of a play:
~/ansible-practice/playbook-01.yml
--- - hosts : all tasks : - name : Print bulletin debug : msg : Hi Ansible Globe
Tasks are divers as a list under the proper noun tasks
inside a play, at the aforementioned level as the hosts
directive that defines the targets for that play. The proper noun
property defines the output that will be printed out when that task is about to exist executed.
The example task invokes the debug
module, which allows yous to display letters in a play. These letters tin can be used to evidence debug data such as the contents of a variable or the output bulletin returned by a command, for instance.
Each module has its ain set of options and properties. The debug
module expects a property named msg
containing the message to be printed out. Pay special attending to the indentation (ii spaces), since msg
must exist a holding inside debug
.
Published on April 15, 2021 · Updated on April 14, 2021
Ansible supports the use of variables to better customize the execution of tasks and playbooks. This way, information technology'south possible to utilise the same playbook with different targets and environments.
Variables can come from unlike sources, such every bit the playbook file itself or external variable files that are imported in the playbook. Special precedence rules will apply when working with multiple variable sources that define a variable with the same name.
To see how variables piece of work in practice, nosotros'll create a new exam playbook that will print the value of two variables, username
and home_dir
. Create a new file called playbook-02.yml
in your ansible-practice
directory:
- nano ~/ansible-practice/playbook-02.yml
Then add together the following lines to the new playbook file:
~/ansible-practice/playbook-02.yml
--- - hosts : all vars : - username : sammy - domicile : /home/sammy tasks : - name : print variables debug : msg : "Username: {{ username }}, Dwelling dir: {{ dwelling }}"
Save and shut the file when you're done editing.
The vars
section of the playbook defines a listing of variables that will exist injected in the telescopic of that play. All tasks, every bit well as any file or template that might exist included in the playbook, will accept access to these variables.
To try this playbook on servers from your inventory file, run ansible-playbook
with the same connectedness arguments yous've used before when running our first example. Again, we'll be using an inventory file named inventory
and the sammy user to connect to the remote servers:
- ansible-playbook -i inventory playbook-02.yml -u sammy
You'll run into output like this:
Output
PLAY [all] *********************************************************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************************************** ok: [203.0.113.10] Job [print variables] *********************************************************************************************************************************************************************** ok: [203.0.113.ten] => { "msg": "Username: sammy, Home dir: /home/sammy" } PLAY RECAP *********************************************************************************************************************************************************************************** 203.0.113.10 : ok=two inverse=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The print variables
task will apply the debug
module to impress the values of the 2 variables we defined in the vars
section of the playbook.
Published on April xv, 2021 · Updated on April 14, 2021
By default, before executing the gear up of tasks defined in a playbook, Ansible will take a few moments to assemble information about the systems that are beingness provisioned. This data, referred to as facts, contain details such as network interfaces and addresses, the operating system running on remote nodes, and available memory, among other things.
Ansible stores facts in JSON format, with items grouped in nodes. To check what kind of data is available for the systems you're provisioning, y'all can run the setup
module with an ad hoc command:
- ansible all -i inventory -chiliad setup -u sammy
This command will output an extensive JSON containing information about your server. To obtain a subset of that data, you tin can use the filter
parameter and provide a pattern. For case, if you'd like to obtain information about all IPv4 addresses in the remote nodes, you lot can utilize the following command:
- ansible all -i inventory -m setup -a "filter=*ipv4*" -u sammy
You'll see output similar this:
Output
203.0.113.x | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "203.0.113.ten", "198.51.100.23" ], "ansible_default_ipv4": { "accost": "203.0.113.x", "allonym": "eth0", "broadcast": "203.0.113.255", "gateway": "203.0.113.i", "interface": "eth0", "macaddress": "06:c7:91:16:2e:b7", "mtu": 1500, "netmask": "203.0.113.0", "network": "203.0.113.0", "type": "ether" } }, "changed": false }
Once you have found the facts that will be useful for your play, y'all can update your playbook accordingly. Every bit an instance, the post-obit playbook will print out the IPv4 accost of the default network interface. From the previous control output, nosotros can come across that this value is bachelor through ansible_default_ipv4.address
in the JSON provided by Ansible.
Create a new file called playbook-03.yml
in your ansible-practise
directory:
- nano ~/ansible-practice/playbook-03.yml
And then add the post-obit lines to the new playbook file:
~/ansible-practice/playbook-03.yml
--- - hosts : all tasks : - name : impress facts debug : msg : "IPv4 address: {{ ansible_default_ipv4.accost }}"
Save and shut the file when you're done.
To try this playbook on servers from your inventory file, run ansible-playbook
with the aforementioned connection arguments yous've used before when running our showtime example. Once again, nosotros'll be using an inventory file named inventory
and the sammy user to connect to the remote servers:
- ansible-playbook -i inventory playbook-03.yml -u sammy
When you run the playbook, you'll see your remote server'south IPv4 address in the output as expected:
Output
... TASK [impress facts] *************************************************************************************************************************************************************************** ok: [server1] => { "msg": "IPv4 address: 203.0.113.10" } ...
Facts encapsulate important information that you can leverage to better customize your playbooks. To learn more virtually all the data you can obtain through facts, delight refer to the official Ansible documentation.
Published on April 15, 2021 · Updated on April xiv, 2021
In Ansible, you can ascertain conditions that volition be evaluated before a job is executed. When a condition is not met, the job is then skipped. This is done with the when
keyword, which accepts expressions that are typically based on a variable or a fact.
The following example defines two variables: create_user_file
and user
. When the create_user_file
is evaluated to truthful
, a new file will exist created in the home directory of the user defined by the user
variable:
Create a new file called playbook-04.yml
in your ansible-practice
directory:
- nano ~/ansible-exercise/playbook-04.yml
So add together the post-obit lines to the new playbook file:
~/ansible-practice/playbook-04.yml
--- - hosts : all vars : - create_user_file : yes - user : sammy tasks : - name : create file for user file : path : /dwelling house/{ { user } }/myfile state : touch when : create_user_file
Relieve and close the file when you're done editing its contents.
To execute this playbook on servers from your inventory file, run ansible-playbook
with the same connectedness arguments yous've used before when running other playbooks in this series. Once more, we'll be using an inventory file named inventory
and the sammy user to connect to the remote servers:
- ansible-playbook -i inventory playbook-04.yml -u sammy
When the status is met, you'll see a inverse
condition in the play output:
Output
... TASK [create file for user] ***************************************************************************** changed: [203.0.113.ten] ...
If you change the value of create_user_file
to no
, the status will be evaluated to false
. In this case, you'll see a skipping
status in the play output, indicating that the chore was not executed:
Output
... TASK [create file for user] ***************************************************************************** skipping: [203.0.113.10] ...
A mutual utilize for conditionals in the context of Ansible playbooks is to combine them with annals
, a keyword that creates a new variable and assigns information technology with the output obtained from a command. This way, y'all can use any external control to evaluate the execution of a chore.
One important matter to notice is that, by default, Ansible will interrupt a play if the command you're using to evaluate a condition fails. For that reason, y'all'll need to include an ignore_errors
directive set to yep
in said task, and this will brand Ansible movement on to the side by side task and keep the play.
The following instance will only create a new file in the user habitation directory in case that file doesn't exist yet, which we'll test with an ls
command. If the file exists, however, we'll show a message using the debug
module.
Create a new file chosen playbook-05.yml
in your ansible-practice
directory:
- nano ~/ansible-practice/playbook-05.yml
So add the following content to the new playbook file:
~/ansible-practice/playbook-05.yml
--- - hosts : all vars : - user : sammy tasks : - name : Check if file already exists control : ls /home/{ { user } }/myfile register : file_exists ignore_errors : yes - proper noun : create file for user file : path : /abode/{ { user } }/myfile country : touch when : file_exists is failed - name : show message if file exists debug : msg : The user file already exists. when : file_exists is succeeded
Save and shut the file when you're done.
So, run ansible-playbook
with the same connectedness arguments from the previous examples. Here, we're using an inventory file named inventory
and a user named sammy
, but yous should alter these values accordingly:
- ansible-playbook -i inventory playbook-05.yml -u sammy
The first time y'all run this playbook, the command volition fail because the file doesn't be in that path. The task that creates the file will then be executed, while the terminal task will exist skipped:
... [secondary_label Output] TASK [Check if file already exists] ********************************************************************* fatal: [203.0.113.10]: FAILED! => {"inverse": true, "cmd": ["ls", "/home/sammy/myfile"], "delta": "0:00:00.004258", "terminate": "2020-10-22 13:10:12.680074", "msg": "not-zero render lawmaking", "rc": 2, "starting time": "2020-ten-22 13:10:12.675816", "stderr": "ls: cannot admission '/home/sammy/myfile': No such file or directory", "stderr_lines": ["ls: cannot access '/home/sammy/myfile': No such file or directory"], "stdout": "", "stdout_lines": []} ...ignoring Job [create file for user] ***************************************************************************** changed: [203.0.113.x] Task [evidence message if file exists] ********************************************************************** skipping: [203.0.113.10] ...
From the output, you can meet that the create file for user
task caused a change in the server, which means the file was created. Now, run the playbook over again and you'll become a different issue:
- ansible-playbook -i inventory playbook-05.yml -u sammy
Output
... Task [Check if file already exists] ********************************************************************* changed: [203.0.113.10] Job [create file for user] ***************************************************************************** skipping: [203.0.113.10] Job [show message if file exists] ********************************************************************** ok: [203.0.113.10] => { "msg": "The user file already exists." } ...
If you'd similar to learn more about using conditionals in Ansible playbooks, delight refer to the official documentation.
Published on April xv, 2021 · Updated on April xiv, 2021
When automating server setup, sometimes you'll need to repeat the execution of the same task using different values. For example, you may demand to change permissions of multiple files, or create multiple users. To avoid repeating the task several times in your playbook file, it'southward better to use loops instead.
In programming, a loop allows y'all to echo instructions, typically until a sure status is met. Ansible offers different looping methods, with the loop
keyword beingness the almost recommended option for longer term compatibility.
The following example creates iii different files on the /tmp
location. It uses the file
module inside a task that implements a loop using three different values.
Create a new file called playbook-06.yml
in your ansible-practice
directory:
- nano ~/ansible-practice/playbook-06.yml
Then add the following lines to the new playbook file:
~/ansible-practice/playbook-06.yml
--- - hosts : all tasks : - name : creates users files file : path : /tmp/ansible- { { item } } country : touch loop : - sammy - erika - brian
Salve and close the file when you're washed.
And then, run ansible-playbook
with the same connection arguments from the previous examples. Again, we're using an inventory file named inventory
and a user named sammy
, simply you should change these values accordingly:
- ansible-playbook -i inventory playbook-06.yml -u sammy
You'll go output like this, showing each private item value that was used within the loop:
Output
... Chore [creates users files] ****************************************************************************** changed: [203.0.113.ten] => (item=sammy) inverse: [203.0.113.10] => (item=erika) changed: [203.0.113.ten] => (item=brian) ...
For more than detailed information on how to use loops when writing Ansible playbooks, please refer to the official documentation.
Published on Apr xv, 2021 · Updated on April 14, 2021
Simply as with regular commands that you execute on a terminal, some tasks will require special privileges in order for Ansible to execute them successfully on your remote nodes.
It is of import to empathize how privilege escalation works in Ansible and then that yous're able to execute your tasks with appropriate permissions. Past default, tasks will run as the connecting user - this might be either root or any regular user with SSH access to the remote nodes in an inventory file.
To run a control with extended permissions, such equally a control that requires sudo
, you lot'll demand to include a become
directive set to yes
in your play. This tin exist done either as a global setting valid to all tasks in that play, or as an individual instruction applied per task. Depending on how your sudo
user is fix inside the remote nodes, yous may also demand to provide the user'south sudo
password. The post-obit case updates the apt
cache, a task that requires root permissions.
Create a new file chosen playbook-07.yml
in your ansible-do
directory:
- nano ~/ansible-exercise/playbook-07.yml
Then add the post-obit lines to the new playbook file:
~/ansible-practice/playbook-07.yml
--- - hosts : all become : yep tasks : - name : Update apt cache apt : update_cache : yes
Salvage and shut the file when yous're done.
To run this playbook, you lot'll need to include the -Thousand
option within the ansible-playbook
command. This will make Ansible prompt you for the sudo
password for the specified user.
- ansible-playbook -i inventory playbook-07.yml -u sammy -K
Yous can besides change which user yous want to switch to while executing a task or play. To practise that, fix the become_user
directive to the name of the remote user you lot desire to switch to. This is useful when you have several tasks in a playbook that rely on sudo
, but also a few tasks that should run every bit your regular user.
The following case defines that all tasks in this play will exist executed with sudo
by default. This is set at the play level, right after the hosts
definition. The commencement task creates a file on /tmp
using root
privileges, since that is the default became_user
value. The concluding task, all the same, defines its own become_user
.
Create a new file chosen playbook-08.yml
in your ansible-practice
directory:
- nano ~/ansible-exercise/playbook-08.yml
Add the post-obit content to the new playbook file:
~/ansible-exercise/playbook-08.yml
--- - hosts : all get : yep vars : user : "{{ ansible_env.USER }}" tasks : - name : Create root file file : path : /tmp/my_file_root land : touch - name : Create user file become_user : "{{ user }}" file : path : /tmp/my_file_{ { user } } state : touch
Save and shut the file when y'all're finished.
The ansible_env.USER
fact contains the username of the connecting user, which tin be defined at execution fourth dimension when running the ansible-playbook
command with the -u
option. Throughout this guide, we're connecting as sammy
:
- ansible-playbook -i inventory playbook-08.yml -u sammy -K
Output
BECOME password: PLAY [all] ********************************************************************************************** Chore [Gathering Facts] ********************************************************************************** ok: [203.0.113.ten] Job [Create root file] ********************************************************************************* changed: [203.0.113.x] Chore [Create user file] ********************************************************************************* changed: [203.0.113.10] PLAY RECAP ********************************************************************************************** 203.0.113.10 : ok=3 changed=two unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
When the playbook is finished running, you tin can log onto the remote node(s) to verify that two new files were created on /tmp
, each with different ownership data:
- ssh sammy@203.0.113.10
- ls -la /tmp/my_file*
Output
-rw-r--r-- i root root 0 Apr xiv 13:xix /tmp/my_file_root -rw-r--r-- 1 sammy sudo 0 Apr 14 12:07 /tmp/my_file_sammy
For more than detailed data about privilege escalation in Ansible, please refer to the official documentation.
Published on April xv, 2021 · Updated on April fourteen, 2021
Automating the installation of required system packages is a common operational chore in Ansible playbooks, since a typical application stack requires software from different sources.
The apt
module manages system packages on Debian-based operating systems such every bit Ubuntu, the distribution we're using on remote nodes throughout this guide. The following playbook will update the apt
enshroud and so brand sure Vim is installed on remote nodes.
Create a new file called playbook-09.yml
in your ansible-exercise
directory:
- nano ~/ansible-practise/playbook-09.yml
So add the following lines to the new playbook file:
~/ansible-practice/playbook-09.yml
--- - hosts : all become : yes tasks : - name : Update apt enshroud and make sure Vim is installed apt : proper name : vim update_cache : yep
Save and close the file when yous're done.
Discover that we've included the go
directive in the beginning of the play. This is required since installing packages requires administrative organization permissions.
Removing a parcel is done in a similar way, the only change is that you take to define the package state to absent
. The land
directive has a default value of present
, which will make certain that the packet is installed on the system, regardless of the version. The package will be installed if not present. To clinch you have the latest version of a package, you tin can use latest
instead. This will cause apt
to update the requested bundle if that is not on their latest version.
Remember to provide the -M
option when running this playbook, since it requires sudo
permissions:
- ansible-playbook -i inventory playbook-09.yml -u sammy -K
Output
Become countersign: PLAY [all] ********************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [203.0.113.10] TASK [Update apt enshroud and make sure Vim is installed] ************************************************** ok: [203.0.113.10] PLAY Epitomize ********************************************************************************************** 203.0.113.10 : ok=two changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
When installing multiple packages, y'all tin can use a loop and provide an array containing the names of the packages you lot desire to install. The post-obit playbook will make certain the packages vim
, unzip
, and scroll
are installed and in their latest version.
Create a new file called playbook-10.yml
in your ansible-practice
directory, on your Ansible command node:
- nano ~/ansible-practice/playbook-ten.yml
Add the following content to the new playbook file:
~/ansible-practice/playbook-10.yml
--- - hosts : all become : aye tasks : - proper noun : Update apt cache and make certain Vim, Curl and Unzip are installed apt : proper noun : "{{ item }}" update_cache : yeah loop : - vim - scroll - unzip
Salvage and close the file when yous have finished.
And then, run ansible-playbook
with the same connexion arguments from the previous examples, and don't forget to include the -K
option since this playbook requires administrative privileges:
- ansible-playbook -i inventory playbook-09.yml -u sammy -1000
You'll run into output like this, indicating that the same task run through three iterations using the unlike values we have provided: vim
, whorl
, and unzip
:
Output
BECOME password: PLAY [all] *************************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************** ok: [203.0.113.10] Chore [Update apt enshroud and brand certain Vim, Curl and Unzip are installed] ************************************************************************** ok: [203.0.113.x] => (detail=vim) ok: [203.0.113.10] => (item=curl) changed: [203.0.113.10] => (item=unzip) PLAY Recap *************************************************************************************************************************************** 203.0.113.10 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
For more details on how to manage system packages, including how to remove packages and how to use advanced apt
options, you can refer to the official documentation.
Published on Apr 15, 2021 · Updated on April 15, 2021
Templates allow y'all to create new files on the nodes using predefined models based on the Jinja2 templating system. Ansible templates are typically saved as .tpl
files and support the use of variables, loops, and conditional expressions.
Templates are commonly used to configure services based on variable values that can exist ready upward on the playbook itself, in included variable files, or obtained via facts. This enables you to create more versatile setups that adapt behavior based on dynamic information.
To try it out this characteristic with a applied example, create a new directory to concur non-playbook files within your ansible-practise
directory:
- mkdir ~/ansible-practice/files
Next, create a new template file for an HTML landing page. Afterwards, we'll set up a playbook which will configure your remote nodes to serve the landing page with Nginx:
- nano ~/ansible-practice/files/landing-page.html.j2
Add the following content to the template file:
~/ansible-practice/files/landing-page.html.j2
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>{{ page_title }}</title> <meta name="description" content="Created with Ansible"> </caput> <body> <h1>{{ page_title }}</h1> <p>{{ page_description }}</p> </body> </html>
Save and close the file when you're done.
This template uses two variables that must be provided whenever the template is practical in a playbook: page_title
and page_description
.
The post-obit playbook sets up the required variables, installs Nginx, and and so applies the specified template to replace the existing, default Nginx landing page located at /var/www/html/index.nginx-debian.html
. The terminal task uses the ufw
module to enable tcp admission on port 80
, in case you have your firewall enabled as recommended in our initial server setup guide.
Create a new file called playbook-eleven.yml
in your ansible-practice
directory:
- nano ~/ansible-practice/playbook-xi.yml
Add the following content to the new playbook file:
~/ansible-do/playbook-11.yml
--- - hosts : all go : aye vars : page_title : My Landing Folio page_description : This is my landing folio description. tasks : - name : Install Nginx apt : name : nginx state : latest - name : Apply Page Template template : src : files/landing-folio.html.j2 dest : /var/www/html/index.nginx-debian.html - proper name : Let all access to tcp port fourscore ufw : rule : allow port : 'fourscore' proto : tcp
Recollect to provide the -K
option if yous run this playbook, since it requires sudo
permissions:
- ansible-playbook -i inventory playbook-11.yml -u sammy -Thou
Output
BECOME password: PLAY [all] ********************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [203.0.113.10] TASK [Install Nginx] ************************************************************************************ changed: [203.0.113.10] TASK [Apply Page Template] ****************************************************************************** changed: [203.0.113.10] TASK [Allow all admission to tcp port fourscore] ****************************************************************** changed: [203.0.113.x] PLAY RECAP ********************************************************************************************** 203.0.113.10 : ok=iv changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
When the play has finished, you tin access the web server's public IP address from your browser. You'll see a page like this:
That means your playbook worked as expected, and the default Nginx page was replaced by the template you have created.
Published on April xv, 2021 · Updated on April 15, 2021
In a nutshell, handlers are special tasks that only go executed when triggered via the notify
directive. Handlers are executed at the terminate of the play, in one case all tasks are finished.
In Ansible, handlers are typically used to offset, reload, restart, and stop services. If your playbook involves changing configuration files, there is a high take chances that y'all'll need to restart a service and then that the changes take issue. In this instance, you lot'll need to define a handler for that service and include the notify
directive in any tasks that require that service handler.
In a previous department of this series, yous've seen how to use a template to replace the default Nginx folio with a custom HTML landing page. In practise, when setting up your Nginx web server, you're most likely going to include new server block files in your sites-available
directory, create symbolic links, or change settings that require a server reload or restart.
Considering such a scenario, this is how a handler to restart the Nginx service would look like:
... handlers : - proper noun : Restart Nginx service : name : nginx country : restarted
To trigger this handler, you'll demand to include a notify
directive in whatever task that requires a restart on the Nginx server.
The post-obit playbook replaces the default document root in Nginx's configuration file using the built-in Ansible module supersede. This module looks for patterns in a file based on a regular expression defined past regexp
, so replaces whatsoever matches plant with the content divers past replace
. The task then sends a notification to the Restart Nginx
handler for a restart as soon every bit possible. What that means is, it doesn't matter how many times you trigger the restart, information technology will simply happen when all tasks are already finished executing and the handlers beginning running. Additionally, when no matches are found, no changes are made to the organisation, and for that reason the handler is not triggered.
Create a new file called playbook-12.yml
in your ansible-do
directory:
- nano ~/ansible-practice/playbook-12.yml
Add together the following lines to the new playbook file:
ansible-practice/playbook-12.yml
--- - hosts : all go : yes vars : page_title : My Second Landing Page page_description : This is my second landing page clarification. doc_root : /var/www/mypage tasks : - proper name : Install Nginx apt : name : nginx land : latest - proper name : Make sure new doc root exists file : path : "{{ doc_root }}" country : directory mode : '0755' - proper noun : Apply Folio Template template : src : files/landing-folio.html.j2 dest : "{{ doc_root }}/index.html" - name : Replace document root on default Nginx configuration replace : path : /etc/nginx/sites-available/default regexp : '(\s+)root /var/www/html;(\s+.*)?$' replace : \g<ane>root { { doc_root } };\k<2> notify : Restart Nginx - name : Allow all access to tcp port 80 ufw : rule : allow port : '80' proto : tcp handlers : - name : Restart Nginx service : name : nginx country : restarted
Save and shut the file when you're washed.
One of import affair to go on in mind when using handlers is that they are simply triggered when the task that defines the notify
trigger causes a change in the server. Taking this playbook into account, the beginning time it runs the replace
task it will change the Nginx configuration file and thus the restart volition run. In subsequent executions, however, since the string to be replaced is not present in the file anymore, the chore won't cause any changes and won't trigger the handler execution.
Remember to provide the -Thousand
pick if you lot run this playbook, since it requires sudo
permissions:
- ansible-playbook -i inventory playbook-12.yml -u sammy -M
Output
Go password: PLAY [all] ********************************************************************************************** Chore [Gathering Facts] ********************************************************************************** ok: [203.0.113.10] TASK [Install Nginx] ************************************************************************************ ok: [203.0.113.x] TASK [Make sure new doc root exists] ******************************************************************** changed: [203.0.113.ten] TASK [Employ Folio Template] ****************************************************************************** inverse: [203.0.113.10] Job [Supervene upon certificate root on default Nginx configuration] ********************************************* changed: [203.0.113.10] Chore [Allow all access to tcp port 80] ****************************************************************** ok: [203.0.113.10] RUNNING HANDLER [Restart Nginx] ************************************************************************* changed: [203.0.113.10] PLAY Recap ********************************************************************************************** 203.0.113.10 : ok=7 changed=four unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If you look at the output, you'll see the "Restart Nginx" handler being executed just before the end of the play. If you go to your browser and access the server'south IP address at present, you lot'll see the following page:
In the next and final part of this series, nosotros'll connect all the dots and put together a playbook that automates setting upwardly a remote Nginx server to host a static HTML website.
Published on Apr xv, 2021 · Updated on April 14, 2021
If you were following along with all parts of this series, at this point you should exist familiar with installing system packages, applying templates, and using handlers in Ansible playbooks. In this part of the serial, you'll use what you've seen then far to create a playbook that automates setting upward a remote Nginx server to host a static HTML website on Ubuntu xx.04.
First by creating a new directory on your Ansible control node where you'll fix upwards the Ansible files and a demo static HTML website to exist deployed to your remote server. This could exist in whatever location of your choice inside your home folder. In this example we'll use ~/ansible-nginx-demo
.
- mkdir ~/ansible-nginx-demo
- cd ~/ansible-nginx-demo
Next, re-create your existing inventory file into the new directory. In this example, we'll use the same inventory you prepare at the beginning of this series:
- cp ~/ansible-practise/inventory .
This will re-create a file named inventory
from a folder named ansible-practice
in your home directory, and save information technology to the current directory.
Obtaining the Demo Website
For this sit-in, we'll use a static HTML website that is the subject of our How To Code in HTML serial. Start by downloading the demo website files by running the post-obit command:
- curl -L https://github.com/do-customs/html_demo_site/archive/refs/heads/primary.zip -o html_demo.cipher
You'll need unzip
to unpack the contents of this download. To make certain you take this tool installed, run:
- sudo apt install unzip
Then, unpack the demo website files with:
- unzip html_demo.zip
This will create a new directory called html_demo_site-master
on your electric current working directory. You lot can cheque the contents of the directory with an ls -la
command:
- ls -la html_demo_site-main
Output
total 28 drwxrwxr-ten 3 sammy sammy 4096 sep 18 2020 . drwxrwxr-x v sammy sammy 4096 mrt 25 15:03 .. -rw-rw-r-- 1 sammy sammy 1289 sep eighteen 2020 about.html drwxrwxr-x 2 sammy sammy 4096 sep 18 2020 images -rw-rw-r-- 1 sammy sammy 2455 sep 18 2020 index.html -rw-rw-r-- 1 sammy sammy 1079 sep xviii 2020 LICENSE -rw-rw-r-- 1 sammy sammy 675 sep eighteen 2020 README.doctor
Creating a Template for Nginx'south Configuration
You'll at present ready the Nginx template that is necessary to configure the remote web server. Create a new binder within your ansible-demo
directory to concord non-playbook files:
- mkdir files
So, open a new file called nginx.conf.j2
:
- nano files/nginx.conf.j2
This template file contains an Nginx server block configuration for a static HTML website. It uses three variables: document_root
, app_root
, and server_name
. Nosotros'll define these variables afterwards on when creating the playbook. Copy the post-obit content to your template file:
~/ansible-nginx-demo/files/nginx.conf.j2
server { listen 80; root {{ document_root }}/{{ app_root }}; index index.html alphabetize.htm; server_name {{ server_name }}; location / { default_type "text/html"; try_files $uri.html $uri $uri/ =404; } }
Save and shut the file when you're done.
Creating a New Ansible Playbook
Next, nosotros'll create a new Ansible playbook and fix the variables that we've used in the previous section of this guide. Open a new file named playbook.yml
:
- nano playbook.yml
This playbook starts with the hosts
definition set to all
and a become
directive that tells Ansible to run all tasks equally the root user by default (the aforementioned as manually running commands with sudo
). Within this playbook'southward var
section, we'll create iii variables: server_name
, document_root
, and app_root
. These variables are used in the Nginx configuration template to prepare the domain name or IP accost that this web server volition respond to, and the total path to where the website files are located on the server. For this demo, we'll use the ansible_default_ipv4.address
fact variable because information technology contains the remote server's public IP address, only you can replace this value with your server'south hostname in case it has a domain name properly configured within a DNS service to point to this server:
~/ansible-nginx-demo/playbook.yml
--- - hosts : all become : aye vars : server_name : "{{ ansible_default_ipv4.address }}" document_root : /var/www/html app_root : html_demo_site-main tasks :
You tin can keep this file open for now. The side by side sections will walk you through all tasks that you'll need to include in this playbook to brand information technology fully functional.
Installing Required Packages
The following task volition update the apt
cache so install the nginx
package on remote nodes:
~/ansible-nginx-demo/playbook.yml
. . . - proper noun : Update apt enshroud and install Nginx apt : name : nginx state : latest update_cache : yeah
Uploading Website Files to Remote Nodes
The next task will use the copy
born module to upload the website files to the remote document root. Nosotros'll use the document_root
variable to ready the destination on the server where the awarding binder should be created.
~/ansible-nginx-demo/playbook.yml
. . . - proper name : Copy website files to the server's certificate root copy : src : "{{ app_root }}" dest : "{{ document_root }}" mode : preserve
Applying and Enabling the Custom Nginx Configuration
We'll now apply the Nginx template that will configure the web server to host your static HTML file. After the configuration file is set at /etc/nginx/sites-available
, nosotros'll create a symbolic link to that file inside /etc/nginx-sites-enabled
and notify the Nginx service for a posterior restart. The entire procedure will crave two separate tasks:
~/ansible-nginx-demo/playbook.yml
. . . - name : Apply Nginx template template : src : files/nginx.conf.j2 dest : /etc/nginx/sites-available/default notify : Restart Nginx - proper noun : Enable new site file : src : /etc/nginx/sites-bachelor/default dest : /etc/nginx/sites-enabled/default state : link notify : Restart Nginx
Assuasive Port lxxx on UFW
Next, include the task that enables tcp access on port fourscore:
~/ansible-nginx-demo/playbook.yml
. . . - name : Allow all access to tcp port 80 ufw : dominion : allow port : '80' proto : tcp . . .
Creating a Handler for the Nginx Service
To cease this playbook, the simply thing left to do is to prepare the Restart Nginx
handler:
~/ansible-nginx-demo/playbook.yml
. . . handlers : - name : Restart Nginx service : proper noun : nginx land : restarted
Running the Finished Playbook
Once you're finished including all the required tasks in your playbook file, it volition wait like this:
~/ansible-nginx-demo/playbook.yml
--- - hosts : all become : yes vars : server_name : "{{ ansible_default_ipv4.accost }}" document_root : /var/world wide web app_root : html_demo_site-primary tasks : - name : Update apt enshroud and install Nginx apt : name : nginx state : latest update_cache : aye - name : Copy website files to the server's document root re-create : src : "{{ app_root }}" dest : "{{ document_root }}" mode : preserve - proper name : Utilize Nginx template template : src : files/nginx.conf.j2 dest : /etc/nginx/sites-available/default notify : Restart Nginx - name : Enable new site file : src : /etc/nginx/sites-bachelor/default dest : /etc/nginx/sites-enabled/default state : link notify : Restart Nginx - proper noun : Allow all admission to tcp port 80 ufw : rule : allow port : 'lxxx' proto : tcp handlers : - name : Restart Nginx service : name : nginx state : restarted
To execute this playbook on the server(s) that you set upwardly in your inventory file, run ansible-playbook
with the aforementioned connection arguments you've used when running a connection exam within the introduction of this series. Here, we'll be using an inventory file named inventory
and the sammy user to connect to the remote server. Considering the playbook requires sudo
to run, nosotros're as well including the -M
argument to provide the remote user'due south sudo
password when prompted past Ansible:
- ansible-playbook -i inventory playbook.yml -u sammy -K
You'll see output like this:
Output
BECOME password: PLAY [all] ********************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [203.0.113.10] TASK [Update apt cache and install Nginx] *************************************************************** ok: [203.0.113.10] TASK [Copy website files to the server's document root] ************************************************* inverse: [203.0.113.ten] TASK [Apply Nginx template] ***************************************************************************** inverse: [203.0.113.10] TASK [Enable new site] ********************************************************************************** ok: [203.0.113.ten] Task [Allow all access to tcp port 80] ****************************************************************** ok: [203.0.113.10] RUNNING HANDLER [Restart Nginx] ************************************************************************* changed: [203.0.113.10] PLAY Epitomize ********************************************************************************************** 203.0.113.10 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
One time the playbook is finished, if you get to your browser and access your server's hostname or IP address you should now meet the post-obit page:
Congratulations, you have successfully automated the deployment of a static HTML website to a remote Nginx server, using Ansible.
If you make changes to any of the files in the demo website, you can run the playbook once again and the copy
job will make certain whatever file changes are reflected in the remote host. Because Ansible has an idempotent behavior, running the playbook multiple times will not trigger changes that were already made to the system.
Conclusion
By following this series, yous learned how to use in practice some of the most common features of Ansible playbooks, such equally variables, conditionals, loops, templates, and handlers. Yous created a playbook to automate the deployment of a remote Nginx web server, with a custom server template and a task to re-create your local website files to the remote server'southward document root.
To learn more about Ansible and its command line interface, yous tin check our series on How To Manage Remote Servers with Ansible, and our Ansible Reference Guide. Visit our Ansible tag page for more content, including workshops and video presentations, almost this tool.
For more information well-nigh the subjects discussed in this series, bank check the following resources:
- All content under the Ansible tag
- Official Ansible Documentation
Source: https://www.digitalocean.com/community/tutorial_series/how-to-write-ansible-playbooks
0 Response to "Ansible Run a Specifc Task Again"
Post a Comment