-
Notifications
You must be signed in to change notification settings - Fork 4
Ansible Fundamentals
The very basics on how to get started with Ansible
Install Ansible on your workstation
- Install ssh key pair on your
workstation
andservers
- Generate ssh key-pair
# create a private key and a .pub public key ssh-keygen -t ed25519 -C "description" # follow the on-screen instructions to generate the ssh-key
- Add the generated ssh-keys to
known_hosts
ssh-add <keyname>
-
Dump/ copy
the public key to all the other servers to which the main ansible machine is going to talk to.
# comand to copy ssh public key from the main workstation to the server in order for the main server to talk to the target server ssh-copy-id -i ~/.ssh/<keyname>.pub <server-ip-or-hostname>
- List active keys:
ssh-add -L
- Remove an ssh-key:
ssh-add -D <keyname>
- Keep the private key on the workstation that the Ansible will use to ssh to other servers
- Add all the
IP
orHostnames
of the server you want ansible to connect to and work with - Dynamic Inventory is also supported in Ansible
- For Dynamic just get the server info from the cloud provider.
- In order to check the connection to all the servers from the main where ansible is installed
# create a file `inventory`
# this contains server hostnames and ips
10.0.0.136
pihole
# this will create a connection and check if we can connect to our servers
# here the path till ssh private is given and the key name is `ansible` (private key)
# inventory contains all the server ips to which using this key the ansible workstation is going to connect.
# -i is for the inventory file
# -m is for the module
ansible all --key-file ~/.ssh/<keyname> -i inventory -m ping
# To list all the hosts
ansible all --list-hosts
# Lists all the data/information of all the servers
# m is the module flag
ansible all -m gather_facts
# Lists all the data of a specific server
ansible all -m gather_facts --limit <server-ip-or-hostname>
The ansible.cfg
file can be used to setup some default values when running the ansible command.
NOTE: There is a default
ansible.cfg
file in/etc/ansible/
, but the one we create in our working dir will take priority over the one defined in/etc/ansible
.
# this file is read by ansible when we run it
[defaults]
inventory = <filename>
private_key_file = ~/.ssh/<filename>
This will help us shorten our ansible commands and avoid passing long command line options.
# previous command:
# ansible all --key-file ~/.ssh/<filename> -i inventory -m ping
# is shortened to:
ansible all -m ping
Output:
pihole | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
- Some commands which require sudo privileges to work with.
- Elevated privileges can be achieved using the below syntax.
# Tell ansible to use sudo (become) -> asks for password!
ansible all -m apt -a update_cache=true --become --ask-become-pass
# -m apt is for ubuntu/debian distros
Output:
BECOME password:
pihole | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"cache_update_time": 1695323800,
"cache_updated": true,
"changed": true
}
# Install a package named tmux via the apt module
# Equivalent to sudo apt-get install tmux
ansible all -m apt -a name=tmux --become --ask-become-pass
To check what command was run by ansible on all your servers, login to any one server, navigate to
/var/log/apt/history.log
file.
# Install a package via the apt module, and also make sure it’s the latest version available
ansible all -m apt -a "name=snapd state=latest" --become --ask-become-pass
# Upgrade all the package updates that are available
ansible all -m apt -a upgrade=dist --become --ask-become-pass
Learn more about apt modules here: ansible.builtin.apt module
- Before Ansible runs any playbooks or before running any commands on servers it will
First Gather Facts
and do the further things. - To disable fact gathering for a play, set the
gather_facts
key to no - Follow a proper directory structure for defining an ansible playbook. Ref
# create the playbook
---
- hosts: all
become: true
tasks:
- name: "install the apache2 package"
apt:
name: apache2
# Run the playbook
ansible-playbook --ask-become-pass install_apache.yml
- Lets say you 3 servers one for front end, second one contains some business logic as in REST API, and last one is a DB server
- So, we would have to target specific servers for specific configurations
- Need to create groups in inventory file, ex: one for
db_servers
,file_servers
,web_servers
# inventory_group file
[web_servers]
172.16.250.132
172.16.250.248
[db_servers]
172.16.250.133
[file_servers]
172.16.250.134
[workstations]
172.16.250.135
---
# target specific nodes
# ansible-playbook --ask-become-pass site.yml
# runs on all servers
- hosts: all
become: true
tasks:
# `pre_tasks:` can be used with roles when we want to mandate some things to run before others
- name: install updates (CentOS)
dnf:
update_only: true
update_cache: true
when: ansible_distribution = "CentOS"
- name: install updates (Ubuntu)
apt:
upgrade: dist
update_cache: true
when: ansible_distribution == "Ubuntu"
# runs only on web_servers defined in the `inventory` file
- hosts: web_servers
become: true
tasks:
- name: "install the apache2 and php package for Ubuntu"
apt:
name:
- apache2
- libapache2-mod-php
state: latest
when: ansible_distribution == "Ubuntu"
- name: "install the apache and php package for CentOS"
dnf:
name:
- httpd
- php
state: latest
when: ansible_distribution == "CentOS"
# runs only on db_servers defined in the `inventory` file
- hosts: db_servers
become: true
tasks:
- name: install mariadb package (CentOS)
dnf:
name: mariadb
state: latest
when: ansible_distribution == "CentOS"
- name: install mariadb package (Ubuntu)
apt:
name: mariadb-server
state: latest
when: ansible_distribution == "Ubuntu"
# runs only on file_servers defined in the `inventory` file
- hosts: file_servers
become: true
tasks:
- name: install samba package
package:
name: samba
state: latest
- To include multiple distros in a single task:
---
tasks:
- name: "update repository index"
apt:
update_cache: true
when: ansible_distribution in ["Debian", "Ubuntu"]
- We can make the above playbook even more modular and use variables in places for an easier configuration.
- Variables in the inventory
# inventory
172.16.250.132 apache_package=apache2 php_package=libapache2-mod-php
172.16.250.248 apache_package=apache2 php_package=libapache2-mod-php
172.16.250.133 apache_package=apache2 php_package=libapache2-mod-php
172.16.250.134 apache_package=httpd php_package=php
---
# ansible-playbook --ask-become-pass install_apache.yml
- hosts: all
become: true
tasks:
# Ubuntu server setup
- name: "install the apache2 and php package for Ubuntu"
apt:
name:
- "{{ apache_package }}"
- "{{ php_package }}"
state: latest
update_cache: true
when: ansible_distribution == "Ubuntu"
# CentOS server setup
- name: "install the apache and php package for CentOS"
dnf:
name:
- "{{ apache_package }}"
- "{{ php_package }}"
state: latest
update_cache: true
when: ansible_distribution == "CentOS"
We can further shorten our yaml
file to a single play by defining a single package
instead of 2 different plays for apt
and dnf
, for different distros.
- Using
package
Package is a module in ansible that is a generic package manager and it automatically uses the underlying package manager for the hosts or servers.
---
# ansible-playbook --ask-become-pass install_apache.yml
- hosts: all
become: true
tasks:
# Ubuntu server setup
- name: "install the apache and php"
package:
name:
- "{{ apache_package }}"
- "{{ php_package }}"
state: latest
update_cache: true
NOTE: It can be argued that
package
may or may not be the best way to handle multi-distribution linux shop since we are hard-coding the package names. But this again is scenario and admin based.
- Used to run
SPECIFIC TASK
in the playbook instead of running all the tasks for testing just one change in one task. - So, we dont need to run all the tasks just for one change in other task.
- We
Tag
all the tasks and then based on that tag we can run that particular task and skip all the other tasks.
---
# target specific nodes
# ansible-playbook --ask-become-pass site.yml
# runs on all servers
- hosts: all
become: true
tasks:
# `pre_tasks:` can be used with roles when we want to mandate some things to run before others
- name: install updates (CentOS)
tags: always
# dnf:
# update_only: true
# update_cache: true
# when: ansible_distribution = "CentOS"
- name: install updates (Ubuntu)
tags: always
# apt:
# upgrade: dist
# update_cache: true
# when: ansible_distribution == "Ubuntu"
# runs only on web_servers defined in the `inventory` file
- hosts: web_servers
become: true
tasks:
- name: "install the apache2 and php package for Ubuntu"
tags: apache,apache2, ubuntu
# apt:
# name:
# - apache2
# - libapache2-mod-php
# state: latest
# when: ansible_distribution == "Ubuntu"
- name: "install the apache and php package for CentOS"
tags: apache,centos,https
# dnf:
# name:
# - httpd
# - php
# state: latest
# when: ansible_distribution == "CentOS"
# runs only on db_servers defined in the `inventory` file
- hosts: db_servers
become: true
tasks:
- name: install mariadb package (CentOS)
tags: centos,mariadb
# dnf:
# name: mariadb
# state: latest
# when: ansible_distribution == "CentOS"
- name: install mariadb package (Ubuntu)
tags: ubuntu,db,mariadb
# apt:
# name: mariadb-server
# state: latest
# when: ansible_distribution == "Ubuntu"
# runs only on file_servers defined in the `inventory` file
- hosts: file_servers
become: true
tasks:
- name: install samba package
tags: samba
# package:
# name: samba
# state: latest
1. List all tags in a playbook
# List the available tags in a playbook
ansible-playbook --list-tags site_with_tags.yml
2. Run a playbook with a specific tag
# Examples of running a playbook but targeting specific tags
ansible-playbook --tags db --ask-become-pass site_with_tags.yml
ansible-playbook --tags centos --ask-become-pass site_with_tags.yml
ansible-playbook --tags apache --ask-become-pass site_with_tags.yml
3. Run a playbook with multiple tags
# target multiple tags
ansible-playbook --tags "apache,db" --ask-become-pass site_with_tags.yml
- You can copy files from Local System to all the other servers
- We can also download binaries like Terraform, Unzip, etc on a workstation locally or on other servers.
1. Example of copying file from local to all the web servers
# Example of copying file from local to all the web servers
- hosts: web_servers
become: true
tasks:
- name: copy html file for site
tags: apache,apache,apache2,httpd
copy:
src: default_site.html
dest: /var/www/html/index.html
owner: root
group: root
mode: 0644
2. Example of downloading binaries in local workstation
# Example of downloading binaries in local workstation
- hosts: workstations
become: true
tasks:
- name: install unzip
package:
name: unzip
- name: install terraform
unarchive:
src: https://releases.hashicorp.com/terraform/0.12.28/terraform_0.12.28_linux_amd64.zip # download link address
dest: /usr/local/bin # binary will be downloaded here
remote_src: yes # notify ansible that this package is from the internet and not a package manager
mode: 0755
owner: root
group: root
3. Run the playbook
ansible-playbook --ask-become-pass file_management.yml
- It is a module that can be used to start, stop, restart, or reload services on remote hosts. This is useful for managing the state of services, especially when deploying updates or changes.
# changes related to start httpd automatically and
# enabling it in case the server goes down to restart httpd automatically
- name: start and enable httpd (CentOS)
tags: apache,centos,httpd
service: # module to start/stop/restart/enable a service
name: httpd
state: started
enabled: yes
when: ansible_distribution == "CentOS"
# If the configuration file is changed and needs a restart so this is how it can be done
- name: change e-mail address for admin
tags: apache,centos,httpd
lineinfile: #module to be used to change a line
path: /etc/httpd/conf/httpd.conf # path to the file which is to be changed
regexp: '^ServerAdmin' # line begin with ServerAdmin
line: ServerAdmin [email protected] #replace that with this line
when: ansible_distribution == "CentOS"
register: httpd # variable declare that stores the state of httpd whether its changed or not
- name: restart httpd (CentOS)
tags: apache,centos,httpd
service:
name: httpd
state: restarted
when: httpd.changed # this play check if changed then run this which will restart the server
- Registered Variables -> One can capture the output of a command by using the register statement.
- The output is saved into a variable that could be used later for either debugging purposes or in order to achieve something else, such as a particular configuration based on a command's output.
- [WIP]
- They are executed only once.
- Executed at the very end.
- Create Roles basically an Ansible PlayBook only
- Add all the plays(tasks) in that particular role
- For example, you can add some Bootstrapping scripts as Plays like an apt-get update
- These types of roles can be used to set up a server which has nothing on it.
- So, this can actually download all the latest packages required by the system.
- Ansible’s
check
mode allows you to execute a playbook without applyingANY ALTERATIONS
to your systems. - You can use check mode to test playbooks before implementing them in a production environment.
-
Check
mode offers a safe and practical approach to examine the functionality of your playbooks without risking unintended changes to your systems. Moreover, it is a valuable tool for troubleshooting playbooks that are not functioning as expected.
ansible-playbook --check playbook.yaml