Skip to content

Instantly share code, notes, and snippets.

@thejhh
Last active July 13, 2020 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thejhh/b162d88f85a5dbd1517e83478314928f to your computer and use it in GitHub Desktop.
Save thejhh/b162d88f85a5dbd1517e83478314928f to your computer and use it in GitHub Desktop.

Extra Short Getting Started for Ansible

This page has multiple mini guides about using Ansible.

Start using Ansible

Eg. How to automate rsync package installation on multiple Debian/Ubuntu based hosts.

1. Install Ansible

You only need to do this step on the control system -- eg. the system from where you want to control other hosts.

sudo apt-get install ansible

Note! This guide is for a Debian based server. (I would recommend latest Ubuntu LTS.)

2. Create a list of your hosts

These are systems where you should be able to do ssh root@foo.example.com true succesfully. (You'll need SSH keys to make that happen easily.)

Create a file hosts:

[servers]
foo.example.com
bar.example.com

3. Create a playbook file

Create a file named install-rsync-playbook.yml:

---
- hosts: servers
  remote_user: root

  tasks:
   - name: Install rsync
     apt:
       name: rsync
       state: present

This playbook will install rsync on the remote system using apt module.

You can run it multiple times and it will only install rsync if it's missing from the target system.

Please note: Apt module requires that the target system must have Python installed. If you want to test Ansible without Python installed you can use command module -- or even use it to install Python!

4. Execute your playbook

ansible-playbook -i ./hosts install-rsync-playbook.yml

5. Profit!

That's all!

You probably have rsync installed on all of your systems now.

How to use variables to write dynamic tasks

You might have some stuff which is different on some systems and want a way to define that.

1. Create a file named hostvars.yml

all:
  vars:
    nginx_webroot: /var/www
    
  children:
    servers:
      vars:
        nginx_webroot: /var/www/default

  hosts:
    foo.example.com:
      nginx_webroot: /var/www/foo
    bar.example.com:
      nginx_webroot: /var/www/bar

This file defines that:

  • The variable nginx_webroot will default to /var/www
  • Except if the target host is part of servers group, then it is /var/www/default
  • Except if it is foo.example.com or bar.example.com, then /var/www/foo or /var/www/bar

You can also test your inventory:

ansible-inventory -i ./hosts -i ./hostvars.yml --host foo.example.com

2. Use your variable in a playbook

Now you can use this in a task like:

- name: Create a directory for webroot if it does not exist
  file:
    path: "{{ nginx_webroot }}"
    state: directory
    mode: '0755'

You may also define a default value into the task and remove defaults from the hostvars.yml:

- name: Create a directory for webroot if it does not exist
  file:
    path: "{{ nginx_webroot | default('/var/www') }}"
    state: directory
    mode: '0755'

You can use this syntax to define dynamic content to tasks almost anywhere on your YML file.

Fun Fact: The template engine here is called Jinja 2 and since it works using Python, you can use Python in it.

3. Excecute with -i ./hostvars.yml included in the command

ansible-playbook -i ./hosts -i ./hostvars.yml install-rsync-playbook.yml

Organize your tasks to multiple files

I would recommend to organize your tasks to different files instead of one big playbook.

This will help you upkeep your rules in the long run.

I find it also easier to copy paste rules from other sources when you don't have to fix the intention.

1. Create your task files

Create a file 01-install-rsync.yml:

- name: Install rsync
  apt:
    name: rsync
    state: present

Create a file 02-setup-nginx.yml:

- name: Create a directory for webroot if it does not exist
  file:
    path: "{{ nginx_webroot | default('/var/www') }}"
    state: directory
    mode: '0755'

2. Change your playbook to include it

---
- hosts: servers
  remote_user: root

  tasks:
   - import_tasks: ./01-install-rsync.yml
   - import_tasks: ./02-setup-nginx.yml

That's all.

If you need to disable ./01-install-rsync.yml temporarely, you can just comment that line out using the # prefix in your playbook.

Make Something Happen on Changes

You can define handlers to do stuff when something changes in your system.

1. Create a handler to restart nginx service

Create a file 99-restart-nginx.yml:

- name: Restart nginx
  service:
    name: nginx
    state: restarted

2. Create a file called handlers.yml

- import_tasks: ./99-restart-nginx.yml

This way you don't need to add new handlers to all of your playbooks!

3. Use handlers.yml in your playbook

---
- hosts: servers
  remote_user: root

  handlers:
   - import_tasks: ./handlers.yml

  tasks:
   - import_tasks: ./01-install-rsync.yml
   - import_tasks: ./02-setup-nginx.yml
  

4. Execute "Restart nginx" handler when a task changes something

- name: Create a directory for webroot if it does not exist
  file:
    path: "{{ nginx_webroot | default('/var/www') }}"
    state: directory
    mode: '0755'
  notify: Restart nginx

Now, Ansible will execute a handler called Restart nginx every time this specific task will end in a changed state.

Also if there's multiple tasks telling Ansible to execute Restart nginx, Ansible will only execute it once.

Note! The name of the handler is case sensitive: restart nginx is not same as Restart nginx!

Protip: You can use notify also in a handler to execute something else if the handler changes state.

What next?

1. Subscript & Star this gist

Click the buttons in the right top corner and you'll get notified when this page changes.

2. Give feedback

Don't hesitate to write a comment. Feedback is always welcome!

Eg. tell me about a new miniguide topic I could write here.

3. Share to your friends

Feel free to share this page on IRC, Matrix, Discord, Facebook, Twitter, Linkedin -- or any other website/app you people use these days. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment