Ansible 101 - The basics
Ansible is an open-source tool for automating infrastructure and application deployment, using simple YAML language. It's used to manage and automate tasks across multiple servers and devices.
It uses simple, human-readable language (YAML) to describe tasks and configurations, and can be used to manage and automate the deployment, configuration, and management of various systems and applications. Ansible allows you to automate tasks such as software installation, configuration changes, and service management across a large number of servers and devices with minimal effort. It is often used in DevOps and IT operations to improve efficiency and reduce errors.
Most of the content of this blog post came from another blog post I wrote about Ansible. It's a great place to start, with many links with awesome content made by the community and by Red Hat, all of them for free:
1. Ansible world overview
---
markmap:
zoom: false
pan: false
---
# Ansible
## [Documentation](https://docs.ansible.com/)
## [Ansible Core](https://docs.ansible.com/core.html)
- ansible
- ansible-playbook
- ansible-vault
- ...
## [Ansible Automation Platform (AAP)](https://www.redhat.com/en/technologies/management/ansible)
- Automation Controller (AWX)
- Automation Hub (pulp)
## [Content Creator tools](https://www.ansible.com/content-tools#:~:text=Ansible%C2%AE%20content%20tools%20are,exact%20Ansible%20content%20they%20need.)
- ansible-navigator
- ansible-lint
## [Community](https://hackmd.io/@ansible-community)
- [Chat at Matrix](https://hackmd.io/@ansible-community/community-matrix-faq)
- [Ansible Galaxy (collections repo)](https://galaxy.ansible.com/)
2. How to install Ansible
Reference: https://docs.ansible.com/ansible/latest/installation_guide/index.html
You can install Ansible using some package manager, like dnf
or brew
, but you can also use pip
to get the latest version.
Example using pip
:
# Create a virtual environment
python3 -m venv venv
# Enable the virtual environment
source ./venv/bin/activate
# Install ansible
pip install ansible
3. The YAML sintax
Reference: https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
Ansible uses the YAML structure. So, it's important to know:
- dict/map
- string (inline, multiline)
- number
- bool
- list
4. My first playbook
Reference: https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html
When you install the ansible
package, a few CLIs will become available, one of them is the ansible-playbook
. You can use it to directly run the playbook:
# Create the my-playbook.yaml file
vim my-playbook.yaml
# Run the playbook
ansible-playbook \
-e custom_message="I like coffee" \
my-playbook.yaml
# ./my-playbook.yaml
- name: My first playbook to run on the localhost
hosts: localhost
connection: local
# Example of map
vars:
show_message: false
custom_message: I like Pokémon
tasks:
- name: My debug task
debug:
msg: |
The custom_message value is: {{ custom_message }}
{% if show_message %}
hey!
{% endif %}
5. Converting a bash script into an Ansible Playbook
Create an automation with a bash script
- Create a directory
- Create a text file with the current datetime
- Compress the file
- Output the file name
#!/bin/bash
OUTPUT_DIR=$(pwd)/output
mkdir -p ${OUTPUT_DIR}
date > ${OUTPUT_DIR}/time.log
cd ${OUTPUT_DIR}
tar -cvf time.log.tar time.log
echo
echo "output file: $(pwd)/time.log.tar"
Create a playbook that invokes the bash script
# Documentation here
---
- name: Run script
hosts: localhost
connection: local
tasks:
- name: Create output dir
shell: |
OUTPUT_DIR=$(pwd)/output
mkdir -p ${OUTPUT_DIR}
date > ${OUTPUT_DIR}/time.log
cd ${OUTPUT_DIR}
tar -cvf time.log.tar time.log
echo
echo "output file: $(pwd)/time.log.tar"
Convert each bash script step into Ansible native modules
# Documentation here
---
- name: Compress datetime file
hosts: localhost
connection: local
tasks:
- name: Create output dir
file:
path: "{{ playbook_dir }}/output"
state: directory
- name: Create a file with the date
copy:
content: "{{ ansible_date_time.epoch }}"
dest: "{{ playbook_dir }}/output/time.log"
- name: Compress time.log
archive:
path: "{{ playbook_dir }}/output/time.log"
dest: "{{ playbook_dir }}/output/time.log.gz"
format: gz
- name: Show time.log file path
ansible.builtin.debug:
msg: "{{ playbook_dir }}/output/time.log"
6. Run Ansible against a remote instance
How to connect to a remote instance
Create an inventory file:
# ./inventory
[minecraft-servers]
192.168.11.22
[minecraft-servers:vars]
custom_message="This message came from the inventory file"
Create the playbook:
# ./remote-playbook.yaml
- name: Connecting to a remote instance
hosts: minecraft-servers
connection: local
# Example of map
vars:
custom_message: I like Pokémon
tasks:
- name: My debug task
debug:
msg: "The custom_message value is: {{ custom_message }}"
Run the playbook against the remote instance:
# Test your SSH connection against your host
ssh [email protected]
# Create the inventory file
vim ./inventory
# Create the playbook
vim ./remote-playbook.yaml
# Run the playbook
ansible-playbook -i ./inventory ./remote-playbook.yaml
How to add your GitHub pub keys to the SSH authorized_keys file
- hosts: all
vars:
github_users:
- thenets
machine_user: ec2-user
tasks:
- name: Add the GitHub user's public keys to the authorized_keys file
ansible.posix.authorized_key:
user: "{{ machine_user }}"
key: https://github.com/{{ item }}.keys
become: true
loop: "{{ github_users }}"
Cheatsheet
Tricks
- Dynamicaly set env variable
- name: Set var in real time
set_fact:
current_time: "{{ lookup('pipe', 'date +%Y-%m-%d_%H-%M-%S') }}"
Full playbook example
---
- name: Basic Playbook for working with files
# cat /etc/hosts - use this in terminal to see list of available hosts
hosts: localhost
# SSH is the default connection unless you are running in your own computer
connection: local
vars:
luiz_filename: luiz_loves_shrimp
other_filename: other_file
my_directories: ./foo/bar/
tasks:
# Google for "ansible 'something' module"
- name: Creating a file
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html
ansible.builtin.file:
path: "{{ luiz_filename }}"
# about state parameter:
#https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html#parameter-state
state: touch
# aboput registering the output of the task
# https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables
register: created_file
# Returned values of file module
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html#return-values
- name: Debugging registered variable
ansible.builtin.debug:
msg: "{{ created_file }}"
# Fail module to stop the execution at this point (uncomment)
# - ansible.builtin.fail:
# when: created_file.owner != "sakus"
- name: Creating all the directories in the path
ansible.builtin.file:
path: "{{ my_directories }}"
#set state to absent to remove anything
state: directory
recurse: true
- name: Creating a file
ansible.builtin.file:
path: "{{ other_filename }}"
state: touch
- name: Removing a file
ansible.builtin.file:
path: "{{ other_filename }}"
# set state to absent to remove anything
state: absent