The course is part of these learning paths
Getting Started With Ansible
Cloud platforms, on-prem servers, dozens of operating systems, more language and frameworks than you can count, and you have to manage it all!
These days even the "simple" application infrastructures have a lot of moving parts. Managing all of this stuff effectively takes some effort, and configuration management tools such as Ansible can help.
Ansible is an automation engine that can help with provisioning infrastructure, configuring operating systems, deploying applications, and much more.
The goal of this course is to teach you how to get started using Ansible for automation. By then end of this course you should be able to create playbooks to automate basic tasks. You won't know everything there is to know about Ansible, however you'll know enough of the basics to start using Ansible. You'll understand how Ansible manages inventory, how to create simple modules, how to create playbooks, how to deal with errors and more.
Understanding a tool such as Ansible has a lot of value to developers and operations engineers. Especially since it's agentless, because that means you can start managing hosts without needing to install an agent on them first. Well, assuming Python is installed. Developers can use Ansible to automate the creation of development environments that mirror production. And operations can use the same playbooks to automate the creation of staging and production environments. This level of consistency between environments tends to reduce bugs; especially those caused from environmental differences.
One of the features of Ansible that makes it so appealing is that it allows you to create modules with whatever language you want. Another appealing feature is the YAML based playbooks. The reason this is so appealing is that YAML tends to be a very simple format for expressing tasks. And that makes it easier to get started using it.
What You'll Learn
|Lecture||What you'll learn|
|Intro||What will be covered in this course|
|What is Ansible?||An introduction to Ansible|
|Concepts||An overview of the Ansible concepts|
|Installation||How to install Ansible|
|Inventory||How Ansible knows which servers to manage|
|Windows||How Ansible connects to Windows servers|
|Modules||What modules are and how to create one|
|Playbook||What playbooks are and how to create them|
|Handlers, Facts, Variables, and Templates||Handlers, Facts, Variables, and Templates|
|Roles||How to bundle functionality in a role|
|Errors and Debugging||How to deal with errors and how to use the debug module|
|Next Steps||How to keep learning|
If you have thoughts or suggestions for this course, please contact Cloud Academy at firstname.lastname@example.org.
Welcome back. In this lesson, I'll be talking about Playbooks. Playbooks allow you to create complex configurations and execute them on multiple servers at the same time. Here's an example of a Playbook. There's just one play here. A play is the combination of the host it should run on and the tasks that should be run. If was to add another play, it might apply to a different group of host, and it would have some tasks to run.
We'll walk through the anatomy of a playbook in a moment, but first, I want to talk about YAML. This data structure here is called YAML. YAML is a whitespace sensitive data serialization format. Ansible uses YAML quite heavily. YAML used to stand for Yet Another Markup Language, and that at some point it changed, and now YAML stands for YAML Ain't Markup Language. It's a recursive acronym. It's not great, but there it is.
Let's go through the structure of it, so that you're comfortable creating Playbooks. YAML is built around key value pairs. And the values can be basic data types such as strings, numbers, Booleans, as well as lists and dictionaries. It's the list and dictionaries that make YAML a simple but powerful format for representing data. Here's an example of an employee record from Ansible's documentation.
A line that starts with a minus is a list item, and any line at that same indentation level with a minus are part of that same list. In this example, there is just one employee in the list, and if you were to add another, it would have to be at the same level of indentation, and it would also have to start with a minus.
Now, the dictionary key value syntax is to use the key name and a colon followed by a space, and then the value that you want to set. The vale could be any of the supported data types, and that includes things like lists and dictionaries allowing for nested content.
When it comes to Boolean values, Ansible is pretty flexible. It allows you to use the words yes, no, true, and false. So, you have some flexibility, but it's good to standardize on one. Sometimes when dealing with long strings, it helps to break them up into multiple lines, and YAML allows you to use either inclusive or exclusive multi-line strings. Now that means you can use the pipe symbol to have new lines included in the string, or you can use the greater than symbol to exclude the new line characters.
Now, this is useful if you want the text to be easier to read. However, you don't want Ansible to include those new line characters. There are somethings when creating a Playbook that tends to bite people who are new to YAML. One of those things is that if you're using a string as the value for a key, then it needs to be wrapped in quotes if it has a colon in the text.
Another common cause for errors is that if you're using a variable for a value, and that variable is the start of the value, then you need to wrap in quotes. The reason is that YAML let's you use curly braces for specifying dictionaries, though it's optional. And since Ansible uses curly braces for its variables, there can be conflicts when it starts with a curly brace.
Now, this is just an intro to YAML. There is more to learn. However, this should get you up and running and creating Playbooks with some level of comfort. Okay, armed with your understanding of YAML, let's jump back into talking about Playbooks. Playbooks are broken out into plays.
Here's an example of a Playbook with two plays. The first target is the lamp group, and the second targets the test group, and they each have their own tasks. At a very high level, the anatomy of a play is to define the hosts, tasks, and then any additional info. The additional info can include things such as variables, connection info, et cetera.
If you recall, I mentioned the ability to use complex pattern matching for targeting host when using ad hoc commands. Playbooks allow for that same complex pattern matching. So, if you need to target an individual server plus three groups, that's something that you could do.
Tasks are a module with some metadata. This metadata includes things like the name, notifications, settings for ignoring errors, conditional statements, et cetera. Looking at the first task in this play, the name is used as a human readable name for the task. It's what Ansible displays in the console when tasks are run. The module being executed is apt, which is a package manager for Debian based Linux systems.
When you run commands on a command line, you often need to pass in arguments. Since modules are basically just executable code, you'll likely need to pass them arguments as well. And that's what these keys are here. The name and state are values that are passed to the apt module. So, in this example, apt is being passed the name of the package and the state. The name of the package is what to act on, and the state determines if the package should be installed, uninstalled, et cetera.
So, so far in this course I've gone through some of the core concepts. I've explained inventory, modules, Playbooks, YAML. So now it's time to start creating Playbooks. As the course progresses, I'll slowly refactor the Playbook to be more efficient. In that way you can build on what you're learning.
So, here's what I'll do. I'm going to create a Playbook for installing a LAMP stack. In this example, the P will stand for Python, but otherwise, it's a pretty traditional LAMP stack. Then I'll install a simple Flask based application. Flask is a Python web framework.
So, I'll start out with this empty file. I've named it app.yml, and I'll add three hyphens at the top. This is a YAML convention to indicate the start of YAML content. However, it isn't required. I like to use it since Ansible tends to, and that way the YAML files are consistent. Now, I need to create a play. This play will target the lamp group from the inventory. I'll set the remote user to be Ubuntu, and then this become setting tells Ansible to pseudo root.
Now, I need to create some tasks. I like to stub out the names of the tasks that I need, and then I call fill them out afterwards, and this helps me get an idea of what I'm actually trying to do. So, this is just the way I do things, but you can do it differently. I'll add a placeholder for each. Great. Now I can go back and start adding in the modules to accomplish these tasks.
The first task is responsible for installing any packages that are required. Since I'm using a Ubuntu server, I'll use apt. You can specify the name of the package to install the name property. However, since there are several packages, I'm gonna use a variable for this. The syntax is to use two curly braces, the name of the variable, and then two closing curly braces. And it needs to be in quotes, so that YAML doesn't get confused and think that this is the start of a dictionary.
I'll add two more properties, one for state, and that's going to be set to present, meaning that I want these packages installed, and then I'll add a setting for update cash, and I'll set that to true, which updates the apt cache before installing anything, which is generally a good practice.
I mentioned that I want to install multiple packages, and Ansible let's you loop over a task by using the with items property. The with items expects a list, so I'll add each of the list items. The name of the variable here is item, and that's provided by the with items loop. It'll run this task for each item in the list. This saves you from needing to create one task for each package.
The next task in the list is in charge of starting the services, so I'll use the service module, and again, I'm gonna loop over the services that I want to start with the with items loop. So, I'll set the name to be an item variable, and the state should be set to running. And then the services to loop over are going to be Apache2 and MySQL.
Now the next two tasks are shell scripts to enable SSL. And the final task is going to be to restart the Apache service, so that all of this stuff will have taken effect inside of Apache. And when this is done, I can run the Playbook. However, first, I wanna browse to the URL of that LAMP server, so that you can see that there's nothing there. That's because there isn't a web server installed on it yet.
Now, if you run this Playbook, I'm gonna use the ansible-playbook executable, and it's gonna take just a minute or two. It's gonna execute all of these tasks. And when it's done, there are six tasks that had been run successfully. Notice the command to run the Playbook is different than the ad hoc command. It's the ansible-playbook in this case, and not the Ansible executable.
Now if I browse to that URL again, the default Apache page should be displayed, and there it is, okay, with the LAMP stack fully installed on that server, It's time to create some tasks to deploy a simple python based application. I'm just going to copy and paste this section, so that you don't need to watch all of this being typed. I'll start by pasting in the database tasks. These are responsible for installing the Python MySQL library, and making sure that a MySQL user exists with the name of appuser, and then the password that I have previously set.
I also wanna ensure that there is a database schema that exist named appdata. With the database configured, I can paste in the task for installing the application code. So, I'll paste that below the database stuff. This is responsible for installing pip, a Python package manager, for downloading the code from GitHub, and then it will install the dependencies for this Python application with pip.
Okay. With that, I can paste in the final section for configuring the website. This section uses the shell module to call rsync to copy the application from the temp folder to the dub dub dub folder. Then it makes sure that Apache has mod_wsgi installed. That's a module that allows Python to run under Apache. And then I need to copy over a configuration file form the control machine to the LAMP server. This is how Apache knows where to find the application.
Looking at it here, you can see this is a fairly basic setup that just points Apache to the Python file. And with all of this done, I can restart Apache. It's time to test this out by running the Playbook. It'll take a moment, so I'm going to fast forward to when it's complete. Okay, so there it is.
Now, if I refresh the page, it should change from that default Apache page to the new application, and there it is. So yes, it's rather ugly. However, it makes for a very simple test. So, this Playbook has one play with several tasks, and it installs a LAMP stack, and then installs a Flask application. However, there is some duplicating code, and there's some hard coded paths in the Playbook, and in the Apache config file. Let's learn how to clean this up in the next lesson.
So, if you're ready to learn about handlers, facts, variables, and templates, then let's get started in the next lesson.
Ben Lambert is a software engineer and was previously the lead author for DevOps and Microsoft Azure training content at Cloud Academy. His courses and learning paths covered Cloud Ecosystem technologies such as DC/OS, configuration management tools, and containers. As a software engineer, Ben’s experience includes building highly available web and mobile apps. When he’s not building software, he’s hiking, camping, or creating video games.