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 support@cloudacademy.com.
Welcome back. In this lesson I'll talk about Inventory in the context of Ansible. I'll cover Static and Dynamic Inventory, how connections are made, and Host patterns. Inventory is an important concept for Ansible. So let's start with an overview of what it is.
Ansible is able to execute tasks from the control machine against itself and remote servers. And if you want to run tasks on remote servers, then Ansible needs to know about those servers. Tools such as Chef require you to install an agent on the servers that you want to manage. And that agent is responsible for phoning home and registering itself with the control machine. Since Ansible is agentless, it needs a way of knowing about those servers that you want to manage.
And it does this with what's called an Inventory File. An Inventory File is basically a list of the different servers that you want Ansible to manage and you can add servers to groups for easier management. Here's a simple example of what an Inventory File might look like. The first entry is an individual DNS record that represents an e-mail server.
And then there are two groups which are the Web servers and the Database servers. A group allows you to have a set of servers for a specific role. You can create a group by putting the name of the group in square brackets and placing the servers that belong to it below it. In this example, if I refer to the Web servers group, I'm referring to two servers. With the host names foo.example.com and bar.example.com.
In addition to individual groups, you could also specify groups of groups and even variables that belong to a specific group. In this example, notice that there's a group for Atlanta, another for Raleigh, and then there's a Southeast group that contains both the Atlanta and the Raleigh groups.
To create a group of groups, or a Nested group, you can add a colon and then the world children after the name of the group. And that lets Ansible know that it's a Nested group. And you can nest groups even further, just like that last USA group. Notice it consists of the Southeast group as well as some other groups that aren't shown here.
I mentioned earlier, that you can store group variables in the inventory file, which you can see are set with the :vars suffix. And while it is possible, it's a better practice to store them in their own files. By default, Ansible looks for the inventory file in /etc/ansible/hosts.
And if you want to create variables, you'd store them in a file named after the group or host. And the files are stored in either the group_vars or host_vars file inside of the /etc/asible/ directory. Now, don't worry if variables don't make sense just yet. I'll be covering them later in the course.
Okay, so Ansible allows you to specify what servers it has access to. However knowing the name of the server is just part of what's required for Ansible to connect to it. Ansible has a couple of preferred ways for connecting to servers. For Linux servers it's SSH, for Windows servers the preference is to use WinRM, which is the Windows Remote Management protocol. Ansible allows you to specify connection settings per host and per group, as well as in the main Ansible configuration file, which is something I'll set up shortly.
Let's create some servers to manage with Ansible before setting up the inventory file. I'm going to create some servers on AWS. Now Ansible doesn't care where the servers live. So, this could be servers in a data center somewhere, could be on Azure, on Google Cloud, or on your network.
I'm not going to go into detail on the AWS specifics here, the important thing to take note of is that I'm creating three Ubuntu servers, and I'm opening up ports for SSH, which is port 22, and I'll open up port 80 for HTTP traffic. And while those servers are starting up, I'm going to start up another server, and this is going to be a Windows server. This setup is going to be roughly the same as the Linux server. I'm going to accept the default, and I'm going to open up a port for HTTP.
And I'll start this up, and let's get started creating the inventory file. Let's break down the inventory into three groups. One group will be for a LAMP stack. LAMP stand for Linux Apache MySQL and PHP. Although in this case, the PHP is going to be replaced with Python. Another will be for the Windows server. And then the final group will be a test group.
I'm going to open the hosts file with Nano. And then I'll add the LAMP group. I'll grab the DNS name from the AWS console, and I'll paste that in. And then I'm going to repeat this process for the tests and Windows groups. With this file setup, Ansible will be able to reference the serves based on the name of the group that it's a part of.
So, now Ansible knows about the inventory. However, it still won't know how to connect to the server since Ansible doesn't have any of the connection information yet. For this, I'm going to configure the Linux connection. And then I'll do the Windows connection in the next lesson.
Since all of the Linux servers are using the same SSH key in this example, it's going to be easier for me to specify it with the Ansible configuration file than in the inventory file.
So, let's edit the config file, which lives at /etc/ansible/ansibleconfig, and you can see there are a lot of settings here. And it's worth going through and at least having a cursory understanding of them. However, going through them all is going to be outside of the scope of this course.
So I'm going to page down until I find the private_key_setting property. And I'm going to set it to the path of my SSH key. This is a key that I created previously inside of AWS and then downloaded to this folder. Now I'll save the config file. And then I want to test things out. And to test it out, I'm going to run Ping module as an ad hoc command.
Let's ping the Lamp and Test groups. Notice it prints out some details about the status of the command for each of the three Linux servers in the two groups. It returned a pong response, letting us know that everything was successful.
So, you may have noticed that it's easy to use the inventory file to add hosts and groups. However, if you've been working on a cloud platform, then you may be wondering how to handle inventory when servers are created and removed dynamically. And this is where Dynamic Inventory comes in handy. Dynamic Inventory allows you to use an executable to automatically get the inventory from some location. That location could be the API for a cloud platform, some database, or anywhere else that you might have that server information.
Any executable code, capable of producing JSON output, can be used to create a Dynamic Inventory file. However, if you're looking to manage the inventory for common cloud platform, then there are already Dynamic Inventory scripts created.
I'll show how to use a Dynamic Inventory script to interact with AWS. However throughout the rest of the course, I'm going to use the inventory file for simplicity. To use the AWS Inventory script, you need to download it and configure some settings related to Access Tokens.
The Ansible documentation has a page on Dynamic Inventory. I'm going to jump down to the AWS section, and I'm going to download the Inventory script. There are two files required for Dynamic Inventory with AWS. The first is an executable that can fetch the inventory. And the second is an INI file that stores some settings.
I'll copy the Python file, and I'm going to paste it into a file called ec2.py. And I'll do the same thing for the Settings file. Part of the Settings file is to add the AWS access tokens. So, I'm going to paste those in here. And these are something that you can obtain from inside of the AWS console.
These are something that you really want to keep secret, however for the sake of the demo, I'm going to show them. Now the Dynamic Inventory script will know how to talk to the AWS API because it will have access through these access tokens.
So, let's test it out. When I used the Ansible command previously, I passed in the groups that I wanted to interact with. However here there's a slightly different syntax. Here you can use several variables, including things like tags that the VM might have. If you recall, I tagged all of the Linux machines with the same names. So I'll use this syntax here to target just the servers with a tag called Name, with a value of AnsibleDemo. In this case it's just those three Linux servers.
Now Ansible also needs to know how to use this new Dynamic Inventory. And for that you can use the -i flag, followed by the file name. And then like before, you can pass in the module for it to run. The first time this runs, it's going to take a while because it needs to populate the cache. However, running it after the first time will be faster. So, Dynamic Inventory tends to be a much more flexible way to handle inventory. Especially in the cloud.
Going forward for the ease of use, I'm going to switch back to just using the Static Inventory file. However, you'll now at least be familiar with the concept of Dynamic Inventory. You've probably noticed that every time I've run the Ansible command, I've had to specify some hosts to target. Ansible has a very flexible pattern matching syntax that allows to you target just the hosts that you need.
In the example so far, I've run the Ping module against the Lamp and Test groups. And to do that, I've combined the two groups with a colon. You can combine as many groups as needed. And you can use the special All syntax or an asterisk to have all of the hosts from your inventory. You can also use an exclamation point in front of a host name or group name to tell Ansible not to target those hosts. And you can use an ampersand to tell Ansible that you only want to target hosts that belong to two groups.
In this example, the host would need to belong to the Lamp and Test groups in order for the modules to be run against it. You could even use regular expressions to specify the host by starting the line with a tilde. So there's a lot of flexibility here, and it allows you to target just the hosts that you need.
Alright, let's wrap up this lesson. In the next lesson, I'll do a quick overview of configuring a Windows server so that Ansible can manage it. So if you're ready to keep learning, 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.