1. Core Elements of a Playbook:
hosts List of remote hosts to execute on
tasks Set of tasks
variables Built-in or custom variables called in the playbook
templates Files that can replace variables in template files and implement some simple logic
handlers Used in conjunction with notify, triggered by specific conditions, executed if conditions are met, otherwise not executed
tags Tags that specify which task to execute, used to select parts of the playbook to run; Ansible will automatically skip unchanged parts. Example: ansible-playbook -t tagname name.yml
remote_user: Can be used in hosts and tasks, and can specify to execute tasks on the remote host via sudo; applicable globally for the play or for a specific task.
Additionally, you can even use sudo_user to specify the user to switch to when using sudo.
Example:
- hosts: websrvs
remote_user: root # Optional, defaults to root. Connects as root.
tasks:
– name: test connection
ping:
remote_user: test
sudo: yes
sudo_user: dev
tasks: Tasks
Example:
tasks:
- name: taskname # Name the task
command: /bin/bash /root/test.sh # Module name: execute the corresponding parameters of this module
ansible-playbook –check name.yml Check for possible changes without actually executing; –check is the same as -C
ansible-playbook –list-hosts name.yml List the hosts that will run the tasks
ansible-playbook –list-tags name.yml List the tags
ansible-playbook –list-tasks name.yml List the tasks
ansible-playbook –limit host list name.yml Execute only on hosts in the host list
-v -vv -vvv Show execution process; the more v, the more detailed
Playbook to Install httpd
—
- hosts: all
remote_user: root
tasks:
- name: "Install Apache"
yum: name=httpd # yum module: install httpd
- name: "Copy configuration file"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/ # copy module: copy file
- name: "Copy configuration file"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "Start Apache and set to start on boot"
service: name=httpd state=started enabled=yes # service module: start service
Playbook to Create User
—
- hosts: all
remote_user: root
tasks:
- name: create mysql user
user: name=mysql system=yes uid=36
- name: create a group
group: name=httpd system=yes
Example Playbook to Install httpd Service
- hosts: websrvs
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configuration file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
- name: start service
service: name=httpd state=started enabled=yes
Example Playbook to Install nginx Service
- hosts: all
remote_user: root
tasks:
- name: add group nginx
group: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: Start Nginx
service: name=nginx state=started enabled=yes
Using Handlers in Playbooks
- hosts: websrvs
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configuration file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart httpd
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
- hosts: webnodes
vars:
http_port: 80
max_clients: 256
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: ensure apache is running
service: name=httpd state=started
- name: Install configuration file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart httpd # First way to use notify
handlers:
- name: restart httpd
service: name=httpd state=restarted
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
tags: user
group: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: config
copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
notify: # Second way to use notify
- Restart Nginx
- Check Nginx Process
handlers:
- name: Restart Nginx
service: name=nginx state=restarted enabled=yes
- name: Check Nginx process
shell: killall -0 nginx > /tmp/nginx.log
Using Tags in Playbooks
Tags: Add tags
You can specify a tag for a specific task, and after adding a tag, you can execute a certain action using the tag.
Multiple actions can use the same tag.
vim httpd.yml
- hosts: websrvs
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
tags: install
- name: Install configuration file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: conf
- name: start httpd service
tags: service
service: name=httpd state=started enabled=yes
ansible-playbook -t install,conf httpd.yml Specify to execute the install and conf tags
- hosts: hbhosts
remote_user: root
tasks:
- name: ensure heartbeat latest version
yum: name=heartbeat state=present
- name: authkeys configure file
copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys
- name: authkeys mode 600
file: path=/etc/ha.d/authkeys mode=600
notify:
- restart heartbeat
- name: ha.cf configure file
copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf
notify:
- restart heartbeat
handlers:
- name: restart heartbeat
service: name=heartbeat state=restarted
Using Tags in Playbooks
- hosts: testsrv
remote_user: root
tags: inshttpd # Add tags for the entire playbook
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configuration file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: rshttpd
notify: restart httpd
handlers:
- name: restart httpd
service: name=httpd status=restarted
ansible-playbook –t rshttpd httpd2.yml
Using Variables in Playbooks
Variable Sources:
1) The setup module can display a lot of system information in the system, returning system information for each host including: version, hostname, CPU, memory
ansible all -m setup -a 'filter="ansible_nodename"' # Query hostname
ansible all -m setup -a 'filter="ansible_memtotal_mb"' # Query memory size
ansible all -m setup -a 'filter="ansible_distribution_major_version"' # Query system version
ansible all -m setup -a 'filter="ansible_processor_vcpus"' # Query number of CPUs
2) Define variables in /etc/ansible/hosts (inventory)
Ordinary variables: Defined individually for hosts in the host group, with higher priority than public variables (single host)
Public (group) variables: Define unified variables for all hosts in the host group (same category of a group of hosts)
3) Specify variables via command line, with the highest priority
ansible-playbook -e varname=value
4) Define in the playbook
vars:
- var1: value1
- var2: value2
5) Define in a separate variable YAML file (vars.yml)
6) Define in roles
Variable Naming: Variable names can only consist of letters, numbers, and underscores, and must start with a letter.
Variable Definition: key=value
ep: http_port=80
Variable Calling Method:
1) Call variables using {{ var_name }}, ensuring there are spaces around the variable name; sometimes using "{{ var_name }}" is necessary for it to take effect.
2) Specify using the -e option
ansible-playbook test.yml -e "hosts=dev user=root"
Define variables in the inventory and use them in Ansible:
vim /etc/ansible/hosts
[appsrvs]
192.168.1.2 http_port=80 name=www
192.168.1.3 http_port=81 name=web
[appsrvs:vars] # Variables defined for the host group
ansible_ssh_user=root
ansible_ssh_pass=123456
mark="-"
Calling Variables:
ansible appsrvs -m hostname -a "name={{ name }}" # Change hostname to the defined name variable
ansible appsrvs -m hostname -a "name={{ name }}{{ mark }}{{ http_port }}" # Concatenate variables
Write variables into a separate configuration file for reference:
vim vars.yml
pack: vsftpd
service: vsftpd
Reference Variable File:
vars_files:
- vars.yml
Basic Elements of Ansible
Facts: Information returned by the remote target host that is communicating, stored in Ansible variables.
To obtain all facts supported by a specified remote host, use the following command:
ansible websrvs -m setup
When running a playbook, you can also pass some variables for the playbook to use:
ansible-playbook test.yml -e "hosts=www user=magedu"
register: Define the output of a task as a variable for use in other tasks
Example:
tasks:
- name: shell
shell: /usr/bin/foo
register: foo_result
ignore_errors: True
Example: Using Setup Variables
- hosts: websrvs
remote_user: root
tasks:
- name: create log file
file: name=/var/log/{{ ansible_fqdn }} state=touch
The ansible_fqdn variable can be viewed using:
ansible webserver -m setup | grep ansible_fqdn
Example: var.yml
- hosts: websrvs
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }} state=present
ansible-playbook –e “pkname=httpd” var.yml Variables passed via -e are separated by spaces.
Example: var.yml
- hosts: websrvs
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ username }} state=present
ansible-playbook var.yml # The created user and group are defined as user1 and group1 in the yml file
ansible-playbook -e "username=user2 groupname=group2” var2.yml # Variables passed via command line have the highest priority, so the created user and group are user2 and group2
Using Variable Files
cat vars.yml
var1: httpd
var2: nginx
vim log_create.yml
- hosts: web
remote_user: root
vars_files:
- vars.yml
tasks:
- name: create httpd log
file: name=/app/{{ var1 }}.log state=touch
- name: create nginx log
file: name=/app/{{ var2 }}.log state=touch
Group Nesting:
Groups can also contain other groups, and variables can be specified for hosts within the group.
These variables can only be used in ansible-playbook, while the ansible command does not support them.
Example:
[apache]
httpd1.magedu.com
httpd2.magedu.com
[nginx]
ngx1.magedu.com
ngx2.magedu.com
[websrvs:children]
apache
nginx
[webservers:vars]
ntp_server=ntp.magedu.com
Inventory Parameters
Inventory parameters: Used to define parameters for Ansible’s remote connection to target hosts, not variables passed to the playbook.
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansbile_sudo_pass
Example:
cat /etc/ansible/hosts
[websrvs]
192.168.0.1 ansible_ssh_user=root ansible_ssh_pass=magedu
192.168.0.2 ansible_ssh_user=root ansible_ssh_pass=magedu
host1 ansible_ssh_host=192.168.1.2 ansible_ssh_user=root ansible_ssh_pass=magedu # host1 is an alias
host2 ansible_ssh_host=192.168.1.[3:10] ansible_ssh_user=root ansible_ssh_pass=magedu # Can also represent multiple hosts
Template Example
Example: Use template to synchronize nginx configuration file
Prepare templates/nginx.conf.j2 file
vim temnginx.yml
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
Execute ansible-playbook temnginx.yml
Template Changes in Playbooks
Modify the file nginx.conf.j2 with the following line:
worker_processes {{ ansible_processor_vcpus }};
Algorithm Operations: Example:
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
worker_processes {{ ansible_processor_vcpus+2 }};
Implementing Conditional Judgments with When
Example:
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat" # Execute command module when the system belongs to the RedHat series
In the when statement, you can also use most of Jinja2’s “filters”. For example, to ignore errors from a previous statement and run subsequent specified statements based on its result (failed or success), you can use a form like this:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
Additionally, the when statement can use facts or variables defined in the playbook.
Example: When Conditional Judgment
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
tags: user
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: restart Nginx
service: name=nginx state=restarted
when: ansible_distribution_major_version == "6"
Example:
tasks:
- name: install conf file to centos7
template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
When Conditional Judgment in Playbooks
---
- hosts: srv120
remote_user: root
tasks:
- name:
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
Iteration: with_items
Iteration: Similar to loops
Iteration: When there are tasks that need to be executed repeatedly, you can use the iteration mechanism.
> Reference to iteration items, fixed variable name is “item”
> To use in the task, specify the elements list to iterate with with_items
> List format:
Strings
Dictionaries
Example: Create users testuser1 and testuser2
- name: add several users
user: name={{ item }} state=present group=wheel # {{ item }} is a user-defined variable
with_items: # Define values and counts for {{ item }}
- testuser1
- testuser2
Items in with_items can also be hashes.
Example:
- name: add several users
user: name={{ item.name }} state=present group={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
Ansible’s iteration mechanism has many more advanced features; please refer to the official documentation.
http://docs.ansible.com/playbooks_loops.html
Example: Copy multiple files to the controlled end.
---
- hosts: testsrv
remote_user: root
tasks:
- name: Create rsyncd config
copy: src={{ item }} dest=/etc/{{ item }}
with_items:
- rsyncd.secrets
- rsyncd.conf
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: src={{ item }} dest=/tmp/{{ item }}
with_items:
- file1
- file2
- file3
- name: yum install httpd
yum: name={{ item }} state=present
with_items:
- apr
- apr-util
- httpd
- hosts: websrvs
remote_user: root
tasks:
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
with_items nested sub-variables.
Example:
---
- hosts: testweb
remote_user: root
tasks:
- name: add several users
user: name={{ item.name }} state=present group={{ item.groups }}
with_items:
- { name: 'testuser1' , groups: 'wheel'}
- { name: 'testuser2' , groups: 'root'}
Playbook Dictionary with_items
- name: # Use ufw module to manage which ports need to be opened
ufw:
rule: "{{ item.rule }}"
port: "{{ item.port }}"
proto: "{{ item.proto }}"
with_items:
- { rule: 'allow', port: 22, proto: 'tcp' }
- { rule: 'allow', port: 80, proto: 'tcp' }
- { rule: 'allow', port: 123, proto: 'udp' }
- name: # Configure default rules for network ingress and egress
ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
state: enabled
with_items:
- { direction: outgoing, policy: allow }
- { direction: incoming, policy: deny }
Template for If When Loop in Playbooks
{% for vhost in nginx_vhosts %}
server { # Repeat server code
listen {{ vhost.listen | default('80 default_server') }};
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }};
{% endif %}
{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}
{% endfor %}
Example
// temnginx.yml
---
- hosts: testweb
remote_user: root
vars: # Call variables
nginx_vhosts:
- listen: 8080 # List key-value pairs
//templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
Generated Result:
server {
listen 8080
}
Example
// temnginx.yml
---
- hosts: mageduweb
remote_user: root
vars:
nginx_vhosts:
- web1
- web2
- web3
tasks:
- name: template config
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
// templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
}
{% endfor %}
Generated Result:
server {
listen web1
}
server {
listen web2
}
server {
listen web3
}