Ansible Training
Ansible Training
Quiz - Pretest
• Please open this page for pre-test quiz
• https://forms.gle/pZ1ybsegpioKRJvw9
Get Access To Lab
• Connect to Wi-Fi: IBM-JTI
• Login with your VPN Username & Password
• Enter this command on cmd as administrator (Windows)
• route ADD 192.168.201.0 MASK 255.255.255.0 192.168.200.1
• Enter this command on terminal (MacOS)
• sudo route –n add -net 192.168.201.0/24 192.168.200.1
• Connect to JTI VPN (must have access first)
• Alternatively, create four CentOS 8 VM in your own laptop using
VirtualBox or similar software, connect them in one network (private
NAT)
Lab Access
• Each person will have 4 VMs
• Control Node
• Managed Node 1 -> ansible1
• Managed Node 2 -> ansible2
• Managed Node 3 -> ansible3
• Person 1 = ansible-training01-04
• Person 2 = ansible-training05-08
• IP Address: 192.168.201.1xx
• Where xx is the hostname number
Managed
Person Control Node Node
1 01 02 03 04
2 05 06 07 08
3 09 10 11 12
4 13 14 15 16
5 17 18 19 20
6 21 22 23 24
7 25 26 27 28
8 29 30 31 32
9 33 34 35 36
10 37 38 39 40
11 41 42 43 44
12 45 46 47 48
13 49 50 51 52
14 53 54 55 56
15 57 58 59 60
16 61 62 63 64
17 65 66 67 68
18 69 70 71 72
19 73 74 75 76
Lessons
• Installing Ansible
• Set Up Ansible Managed Environment
• Using Ad Hoc Commands
• Getting Started With Playbooks
• Working With Variables and Facts
What is Ansible?
• IT Automation System
• Configure System
• Deploy Software
• Rolling Update
• Many more
What is Ansible?
• Scripts on Steroids
• If we want to automate a task, we can script it and run it
• But what if we are running it on 10 server?
• No problem, we can log-in to each machine and it will take a short time
• But what about 100 servers? 500 servers? 1000 servers?
Ansible Concept
[fileservers] group
file1.example.com
file2.example.com
file3.example.com
[db]
ansible2
Testing The Inventory File
• ansible -i inventory all --list-hosts
• ansible -i inventory ungrouped --list-hosts
• No ungrouped hosts in the inventory file
• ansible all --list-hosts
• No inventory were specified (by default it will look at /etc/ansible/hosts)
Dynamic Inventory
• Static inventory is nice, but when we have a big environment, it will
be time consuming to maintain it
• Dynamic Inventory that can be used to discover inventory in dynamic
environments, such as cloud
• Many community-provided inventory scripts are available
• These scripts are used in the same way we use the Static Inventory,
but they must have execute permission
• You can easily write dynamic inventory scripts too
• https://github.com/ansible/ansible/tree/devel/contrib/inventory
Ansible Configuration Files
• ansible.cfg
[defaults]
inventory = inventory Look for inventory file named “inventory” in current working directory
remote_user = ansible User that ansible use for ssh
host_key_checking = false Disable the checks for ssh keys so ansible is more tolerant
[privilege_escalation]
become = True Run task as somebody else
become_method = sudo Method to do the privilege escalation
become_user = root Target user to become
become_ask_pass = False Do not ask for password when changing user
• Settings are organized into two sections
• [defaults] sets the default settings
• [privilege_escalation] specifies how Ansible runs commands on managed hosts
Connecting to Remote Hosts
• The default protocol to connect to the remote host is SSH
• Key based authentication is the common approach, but you can also use
password based auth
• To generate SSH keys, use ssh-keygen and use ssh-copy-id to copy the public
key to the managed hosts
• There are other methods as well:
• To manage Windows, use ansible_connection: winrm and ansible_port: 5986
• But if you are taking RHCE exam, Windows management is not part of the
objectives
Escalating Privileges
• sudo is the default mechanism, su can also be used but it’s
uncommon
• Password can also be asked for, but it’s more common to do a
password-less escalation
• echo “ansible ALL=(ALL) NOPASSWD: ALL” > /etc/sudoers.d/ansible
Localhost connection
• Ansible has an implicit localhost entry to run ansible commands
• Usually it’s the control node itself
• When connecting to localhost, the default become settings aren’t
going to be used, the account that ran the ansible command would be
used instead
• Ensure that the user has appropriate permission to sudo
Managing Ansible Config Files
• The ansible.cfg file is considered in order of precedence:
• /etc/ansible/ansible.cfg (default)
• ~/.ansible.cfg (if exists, will replace the default configured above)
• ./ansible.cfg (configuration in the current directory, will always take precedence
if exists)
• If ANSIBLE_CONFIG environment variable exists to refer to a specific
config file, then this will have the highest priority
• To check which file is being used, run ansible --version
• It makes more sense to put Ansible configuration in the project directory
because when you are managing Linux and Windows machine, the
configuration file will be different
Lab 2
• Create an environment with this requirement
• Set up a user named ansible management tasks on managed hosts: ansible1
& ansible2
• Inventory is set up on control host
• ansible.cfg configured with sudo privilege escalation
• SSH-key based login has been configured on ansible1 & ansible 2
• Skip ansible3 for now because we will use it in the next lab
Lesson 3
Using Ad Hoc
Commands
Using Ad Hoc Commands
• To run task on Ansible, typically we will use Playbooks
• A playbook is a YAML file in which tasks can be defined
• But for some tasks, a playbook is too complicated and too much work
• In such cases, we will use an ad-hoc command
• Ad hoc commands are also useful for testing if your playbooks are
successful
Understanding Ansible Modules
• As previously shown, modules is the key function in Ansible
• Ansible comes with a lot of modules that allow you to perform specific tasks on
managed hosts
• When using Ansible, you’ll always use modules to tell Ansible what you want it to
do, whether it’s in ad hoc commands or in a playbook
• By default Ansible has provided many modules, but you can also develop your own
• To list available modules, use this command: ansible-doc –l
• ansible-doc is like manpage for ansible modules, all the arguments needed for
each modules are explained there
• Modules are idempotent, meaning that when running them, it will give the same
result, if a task is already done, it won’t touch it.
Ad Hoc Commands Ingredients
• The basic structure is ansible hosts –m module [-a ‘module arguments’] [-i
inventory]
• The hosts part specifies on which host the command should be performed
• The module part indicates which ansible module to use; following the modules,
you can specify the module argument
• Inventory needs only be specified in the command if it’s not already exists
• Example:
• ansible all –m user –a “name=lisa”
• Run ansible in all host, run module user, with an argument name, value lisa
• It will create a user lisa in all ansible host (module user is used to create user)
• Verification: ansible all –m command –a “id lisa”
• It will run a shell command “id lisa” in all the hosts (module command is used to run shell commands in
each target machine)
Understanding Ansible Modules
• ansible all –m user –a “name=lisa state=absent”
• What does this command do?
• Verify the result with: ansible all –m command –a “id lisa”
Tip:
Don’t forget to set ansible.cfg & inventory!
Use ansible instead of manual SSH
Solution – Lab 3
• Create config file
vi /home/ansible/lab3/ansible.cfg
[defaults]
inventory=inventory
remote_user=ansible
host_key_checking=false
[privilege_escalation]
become=true
become_user=root
become_method=sudo
become_ask_pass=false
Solution – Lab 3
• Create inventory file
vi /home/ansible/lab3/inventory
[web]
ansible1
[db]
ansible2
ansible3
Solution – Lab 3
• Do the adhoc commands
• ansible –all –m ping
• ansible3 will fail
• ansible -u root –i inventory ansible3 --ask-pass -m raw –a “yum install
python3 –y”
• It will ask for SSH password
Lesson 4
Ansible Playbooks
Why Playbooks?
• Ad-hoc commands can be used to run one or few tasks
• Ad-hoc commands are convenient to test, or when a complete
managed infrastructure isn’t set up yet
• Ansible Playbooks are used to run multiple tasks against managed
hosts in a scripted way
• In Playbooks, one or multiple plays are started
• Each play runs one or more tasks
• In these tasks, different modules are used to perform the actual work
• Playbooks are written in YAML, with .yml or .yaml as their extension
YAML? What is That?
• An easy to read format to structure tasks / items that need to be
created
• In YAML files, items are using indentation with white spaces to
indicate the structure of data
• Data Elements at the same level should have the same indentation
• Child items are indented more than the parent items
• No strict requirement about the amount of spaces, but two spaces is
common
Example Playbook in YAML
---
- name : deploy vsftpd
hosts: ansible2.local
tasks:
- name: install vsftpd
yum: name=vsftpd
- name: enable vsftpd
service: name=vsftpd enabled=true
- name: create readme file
copy:
content: “free downloads for everybody!”
dest: /var/ftp/pub/README
force: no
mode: 0444
…
Running Playbook
• Use this command: ansible-playbook filename.yml
• A successful run requires the inventory and become parameters to be
set correctly, and also requires access to an inventory file
• The output of the ansible-playbook command will show what exactly
has happened
• Playbooks in general are idempotent; meaning that running the same
playbook again and again should produce the same result
• Warning: there are no easy way to undo changes made by a playbook
Example Output
[ansible@ansible-control lab4]$ ansible-playbook vsftpd.yml
PLAY [deploy vsftpd] ***********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible2]
TASK [install vsftpd] **********************************************************
changed: [ansible2]
TASK [enable vsftpd] ***********************************************************
changed: [ansible2]
TASK [create readme file] ******************************************************
changed: [ansible2]
PLAY RECAP *********************************************************************
ansible2 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Example Output 2
[ansible@ansible-control lab4]$ ansible-playbook vsftpd.yml
PLAY [deploy vsftpd] ***********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible2]
TASK [install vsftpd] **********************************************************
ok: [ansible2]
TASK [enable vsftpd] ***********************************************************
ok: [ansible2]
TASK [create readme file] ******************************************************
ok: [ansible2]
PLAY RECAP *********************************************************************
ansible2 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifying Playbook Syntax
• ansible-playbook --syntax-check filename.yml will perform a syntax check
• Use –v[vvv] to increase output verbosity
• -v will show task result
• -vv will show task results and configuration
• -vvv also shows information about connections to managed hosts
• -vvvv adds information about plug-ins, users that being used to run scripts, and
names of scripts that are executed
• Using –C option to perform a dry run, tries to do the playbook without
doing anything
• But if there is a dependency between the current task and the next task, it may
not run correctly
Writing A Multiple-Play Playbooks:
What is a Play?
• A play is a series of tasks that are executed against selected hosts from the
inventory, using specific credentials
• Using multiple plays allows running tasks on different hosts, using different
credentials from the same playbook
• Within a play definition, escalation parameters can be defined:
• remote_user: the name of the remote user
• become: to enable or disable privilege escalation
• become_method: to allow using alternative escalation solution
• become_user: The target user used for privilege escalation
• The parameters are similar with those in the ansible.cfg, but the parameters
defined in the playbook will take precedence before ansible.cfg
Example:
---
- name: enable webserver
hosts: ansible1
tasks:
- name: install httpd and firewalld
yum:
name:
- httpd
- firewalld
state: latest
- name: install welcome page
copy:
content: "hello world”
dest: /var/www/html/index.html
- name: start web services
service:
name: httpd
enabled: true
state: started
- name: start firewalld services
service:
name: firewalld
enabled: true
state: started
- name: open http port in firewalld
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
Tip: Use ansible-doc for getting references on how to use Ansible modules!
Solution – Install HTTPD
---
- name: enable web server
hosts: ansible2
tasks:
- name: install httpd
yum:
name: httpd
state: latest
- name: enabled httpd service
service:
name: httpd
state: started
enabled: true
- name: open firewall port
firewalld:
service: http
state: enabled
immediate: true
- name: create welcome message
copy:
content: Welcome to Ansible Demo
dest: /var/www/html/index.html
force: no
mode: 0644
...
Solution – Undo Changes
---
- name: disable web server
hosts: ansible2
tasks:
- name: remove welcome message
file:
path: /var/www/html/index.html
state: absent
- name: close firewall port
firewalld:
service: http
state: disabled
immediate: true
- name: disable httpd service
service:
name: httpd
state: stopped
enabled: false
- name: remove httpd
yum:
name: httpd
state: removed
...
- hosts: all
vars:
web_package: httpd
But, a better way to put the variables is to put it in a separate variable file, which will
be included from the Playbook
- hosts: all
vars_files:
- vars/users.yml
Defining Variables
• After defining variables, it can be used later in the playbook
• Notice that order does matter! The variable must be defined first
before the task
• Refer to the variable as {{ web_server }}
• If the variable is the only value, quotes are mandatory!
Example
---
- name: create a user using a variable
hosts: all
vars:
user: lisa
tasks:
- name: create a user {{ user }}
user:
name: "{{ user }}"
...
P.S: this is useless, for creating one user, just ditch the variable.
Understanding Variable Precedence & Scope
• Variables can be set with different types of scope
• Global scope: variable set from the inventory or the command line
• Play scope: applied when it is set from a play
• Host scope: This is applied when set in the inventory or using a host variable
inclusion file
• When the same variable is set at different levels, the most specific
level gets precedence
• When a variable is set from a command line, it will overwrite anything
else
• ansible-playbook site.yml –e “web_package=apache”
Understanding Built-In Variables
Some variables are built in and cannot be used for anything else:
• hostvars
• inventory_hostname
• inventory_hostname_short
• groups
• group_names
• ansible_check_mode
• ansible_play_batch
• ansible_play_hosts
• ansible_version
Be careful when naming variables! Variables like groups or group_names may be considered when you are
writing a playbook, take note that they are a built-in variables and you should be using other names such as
mygroups
Using Host Variables
• Variables can be assigned to hosts and to groups of hosts
• The old way of doing so is through inventory, but this is now
deprecated, because it mixes two types of information in one file
• Instead, you should use two directories to populate host and group
variables
Defining Host Variables Through Inventory
• A variable can be assigned directly to a host
[servers]
web1.example.com web_package=httpd
• group_vars/lamp content:
web_package: httpd
web_service: httpd
Example
• site.yml content:
---
- name: configure web services
hosts: lamp
tasks:
- name: this is the {{ web_package }} package
debug:
msg: "Installing {{ web_package }}"
- name: this is the {{ web_service }} package
debug:
msg: "Starting {{ web_service }} "
...
Understanding Multi-Valued Variables
• Arrays can be used as Variables
• When doing so, with_items can be used to refer to all values of the
variable
• Specific items in the array can be referred to using dotted notation
• This is common in Ansible facts
Example
• An example yaml file
---
- name: show arrays
hosts: ansible1.example.com
vars_files:
- vars/users
tasks:
- name: print array values
debug:
msg: "User {{ users.linda.username }} has homedirectory {{ users.linda.homedir }} and
shell {{users.linda.shell}} "
...
Example
• vars/users
users:
linda:
username: linda
homedir: /home/linda
shell: /bin/bash
lisa:
username: lisa
homedir: /home/lisa
shell: /bin/bash
anna:
username: anna
homedir: /home/anna
shell: /bin/bash
Using Ansible Vault – Dealing with Sensitive
Data
• Some modules require sensitive data to be processed
• This may include: webkeys, passwords, etc
• To process sensitive data in a secure way, Ansible vault can be used
• Ansible Vault is used to encrypt and decrypt files
• Command used: ansible-vault
Create an Encrypted File
• To create an encrypted file, use ansible-vault create playbook.yml
• This command will prompt for a new vault password, and opens the file in vi
for further editing
• Alternatively, a vault password file can be used, but the password file must be
protected in another way:
ansible-vault create --vault-password-file=vault-pass playbook.yml
• To view vault encrypted file, use ansible-vault view playbook.yml
• To edit, use ansible-vault edit playbook.yml
• Use ansible-vault encrypt playbook.yml to encrypt an existing file, and use
ansible-vault decrypt playbook.yml to decrypt it
• To change the password on an existing file, use ansible-vault rekey
Using Playbooks with Vault
• To run a playbook that accesses Vault encrypted files, you need to use
the --vault-id @prompt option to be prompted for password
• Alternatively, you can store the password as a single line string in a
password file, and access that using the --vault-password-file=vault-
file option
Managing Vault Files
• When setting up projects with Vault encrypted files, it makes sense to use separate
files to store encrypted and non-encrypted variables
• To store a host or host-group related variable files, you can use the following structure:
|-group_vars
| |--dbservers
| |- vars
| |- vault
• This replaces the solution that was discussed earlier, where all variables are stored in a
file with the name of the host or host group
Example
• create-user.yml
---
- name: create a user
hosts: all
vars_files:
- secret.yml
tasks:
- name: create user
user:
name: "{{ username }}"
password: "{{ pwhash }}"
...
Example
• ansible-vault create secret.yml
• Enter new password & confirm password
username: lisa
pwhash: password