Skip to content

kapsali29/AnsibleTutorial

Repository files navigation

Setup SSH keys

Firstly we need to create a key that Ansible needs to use ssh-keygen

ssh-keygen -t rsa -b 4096 -C "this is the ansible key no passphrase"

You will be prompted to specify a file to save the key, it is recommended not to use the default we used the following: ~/.ssh/ansible

Finally you need to copy the public key to the remote server an example is the following piece of code

ssh-copy-id -i ~/.ssh/ansible.pub [email protected]

How to setup Ansible

Ansible Gathering Facts

In order to fetch information from a node we need to execute the following commands

ansible $host-alias -m setup

ansible server1 -m setup

These variables will retrieve variables related to a specific node. All variables are prefixed with the ansible_ substring

In order to limit the facts gathered a common practice is to use filters

ansible $host-alias -m setup -a 'filter=${filter_arg}'

ansible server -m setup -a 'filter=ipv4'

some useful filters are:

  • ansible_mem*
  • ansible_eth*
  • ansible_os*

Inventory

Inside the inventory we declare the host information

vmware:  
  hosts:  # Define hosts under this group
    server1:
      ansible_host: 192.168.128.133
      ansible_user: ubuntu

Ansible config

Inside this file we declare configuration information for the ansible playbook

[defaults]
inventory = inventory.yaml
private_key_file = ~/.ssh/ansible

Playbooks

How to execute a playbook

ansible-playbook test_playbook.yaml

If you need to manually provide the sudo password during playbook execution, you can use the --ask-become-pass flag. This will prompt you for the password at the start of the playbook run.

ansible-playbook test_playbook.yaml --ask-become-pass

---
- name: one test playbook
  hosts: vmware
  become: yes

  tasks:
  - name: execute a hello world in shell
    shell: echo "Hello Malaka"

Anasible Vault

Ansible Vault is a feature that allows you to encrypt sensitive data, such as passwords or API keys, and keep them safe when managing infrastructure with Ansible. You can create, edit, view, and use encrypted files with ansible-vault. Here’s a step-by-step example of how to use Ansible Vault.

Firstly we need to create the file that will store the secrets

ansible-vault create secrets.yaml

Edit an ecrypter vault file

ansible-vault edit secrets.yaml

View the contents of a vault file

ansible-vault view secrets.yaml

Encrypt secret from existing YAML file ansible-vault encrypt myfile.yml

Use secrets to a playbook

ansible-playbook test_playbook.yaml --ask-vault-pass

ansible-playbook test_playbook.yml --vault-password-file ~/.vault_password.txt

---
- name: one test playbook
  hosts: vmware
  become: yes
  vars_files:
   - secrets.yaml

  tasks:
  - name: execute a hello world in shell
    shell: echo "Hello Malaka"
  
  - name: run docker ps -a command
    shell: docker ps -a
  
  - name: print secrets.yaml
    debug:
     msg: this is the password {{dbpass}} {{dbuser}}

APT Module

When you want to install packages, remove them or update cache apt module is the prefered way to do so

Update cache

- name: one test playbook
  hosts: vmware
  become: yes
  vars_files:
   - secrets.yaml

  tasks:
  - name: execute a hello world in shell
    shell: echo "Hello Malaka"
  
  - name: run docker ps -a command
    shell: docker ps -a
  
  - name: print secrets.yaml
    debug:
     msg: this is the password {{dbpass}} {{dbuser}}

  - name: update cache
    apt:
      update_cache: yes

Install package

Install one package

  - name: update cache
    apt:
        name: apache2
        state: latest

Install more than one packages in one play

  - name: update cache
    apt:
      name: 
        - apache2
        - jq
      state: latest

How to control different hosts using Host groups

In order to execute a scenario with different handling on the hosts we need to update our inventory.yaml we added an extra VM called client and the updated inventory right now is listed below:

webservers:
  hosts:  # Define hosts under this group
    server1:
      ansible_host: 192.168.128.133
      ansible_user: ubuntu
      my_pack: apache2
      the_pack: jq
clients:
  hosts:
    server2:
      ansible_host: 192.168.128.131
      ansible_user: ubuntu

About Hosts

When we want to perform tasks for all hosts we need to identify the playbook using the all notation.

- hosts: all
  become: yes

If we want to select a specific group we need to identify the group name in the playbook hosts: webservers

- hosts: webservers
  become: yes

Below we put the playbook we created for our case. As you can notice in the same file we can have more than one playbooks.

pre_tasks notation is used to indicate the tasks need to be executed before everything else. Like Init commands

- hosts: all
  become: yes
  pre_tasks:
    - name: show your distributions
      debug:
        msg: "Distro: {{ansible_facts['distribution']}} Architecture: {{ansible_facts['architecture']}}"
- hosts: webservers
  become: yes
  tasks:
    - name: Say hello
      debug:
        msg: "Hello from webserver  {{ansible_facts['user_id']}}@{{ansible_facts['all_ipv4_addresses']}}"

    - name: install jq
      apt:
        name: jq
        state: latest


- hosts: clients
  become: yes
  tasks:
    - name: Say hi
      debug:
        msg: "Hi from client {{ansible_facts['user_id']}}@{{ansible_facts['all_ipv4_addresses']}}"

    - name: install apache2
      apt:
        name: apache2
        state: latest

Tags in Ansible

How you put tags in ansible, check the following playbook

- hosts: webservers
  become: yes
  tags: hello,jq
  tasks:
    - name: Say hello
      debug:
        msg: "Hello from webserver  {{ansible_facts['user_id']}}@{{ansible_facts['all_ipv4_addresses']}}"

    - name: install jq
      apt:
        name: jq
        state: latest
List all available tags in the playbook
ansible-playbook --list-tags site.yaml
Execute specific play using tags
ansible-playbook --tags centos --ask-become-pass site.yaml
Select multiple tags
ansible-playbook --tags "apache,jq" --ask-become-pass site.yaml

Managing files

To accomplish this task we need to create a folder called files inside the folder files we need to create a file called default.html with some dump content.

The next think that we need to do is to add a play that copies that file to a server. In particular you can find the play to be added in site.yaml below

- name: copy default html file for site
  tags: apache,apache2,httpd
  copy:
    src: files/default.html
    dest: /var/www/html/index.html
    owner: root
    group: root
    mode: 0644
The unarchive module

The unarchive module is the ansible builtin module responsible to unzip compressed files, supports local but also remote sources Before you start using unarchive you need to have installed unzip package in your remote servers. An example play that uses the unarchive module is the following.

- name: install unzip
  apt:
    name: unzip
    state: latest

- name: unarchive terraform
  unarchive:
    src: https://releases.hashicorp.com/terraform/1.10.2/terraform_1.10.2_linux_amd64.zip
    dest: /usr/local/bin
    remote_url: yes
    mode: 0755
    owner: root
    group: root

Bootstraping and Managing Users

The main idea of boostraping and setting the remote virtual machines before starting the real interaction with Ansible is to have a dedicated ansible playbook to make some actions / plays like creating users, use the authorized key module to provide access through ssh keys and provide sudo access

For that reason we will create a playbook called bootstrap.yaml

To create a user called simone we created the play below:

- name: create user simone
  user:
    name: simone
    groups: root

Then we need to add the ssh key for user simone to do so we need to add the following play. In our example we have put ansible.pub to test the play

- name: add simone to authorized keys
  authorized_key:
    user: simone
    key: "${simone public key}" 

In order to evaluate that the play was applied we type the following command

ssh -i /.ssh/ansible [email protected]

To transform simone as a sudo user we need to perform the following actions

Firstly we need to add to files folder a file named sudoer_simone which will follows the sudo format and syntax

simone   ALL=(ALL) NOPASSWD: ALL

then we need to user the copy module as follows

- name: make simone a sudoer
  copy:
    src: files/sudoer_simone
    dest: /etc/sudoers.d/simone
    owner: root
    group: root
    mode: 0444

Ansible Roles

In order to improve the structure of our playbooks Ansible has introduced roles. Ansible roles use a folder format where taskbooks (tasks) are stored inside under a folder named with this pattern ${role-name}/tasks/main.yaml.

Example given lets say that we have 3 different roles named base, webservers, clients it is obligatory to create the following structure

  • playbook.yaml
  • base/
    • tasks/
      • main.yaml
  • webservers/
    • tasks/
      • main.yaml
  • clients/
    • tasks/
      • main.yaml

And the playbook should have the following syntax

---
- hosts: all
  become: yes
  tags: always
  pre_tasks:
    - name: show your distributions
      debug:
        msg: "Distro: {{ansible_facts['distribution']}} Architecture: {{ansible_facts['architecture']}}"

- hosts: all
  become: yes
  tags: base
  vars_files:
    - vault.yaml
  roles:
    - base

- hosts: webservers
  become: yes
  tags: hello,jq
  roles:
    - webservers

- hosts: clients
  become: yes
  tags: hi,apache
  roles:
    - clients

Finally we execute the playbook normally as we did in the previous cases

ansible-playbook playbook --ask-become-pass --ask-vault-pass
Attention

If a taskbook is managing files then inside the role folder we need to create a directory named files and put the origin files inside there. Example given

  • clients/
    • files/
      • index.html
    • tasks/
      • main.yaml

Host Variables

Host variables help to generalize the playbooks and have more control. It is very easy to use. Firstly you need to create a folder named host_vars and to create yaml files using your server alias for instance server1.yaml

The folder structure needs to the following:

  • host_vars/
    • server1.yaml
    • server2.yaml
    • ${alias-no3}.yaml

An example variable file for server1 server is like below:

who_am_i: darth-vader
rnd_pack: htop

and for server2

who_am_i: anakin
rnd_pack: wget

And we are able very easily to generalize our roles, playbooks, taskbooks like following (base):

---
- name: say your name
  debug:
    msg: "I am {{ansible_facts['all_ipv4_addresses']}} {{base_description}}"
- name: whoAmI
  debug:
    msg: "I am {{who_am_i}}"

- name: install a package
  apt:
    name: "{{rnd_pack}}"
    state: latest

Handlers

Handlers are used in order to automate triggering events inside roles. To use a Hanlder inside a role you need to create a folder inside the role folder named handlers and create a yaml file called main.yaml and put the tasks that will act as handlers. We need to use notify directive to call a handler inside a task by using the handler name

In particular you need to following the folder structure below:

  • playbook
  • roles/
    • ${role-name}/
      • handlers/
        • main.yaml
      • tasks/
        • main.yaml

We have the following tasks:

---
- name: say your name
  debug:
    msg: "I am {{ansible_facts['all_ipv4_addresses']}} {{base_description}}"
- name: whoAmI
  debug:
    msg: "I am {{who_am_i}}"

- name: install a package
  apt:
    name: "{{rnd_pack}}"
    state: latest

- name: change a file
  lineinfile:
    path: /home/ubuntu/test
    regexp: '^ServerAdmin'
    line: ServerAdmin [email protected]
  notify: restart_apache2

If the task change a file will change a file and take effect then it will notify the task restart_apache2 that lies inside handlers/ and it will restart apache2 service

- name: restart_apache2
  service:
    name: apache2
    state: restarted

Templates

Templates are very important especially in the configuration phase, where you need to setup multiple servers. In order to use template someone needs to be keen with the jinja2 format as well as to have already used host variables. E.g. to have a created the host_vars/ folder and for each host / server to have already created the jinja2 file (.j2) extension.

An example follows:

We have already the following structure:

  • test-handlers.yaml
  • host_vars/
    • server1.yaml
    • server2.yaml
  • roles/
    • base/
      • handlers/
        • main.yaml
      • tasks/
        • main.yaml
      • templates/
        • test-template.j2

The template is the following and uses the jinja2 syntax

My favourite color is {{fav_color}}
My name is {{who_am_i}}

{% if age > 17 %}
You are an adult and you can have a light saber.
My saber is {{light_saber}}
{% else %}
You are a yungster you should not keep a light saber
My saber is {{light_saber}}
{% endif %}

Your enemies are:
{% for enemy in enemies %}
  - {{enemy}}
{% endfor %}

The variables mentioned above are already included in the host variables of each host and in particular are the following

# server1
who_am_i: darth-vader
rnd_pack: htop
fav_color: dark
age: 100
light_saber: Naberie
enemies:
  - Chewbacca
  - Commander Fox
  - Cudon Prax
  - Count Dooku
  - Anakin
# server2
who_am_i: anakin
rnd_pack: wget
fav_color: blue
age: 17
light_saber: Skywalker
enemies:
  - Count Dooku
  - Darth Vader
  - Chancellor
  - General Grievous
  - The Sith

and the playbook uses the template package to point out as a source the template and dest the output formated using the template. In particular the test.conf will get its contents from the test-template.j2 and after the creation of the file a handler will print a message that the file created successfully

- name: use the template to generate test.conf
  template:
    src: templates/test-template.j2
    dest: /etc/test.conf
  notify: template_used

About

It is a simple Ansible tutorial

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published