Like all code, your infrastructure code has a certain grammar. When discussing Ansible in grammatical terms, the inventory is really the first noun you have to know (after all, nothing ever runs without defining some host(s) for Ansible to run it on). Along those same grammar lines, modules are basically your verbs. Almost everything you’ll ever do with Ansible will happen in the context of a module. Ansible has literally thousands of available modules, which is so many modules that evaluating what you can do makes deciding what you actually should do a bit overwhelming at times. And if you’re just starting to work with Ansible, where should you even begin all the learning?
To help you accelerate your learning process, here are 10 Ansible modules which should get you up and running– effectively and efficiently.
(BTW, looking for a quick video walkthrough on how to install Ansible in the first place? Check this out.)
Why only 10? And why these 10? Because whether you refer to it as the Pareto Principle or the “80/20 Rule”, in general it’s fairly well-established that we tend to get 80% of our results from only the top 20% of our toolset. In Level Up’s experience working with Ansible modules, this axiom definitely holds true. All of which means that yes, once you’ve been using Ansible for a while, you’ll likely be working with up to 50 (or even more) modules regularly. But we’re guessing that these first 10 modules will continue to be called upon early and often, and will serve you well on your journey to mastering Ansible.
Here’s the inventory file format that we assume you’ll be using for all of the playbooks given below (be sure to replace AA.BB.CC.DD, etc. with actual IP addresses):
[web]
AA.BB.CC.DD
WW.XX.YY.ZZ
1) command
There are several ways for Ansible to run programs on your remote hosts. However, using the command module is probably the most common way.
What to run in your terminal:
$ ansible-playbook -i inventory command_module_example.yml
---
- name: Command Module Example
hosts: web
tasks:
- name: Get uptime
command: uptime
register: result
- debug: var=result.stdout_lines
(The above playbook also introduces the the register-debug-var pattern, which we’ll explore in more detail below.)
2) copy
The copy module does what you think it does: it copies files and directories.
Imagine for a moment we want to copy an ssh config file to every AWS EC2 instance in the “web” group of remote hosts. Perhaps our ssh config file looks like this:
ssh_config example:
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ForwardAgent yes
And thus, a working playbook example might look like the below.
What to run in your terminal:
$ ansible-playbook -i inventory copy_module_example.yml
---
- name: Copy Module Example
hosts: web
tasks:
- name: Copy ssh config file
copy:
src: files/ssh_config
dest: /home/ec2-user/.ssh/config
owner: ec2-user
group: ec2-user
mode: 0600
3) template
Wait, another module that copies files?
Well, sometimes we want to copy a file as-is, and other times we want to make changes to the file before it lands on the remote host’s filesystem, possibly because of differences we find on individual hosts (differences like hostnames).
index.html.j2 example:
<html>
<head>
<title>Web server</title>
</head>
<body>
<h1>Hello World!</h1>
<p>Server: {{ my_hostname }}</p>
<body>
</html>
What to run in your terminal:
$ ansible-playbook -i inventory template_module_example.yml
---
- name: Template Module Example
hosts: web
vars:
my_hostname: "{{ ansible_nodename }}"
tasks:
- name: Write the index.html file
template:
src: templates/index.html.j2
dest: /var/www/html/index.html
(The above playbook also introduces Jinja2 templating as a concept and as a standard practice, one that you’ll be up to speed on in no time as you begin working with Ansible regularly.)
4) lineinfile
At least once in a while, you may find that neither copy nor template is the ideal module for you when it comes to making a particular change to a particular file. Maybe you don’t want to copy a new version of a file for whatever reason. And maybe you also don’t want to bring the file itself under version control the way a template file would require. In these cases, the lineinfile module might just be your best bet.
What to run in your terminal:
$ ansible-playbook -i inventory lineinfile_module_example.yml
---
- name: Lineinfile Module Example
hosts: web
tasks:
- name: Ensure that a feature toggle is ON
lineinfile:
path: /tmp/myapp.conf
regexp: '^FEATURE_TOGGLE=OFF'
line: 'FEATURE_TOGGLE=ON'
How often will you actually use lineinfile? Granted, perhaps not as often as copy or template. But part of our goal for including it here is to demonstrate Ansible’s inherent flexibility as an automation framework, as well as to hint at some of the implications for the greater OEM and community module ecosystem. Just remember: with Ansible, there’s DEFINITELY more than one way to do just about anything, and the only “right” way is yours.
5) file
Practically speaking, the file module is probably most helpful when it comes to things like creating directory structures, and modifying file permissions.
What to run in your terminal:
$ ansible-playbook -i inventory file_module_example.yml
---
- name: File Module Example
hosts: web
tasks:
- name: Create a new temp directory
file:
name: /tmp/mydir
state: directory
- name: Change the permissions of an existing file
file:
name: /etc/motd
mode: 0755
6) git
The git module includes a number of options for collaborating with other developers in shared repos, but below is a simplistic example.
What to run in your terminal:
$ ansible-playbook -i inventory git_module_example.yml
---
- name: Git Module Example
hosts: web
tasks:
- name: Clone a GitHub Repo
git:
repo: https://github.com/ansible/ansible-examples.git
dest: /tmp/ansible-examples
7) script
Ansible can do basically anything a scripting language can do. But one of the things that makes Ansible great is that it doesn’t have to! If you prefer handle certain tasks in, say, a Bash script, the script module is here for you.
setup.sh example:
#!/usr/bin/env bash
cd /opt
sudo wget https://www.python.org/ftp/python/3.7.9/Python-3.7.9.tgz
sudo tar xzf Python-3.7.9.tgz
cd Python-3.7.9
sudo ./configure --enable-optimizations
sudo make altinstall
sudo touch /home/ec2-user/bootstrapped.txt
What to run in your terminal:
$ ansible-playbook -i inventory script_module_example.yml
---
- name: Script Module Example
hosts: web
tasks:
- name: Install Python3
script: files/setup.sh
args:
creates: /home/ec2-user/bootstrapped.txt
(The above playbook is checking to see if a file named “bootstrapped.txt” already exists BEFORE it executes our script; if it finds this file, it doesn’t execute. This is a subtle but powerful example of what we mean when we say that Ansible is declarative: it won’t do work it doesn’t actually have to do, even when that work is calling some other program’s code.)
8) yum (or apt)
We are providing a RHEL-based example below, but whatever your OS, the general statement we are making here is that package management via Ansible is a highly-desirable skill to acquire.
What to run in your terminal:
$ ansible-playbook -i inventory yum_module_example.yml
---
- name: Yum Module Example
hosts: web
become: true
tasks:
- name: Install Apache
yum:
name: httpd
state: latest
9) service
We think it makes sense to introduce the yum and service modules back to back here, since the whole point of installing something like Apache is (usually) to get it running as well.
What to run in your terminal:
$ ansible-playbook -i inventory yum_and_service_modules_combined_example.yml
---
- name: Yum and Service Modules Combined Example
hosts: web
become: true
tasks:
- name: Install Apache
yum:
name: httpd
state: latest
- name: Start the Apache Service
service:
name: httpd
state: started
10) debug
The debug module is invoked a little differently than the others, but it’s invaluable to learn upfront, because it’s a great way to do things like print specific variables to your screen.
What to run in your terminal:
$ ansible-playbook -i inventory command_module_example.yml:
---
- name: Command Module Example (Again)
hosts: web
tasks:
- name: Get uptime
command: uptime
register: results
- debug: var=results.stdout_lines
(The above playbook implements the register-debug-var pattern. This pattern shows you how to store the response a module gets (register), then use the debug module to print this stored response as a variable to your screen– with formatting!)