Chapter 5
Learning to write Infrastructure as a Code
even though ansible allows us to run ad hoc commands and modules on remote nodes, the real magic starts with the Playbooks
Playbooks allow one to describe the state of the infrastructure and the sequence in which it is achieved ....
as Infrastructure Code
which can then be version controlled and reused many times for many different environments
playbook
Ansible
with intention of being both
as well as
All YAML files to begin with three dashes ---
---
# This is a YAML Document
- list item 1
- list item 2
...
and end with three dots ...
even though its not a must, its a good coding practice to follow this
Ansible plays contain list of items e.g. tasks, hosts, options
---
- name
hosts
become
tasks
- package
- file
- user
...
Ansible plays contain list of items e.g. tasks, hosts, options
---
- name: configure app hosts
hosts: app
become: true
tasks
- package: name=apache state=present
- copy: name=ntp.conf src=files/ntp.conf dest=/etc/ntp.conf
- user: name=dojo state=present
...
with key value pairs commonly known as hashes or dictionaries
all members of the list are at the same indentation level
---
- name: configure app hosts
hosts: app
become: true
tasks
- package: name=apache state=present
- copy: >
name=ntp.conf
src=files/ntp.conf
dest=/etc/ntp.conf
- user: |
name=dojo
uid=5001
home=/home/dojo
state=present
...
> |
---
- name: configure app hosts
hosts: app
become: true
tasks
- package: name=apache state=present
- copy:
name: ntp.conf
src: files/ntp.conf
dest: /etc/ntp.conf
- user:
name: dojo
uid: 5001
home: /home/dojo
state: present
...
:
src: http://www.india.com/buzz/this-precise-grocery-shopping-list-of-an-indian-wife-for-her-husband-will-make-you-laugh-like-crazy-2496164/
WHICH hosts
do WHAT
describe
hosts, vars, become
name
hosts
become
vars
tasks
name
hosts
become
vars
tasks
- name: App Server Configurations
hosts: app
become: true
become_user: admin
become_method: sudo
vars:
apache_port = 8080
max_conections = 4000
ntp_conf = /etc/ntp.conf
tasks:
- name: create app user
user: name=app state=present uid=5002
- name: install git
yum: name=tree state=present
think of sudo
used to run tasks as a different user / become another user
introduced in version 1.9 and supercedes sudo / su
supports sudo, su, pfexec, doas, pbrun, dzdo, ksu and others
Components of Plays which define the desired state of / action taken on a system entity
there is a 1-1 mapping between the task and the system entity managed
tasks invoke modules which are encapsulated procedures to take actions.
modules are also called as task plugins
- name: install ntp package yum: name=ntp state=present
- yum: name=ntp state=present
- name: create dojo user user: > name=dojo uid=5001 home=/home/dojo state=present
- name: create dojo user user: | name=dojo uid=5001 home=/home/dojo state=present
- name: create dojo user user: name: dojo uid: 5001 home: /home/dojo state: present
---
- name: Base Configurations for ALL hosts
hosts: all
become: true
tasks:
- name: create admin user
user:
name: admin
state: present
uid: 5001
- name: remove dojo
user:
name: dojo
state: absent
- name: install tree
yum:
name: tree
state: present
- name: install ntp
yum:
name: ntp
state: present
- name: start ntp service
service:
name: ntpd
state: started
enabled: yes
- name: App Server Configurations
hosts: app
become: true
tasks:
- name: create deploy user
user:
name: deploy
state: present
uid: 5003
- name: install git
yum:
name: git
state: present
play1
play2
cd ansible-bootcamp-code/chap5
ansible all -m ping
switch to chap5 code and validate
You have to create a playbook for base systems configuration. Common configurations for all hosts are,
admin user should be present with uid 5001
user dojo should not have an account on any host
install tree utility
install ntp
on all systems which belong to prod group in the inventory
Lets now create systems.yml file and start adding our first play
---
- name: Base Configurations for ALL hosts
hosts: all
become: true
tasks:
- name: create admin user
user:
name: admin
state: present
uid: 5001
- name: remove dojo
user:
name: dojo
state: absent
- name: install tree
yum:
name: tree
state: present
- name: install ntp
yum:
name: ntp
state: present
file: systems.yml
ansible-playbook systems.yml --syntax-check
Syntax Check
Exercise: Break the syntax, run playbook with --syntax check again, and learn how it works.
http://www.yamllint.com
Another way to validate syntax
# ansible-playbook --help
Usage: ansible-playbook playbook.yml
Options:
--ask-vault-pass ask for vault password
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON
--flush-cache clear the fact cache
--force-handlers run handlers even if a task fails
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory-file=INVENTORY
specify inventory host path (default=myhosts.ini) or
comma separated host list.
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
--list-tags list all available tags
--list-tasks list all tasks that would be executed
ansible-playbook --help
ansible-playbook systems.yml --list-tasks
List Hosts to which this playbook applies
ansible-playbook systems.yml --list-hosts
List Tasks
ansible-playbook systems.yml --list-tags
List Tags
Lets now add a new task to systems.yml to
start ntp service
---
- name: Base Configurations for ALL hosts
hosts: all
become: true
tasks:
- name: create admin user
user:
name: admin
state: present
uid: 5001
- name: remove dojo
user:
name: dojo
state: absent
- name: install tree
yum:
name: tree
state: present
- name: install ntp
yum:
name: ntp
state: present
- name: start ntp service
service:
name: ntp
state: started
enabled: yes
File: systems.yml
TASK [start ntp service] ******************************************************
*
changed: [app2]
fatal: [app1]: FAILED! => {"changed": false, "failed": true, "msg": "no service
or tool found for: ntp"}
fatal: [lb]: FAILED! => {"changed": false, "failed": true, "msg": "no service o
r tool found for: ntp"}
fatal: [db]: FAILED! => {"changed": false, "failed": true, "msg": "no service o
r tool found for: ntp"}
to retry, use: --limit @/tmp/playbook.retry
PLAY RECAP ********************************************************************
*
app1 : ok=5 changed=0 unreachable=0 failed=1
app2 : ok=6 changed=1 unreachable=0 failed=0
db : ok=5 changed=0 unreachable=0 failed=1
lb : ok=5 changed=0 unreachable=0 failed=1
ansible-playbook systems.yml
status = failed
retry step
root@control:/workspace/chap5# ansible-playbook systems.yml --step
PLAY [Base Configurations for ALL hosts] ***************************************
Perform task: TASK: setup (N)o/(y)es/(c)ontinue: y
TASK [setup] *******************************************************************
y
ok: [app1]
ok: [db]
ok: [app2]
ok: [lb]
Perform task: TASK: create admin user (N)o/(y)es/(c)ontinue:
TASK [create admin user] *******************************************************
yok: [app2]
ok: [app1]
ok: [db]
ok: [lb]
Perform task: TASK: install tree (N)o/(y)es/(c)ontinue: y
TASK [install tree] ************************************************************
ok: [app2]
ok: [lb]
ok: [app1]
ok: [db]
ansible-playbook systems.yml --step
You could also do step by step execution of tasks by using --step option
package : ntp => chrony service : ntpd => chronyd
TASK [install ntp] ************************************************************************************************************
fatal: [app1]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [lb]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [app2]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [db]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [localhost]: FAILED! => {"ansible_facts": {"pkg_mgr": "apt"}, "changed": false, "msg": "value of state must be one of: absent, build-dep, fixed, latest, present, got: installed"}
PLAY
Root Cause : NTP is not supported on Centos 8, its been replaces with chrony
---
- name: Base Configurations for ALL hosts
hosts: all
become: true
tasks:
- name: create admin user
user:
name: admin
state: present
uid: 5001
- name: remove dojo
user:
name: dojo
state: absent
- name: install tree
yum:
name: tree
state: present
- name: install chrony
yum:
name: chrony
state: present
- name: start chrony service
service:
name: chronyd
state: started
enabled: yes
File: systems.yml
ntp => chrony ntpd => chronyd
TASK [install chrony] *************************************************************
ok: [lb]
ok: [app1]
ok: [app2]
ok: [db]
PLAY RECAP *********************************************************************
app1 : ok=6 changed=1 unreachable=0 failed=0
app2 : ok=6 changed=1 unreachable=0 failed=0
db : ok=6 changed=1 unreachable=0 failed=0
lb : ok=6 changed=1 unreachable=0 failed=0
ansible-playbook systems.yml --limit @/tmp/playbook.retry
Add a new play to existing playbook which will,
create a deploy user with uid 5003
install git
on all app servers in the inventory
Setup app Servers
---
- name: Base Configurations for ALL hosts
hosts: all
become: true
tasks:
- name: create admin user
user:
name: admin
state: present
uid: 5001
- name: remove dojo
user:
name: dojo
state: absent
- name: install tree
yum:
name: tree
state: present
- name: install ntp
yum:
name: ntp
state: present
- name: start ntp service
service:
name: ntpd
state: started
enabled: yes
- name: App Server Configurations
hosts: app
become: true
tasks:
- name: create deploy user
user:
name: deploy
state: present
uid: 5003
- name: install git
yum:
name: git
state: present
File: systems.yml
play1
play2
PLAY [Base Configurations for ALL hosts] ***************************************
TASK [setup] *******************************************************************
ok: [localhost]
ok: [192.168.61.14]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]
TASK [create admin user] *******************************************************
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]
TASK [remove dojo] *************************************************************
ok: [192.168.61.14]
ok: [192.168.61.12]
ok: [192.168.61.11]
ok: [localhost]
ok: [192.168.61.13]
TASK [install tree] ************************************************************
ok: [192.168.61.11]
ok: [192.168.61.12]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.14]
TASK [install ntp] *************************************************************
ok: [192.168.61.12]
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [192.168.61.11]
ok: [localhost]
TASK [start ntp service] *******************************************************
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.11]
ok: [192.168.61.12]
PLAY [App Server Configurations] ***********************************************
TASK [setup] *******************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]
TASK [create app user] *********************************************************
changed: [192.168.61.12]
changed: [192.168.61.13]
TASK [install git] *************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]
PLAY RECAP *********************************************************************
192.168.61.11 : ok=6 changed=0 unreachable=0 failed=0
192.168.61.12 : ok=9 changed=1 unreachable=0 failed=0
192.168.61.13 : ok=9 changed=1 unreachable=0 failed=0
192.168.61.14 : ok=6 changed=0 unreachable=0 failed=0
localhost : ok=6 changed=0 unreachable=0 failed=0
ansible-playbook systems.yml
You have to limit execution of the tasks
only to app servers
irrespective of host groups playbook defines
PLAY [Base Configurations for ALL hosts] ***************************************
TASK [setup] *******************************************************************
ok: [localhost]
ok: [192.168.61.14]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]
TASK [create admin user] *******************************************************
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]
TASK [remove dojo] *************************************************************
ok: [192.168.61.14]
ok: [192.168.61.12]
ok: [192.168.61.11]
ok: [localhost]
ok: [192.168.61.13]
TASK [install tree] ************************************************************
ok: [192.168.61.11]
ok: [192.168.61.12]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.14]
TASK [install ntp] *************************************************************
ok: [192.168.61.12]
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [192.168.61.11]
ok: [localhost]
TASK [start ntp service] *******************************************************
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.11]
ok: [192.168.61.12]
PLAY [App Server Configurations] ***********************************************
TASK [setup] *******************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]
TASK [create app user] *********************************************************
changed: [192.168.61.12]
changed: [192.168.61.13]
TASK [install git] *************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]
PLAY RECAP *********************************************************************
192.168.61.11 : ok=6 changed=0 unreachable=0 failed=0
192.168.61.12 : ok=9 changed=1 unreachable=0 failed=0
192.168.61.13 : ok=9 changed=1 unreachable=0 failed=0
192.168.61.14 : ok=6 changed=0 unreachable=0 failed=0
localhost : ok=6 changed=0 unreachable=0 failed=0
ansible-playbook systems.yml --limit app
Nano Project 1: Deploy a static html site Create a Playbook website.yml with the following specifications,
It should apply only on lb (load balancer) host
Should use become method
Should add a repository (yum_repository) for nginx with gpgcheck=no and
baseurl=http://nginx.org/packages/centos/6/x86_64/
Should install and start nginx service
Should deploy a sample html app into the default web root directory of nginx using ansible's git module.
Source repo: https://github.com/schoolofdevops/html-sample-app.git
Deploy Path : /usr/share/nginx/html/app
Once deployed, validate the site by visiting http://codebox_ip/app
Lab Exercise 2: Disable Facts Gathering
Run ansible playbook and observe the output
Add the following configuration parameter to ansible.cfg gathering = explicit
Launch ansible playbook run again, observe the output and compare it with the previous run.
Lab Exercise 3:
While running playbook, execution should start at the following task onwards. Find out and use option applicable to ansible-playbook which will achieve this.
Task Name: "install ntp"