Five servers, five different set-ups
A small company has five web servers. Different people set each one up by hand, over two years. One of them answers slowly and nobody can say why.
The cure is to write the set-up down in a file, and let a tool make every machine match it. When a server dies, you build the same one again in minutes.
By the end of this lesson
Note
I can write a playbook that sets up a machine and changes nothing the second time it runs.
Key words
| Word | What it means | Example |
|---|---|---|
| Playbook | a file that lists how machines should be set up | |
| Task | one step in a playbook | |
| Module | a built-in tool that a task uses | ansible.builtin.file |
| Inventory | the list of machines to manage | |
| Idempotent | safe to run again, because the second run changes nothing | |
| Template | a file with blanks that variables fill in |
The cells students fill in are left blank in this preview.
A playbook says how the machine should be
A playbook does not say "make a folder". It says "this folder must exist".
The tool looks at the machine, sees what is already right and fixes only what is wrong. You describe the end state. The tool finds the steps.
This VM holds a project folder. Move into it and read the files. The Runs share one terminal, so the move lasts.
Move into the project folder
cd ~/ansible-labShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Read the playbook
cat site.ymlShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Read the inventory
cat inventory.iniShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run it twice and nothing more changes
A task that is idempotent can run any number of times with the same result. The first run does the work. The second finds nothing to do.
Now try it. The next Run writes a small playbook of your own, practice.yml. It makes a folder and a note in /tmp. It sits beside site.yml and leaves it alone.
Write your own practice playbook
printf '%s\n' '- hosts: localhost' ' gather_facts: false' ' vars:' ' team: Finance' ' tasks:' ' - name: Make a notes folder' ' ansible.builtin.file:' ' path: /tmp/notes-demo' ' state: directory' ' - name: Write a note' ' ansible.builtin.copy:' ' dest: /tmp/notes-demo/note.txt' ' content: "Hello {{ team }}"' > practice.ymlShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run it the first time
ansible-playbook practice.ymlShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run it again
ansible-playbook practice.ymlShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think a playbook is a shell script written in YAML. A script does every step every time. A playbook module checks first and acts only when it must. Use the shell module only when no module exists, because it reports a change on every run.
A template fills blanks from variables
A template is a file with blanks, such as {{ site_name }}. A variable fills each blank when the file is made.
Change a variable and the file changes, with no editing by hand. You can set a variable on the command line with -e.
First read the lab's own template. Then change the team in your practice playbook.
Read the lab's template
cat templates/welcome.txt.j2Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run it with another team
ansible-playbook practice.yml -e team=SupportShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Dry run: what would change back?
ansible-playbook practice.yml --check --diffShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Read the note
cat /tmp/notes-demo/note.txtShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Going further
Write a second playbook, shell.yml, with one task that uses ansible.builtin.shell to run date > /tmp/notes-demo/stamp.txt. Run it twice and read the recap each time.
Then add args: with creates: /tmp/notes-demo/stamp.txt under the task and run it twice again. Explain what changed in the recap, and why.