How We Use Ansіble for Configuration of Our Environments

How We Use Ansіble for Configuration of Our Environments

After testing several SMCs (Software configuration management), we have decided to choose Ansible as it is the most lightweight option and does not require a client-server implementation.

So, let’s get started and see how it works.



We set up ansible on the local machine. Personally, I am using Fedora release 22.

dnf install ansible

DNF is a new package manager, designed to replace yum.

The simplest thing Ansible can do, is running commands on servers. To do this, let’s write in the command line:

ansible all -i inventories/test.ini -u roman -m ping

all  a command running for servers in the inventory file

-i   a path to the inventory file

-u   a user, under which we will access the servers

-m  module

You can also run any arbitrary command:

ansible all -i inventories/test.ini -u roman -a 'date'

Displaying:

62.244.31.234 | success | rc=0 >> 

Wed Jun 29 06:20:19 EDT 2015 

62.244.31.235 | success | rc=0 >>

Wed Jun 29 06:20:19 EDT 2015

-a arbitrary command

The inventory file is a list of servers and groups

cat inventories/test.ini
 
[test1]
62.244.31.234
[test2]
62.244.31.235

ip, domaine     List of Servers

test1, test2     Groups

If you run:

ansible test1 -i inventories/test.ini -u roman -a 'date'

You see:

62.244.31.234 | success | rc=0 >>

Wed Jun 29 06:31:10 EDT 2015

The command applies only to the servers of a certain group.

playbook is one of the main concepts in Ansible. This is a YAML file where we specify what actions must be done on the servers

- hosts: docker
 
  - name: Installing Docker
    yum: name=docker state=latest
    become: yes
   
  - name: Uninstaling Software
    yum: name=sendmail state=absent
    become: yes

In the example above we will install the docker package for docker hosts group and remove sendmail packages

name      An arbitrary designation of the task

yum        yum module

become    Switching user to superuser

If the playbook becomes large, and we need to run an action located somewhere in the end of the file,then we’d have to wait for quite a while. 

To shorten the waiting time, ansible offers tags

- name: Copying docker-storage config
    copy: src={{ files_path }}/docker/docker-storage dest=/etc/sysconfig/docker-storage
    become: yes
    tags: copy_config

Write in the command line:

ansible-playbook --check inventories/docker.yml -i inventory.ini -t copy_config

PLAY [docker] *****************************************************************

GATHERING FACTS ***************************************************************

ok: [docker_ci]

TASK: [Copying docker-storage config] *****************************************

ok: [docker_ci]

PLAY RECAP ********************************************************************

docker_ci : ok=2 changed=0 unreachable=0 failed=0

ansible-playbook --check docker.yml -i inventory.ini -t copy_config --skip-tags

-check       Check, but do not apply changes

-t            Tag

-skip-tags    Will perform all tasks except those that are specified

Tags can be also specified as follows:

 - name: Copying docker-storage config
    copy: src={{ files_path }}/docker/docker-storage dest=/etc/sysconfig/docker-storage
    become: yes
    tags: [docker, config]

Sometimes, having performed some changes, you need to restart the service. For this, ansible has handlers. Handlers are performed at the very end of the playbook, because playbook can have a lot of tasks that will restart the service

- name: Copying nginx config
  template: src={{ templates_path }}/nginx/nginx.conf.j2 dest=/etc/nginx/nginx.conf
  become: yes
  notify:
      - nginx restart
  tags: copy_nginx_config
 
 handlers:
    - name: nginx restart
      service: name=nginx state=restarted
      become: yes

notify Specifies the name of the handler

Ansible has the variables. To omit the same values, let’s ​​define the variables:

- hosts: docker
  vars:
    files_path: /path/to/file
 
  - name: Copying docker-storage config
    copy: src={{ files_path }}/docker/docker-storage dest=/etc/sysconfig/docker-storage
    become: yes

{{}} Variables are defined in such brackets 

Ansible has such a concept as facts, a set of information about the servers. To see the facts about a certain machine, let’s write: 

ansible test1 -i inventories/test.ini -m setup

62.244.31.234 | success >> {

«ansible_facts»: {

«ansible_all_ipv4_addresses»: [

«62.244.31.234»

],

«ansible_all_ipv6_addresses»: [],

«ansible_architecture»: «x86_64»,

«ansible_bios_date»: «NA»,

«ansible_bios_version»: «NA»,

«ansible_cmdline»: {

«quiet»: true

},

«ansible_date_time»: {

«date»: «2015-08-25»,

«day»: «25»,

«epoch»: «1440503957»,

«hour»: «07»,

«iso8601»: «2015-08-25T11:59:17Z»,

«iso8601_micro»: «2015-08-25T11:59:17.235193Z»,

«minute»: «59»,

«month»: «08»,

«second»: «17»,

«time»: «07:59:17»,

«tz»: «EDT»,

«tz_offset»: «-0400»,

«weekday»: «Вторник»,

«year»: «2015»

}

……………..

Facts are collected every time Ansible runs. If you put gather_facts:no in playbook, the facts will not be collected:

---
- hosts: docker
  gather_facts: no
 
  tasks:
  - name: Adding epel repo
    copy: src={{ files_path }}/repo/epel.repo dest={{ repos }}/epel.repo
    become: yes
    when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"
    tags: epel_repo

Let’s consider the cycles, as quite often you need to install lots of packages, which overwhelms playbook with similar tasks. For this, there is the key with_items:

- name: Installing basic packages
    yum: name={{ item }} state=latest
    with_items:
        - mc
        - nano
        - atop
        - htop
        - iptraf-ng

There is another option of usage, by applying several parameters:

tasks:
  - name: Adding users
    user: name={{ item.name }} state=present group={{ item.group }}
    with_items: 
      - { name: testuser1, group: test }
      - { name: testuser2, group: test }
    become: yes

Also, Ansible has conditions. If the condition matches, then the task runs:

tasks:
  - name: "shutdown Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_os_family == "Debian"
 
tasks:
  - name: "shutdown CentOS 6 and 7 systems"
    command: /sbin/shutdown -t now
    when: ansible_distribution == "CentOS" and
          (ansible_distribution_major_version == "6" or ansible_distribution_major_version == "7")

when    condition

Ansible also has filters:

---
- hosts: localhost
  vars:
    numbers: [ 4, 9, 6, 8, 2, 9 ]
    path: /etc/passwd
 
  tasks:
  - debug: msg={{numbers | min }}
  - debug: msg={{numbers | max }}
  - debug: msg={{numbers | unique }}
 
  - debug: msg={{ ['a', 'b', 'c' ] | random }}
 
  - debug: msg={{ path | basename }}
  - debug: msg={{ path | dirname }}
 
  - debug: msg={{ "~/Documents" | expanduser }}

GATHERING FACTS ***************************************************************

ok: [localhost]

TASK: [debug msg={{numbers | min }}] ******************************************

ok: [localhost] => {

«msg»: «2»

}

TASK: [debug msg={{numbers | max }}] ******************************************

ok: [localhost] => {

«msg»: «9»

}

TASK: [debug msg={{numbers | unique }}] ***************************************

ok: [localhost] => {

«msg»: «[4,»

}

TASK: [debug msg=b] ***********************************************************

ok: [localhost] => {

«msg»: «a»

}

TASK: [debug msg={{ path | basename }}] ***************************************

ok: [localhost] => {

«msg»: «passwd»

}

TASK: [debug msg={{ path | dirname }}] ****************************************

ok: [localhost] => {

«msg»: «/etc»

}

TASK: [debug msg=/home/roman/Documents] ***************************************

ok: [localhost] => {

«msg»: «/home/roman/Documents»

}

min           Displays the minimum value

max          Displays the maximum value

unique        Displays the unique value

random       Displays a random value

basename     Displays the file name

dirname      Displays the directory name

expanduser   Discloses tildes 

Registration of the results:

tasks:
  - shell: ls /home
    register: home_dirs
 
  - debug: var=home_dirs

TASK: [debug var=home_dirs] ***************************************************

ok: [localhost] => {

«var»: {

«home_dirs»: {

«changed»: true,

«cmd»: «ls /home»,

«delta»: «0:00:00.004283»,

«end»: «2015-08-25 16:35:28.429512»,

«invocation»: {

«module_args»: «ls /home»,

«module_name»: «shell»

},

«rc»: 0,

«start»: «2015-08-25 16:35:28.425229»,

«stderr»: «»,

«stdout»: «lost+foundnromanntestntestuser1ntestuser2»,

«stdout_lines»: [

«lost+found»,

«roman»,

«test»,

«testuser1»,

«testuser2»

],

«warnings»: [] }

}

}



Now we take the value from stdout_lines

 tasks:
  - shell: ls /home
    register: home_dirs
 
  - debug: var=home_dirs 
 
  - name: Adding home dirs to cron
    cron: name="Backup" minute="0" hour="6,3" job="backup_dir /home/{{ item }}"
    with_items: home_dirs.stdout_lines

When the playbook becomes huge, you can remove pieces to other files:

---
- hosts: docker
  vars_files:
  - ../vars/basic_vars.yml
 
  tasks:
  - include: includes/basic.yml
 
  handlers:
  - include: includes/handlers.yml
 
- include: includes/httpd_servers.yml

The inclusions are an ordinary YAML file:

cat includes/basic.yml

— name: Uninstaling Software

yum: name={{ item }} state=absent

with_items:

— sendmail

— exim

— httpd

become: yes

Add comment

E-mail is already registered on the site. Please use the Login form or enter another.

You entered an incorrect username or password

Sorry that something went wrong, repeat again!
EN DE
Contact us