Ansible is an essential tool for server deployments, enabling quick repeatable deployments across multiple servers. It is similar to other tools such as:
Once you have installed Ansible, here's a rundown of the key concepts you'll use:
Playbooks are configuration files which specify which roles (specific deployment tasks) are run on which hosts (specific server instances listed in inventory files), and using which vars (variables which can be customised for each group of hosts or individual host).
Roles are collections of specific deployment tasks, such as installing Nginx, creating log directories, and anything else you require on a server. These typically also include default vars to be used, any template files that will be customised for each host, and any meta information which may require installing other roles as dependencies.
Hosts are specific server instances, often grouped into separate inventory files. For example, your "production" inventory file may list a web server host, database host, etc. I have used static inventory files in this article for simplicity, you may also consider Dynamic Inventory Configuration.
Vars are variables which may be customised for either groups of hosts (ie Group Vars) or a specific host (ie Host Vars). An example may be deploying a "staging" branch from your git repo to all hosts in the "staging" inventory file. These may be encrypted using Ansible Vault to protect any sensitive information from being included in your code repo.
I generally keep my ansible files in a similar structure advocated in the official Best Practices Guidelines, namely:
ansible /
playbooks /
start_servers.yml # Playbook to start servers
group_vars /
production # Group vars for the production environment
staging # Group vars for the staging environment
inventory /
production # List of hosts for production
staging # List of hosts for staging
roles /
webserver / # The webserver role, included in start_servers.yml playbook
defaults /
main.yml # Default vars which may be overridden by group_vars
files /
id_rsa # A static file copied to the server. These are not customized with vars.
meta /
main.yml # List any dependencies for this role
templates /
nginx.conf.j2 # A dynamic file customized with vars for each hosts. Always ends in .j2 extension.
tasks /
main.yml # Main task for this role, which typically includes other subtasks listed here.
01_create_dirs.yml # Subtask to create directories
02_install_nginx.yml # Subtask to install nginx
03_logging.yml # Subtask to configure logging
04_start_services.yml # Subtask to start all services
Here are some simplistic sample files from the tree structure listed previously.
# ansible/playbooks/start_servers.yml
---
- name: MySite | Webserver Playbook
hosts: webservers
sudo: true
roles:
- webserver
- caching # Another role, not shown in this article
- backup # Another role, not shown in this article
# ansible/group_vars/production
---
git:
branch: master
domain: my-site.com
use_pagerduty: True
# ansible/inventory/production
[webservers]
webserver01.mydomain.aws ansible_ssh_host=10.11.12.123
webserver02.mydomain.aws ansible_ssh_host=10.11.12.124
[database]
rds.master.mydomain.aws ansible_ssh_host=10.11.12.125
rds.slave.mydomain.aws ansible_ssh_host=10.11.12.126
# ansible/roles/webserver/defaults/main.yml
---
git:
branch: development # This gets overridden in group_vars
repo: ssh://git@github.com/my-git/my-repo.git
domain: my-site.com
use_pagerduty: False # This gets overridden in group_vars
nginx:
user: myuser
worker_processes: 4
# ansible/roles/webserver/meta/main.yml
---
dependencies:
- { role: logging } # Requires another role, which is not shown in this article
# ansible/roles/webserver/templates/nginx.conf.j2
user {{ nginx.user }};
worker_processes {{ nginx.worker_processes }};
pid /var/run/nginx.pid;
### Rest of nginx config file not shown ... #
# ansible/roles/webserver/tasks/main.yml
---
- name: Clone/pull from github
git: repo={{ git.url }} dest={{ path }} version="{{ git.branch }}" key_file="/home/{{ nginx.user }}/.ssh/id_rsa" accept_hostkey=yes force=yes
sudo_user: "{{ nginx.user }}"
tags:
- update
### Rest of task not shown ... #
With my configuration setup as described previously, I can now deploy a cluster of webservers in seconds by running:
ansible-playbook start_servers.yml -i inventory/production --ask-vault-pass
Note: The --ask-vault-pass option will prompt the user to enter the Ansible Vault password used for any encrypted vars files.