Ansible — система управления конфигурациями

2779
Ansible — система управления конфигурациями
Ansible — система управления конфигурациями

Начало

Ссылки:

https://www.ansible.com/ - офф сайт
https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html - бест практик
https://pastebin.com/9hpUPE1z - пример конфига vpn клиента
https://www.youtube.com/watch?v=Ck1SGolr6GI&list=PLg5SS_4L6LYufspdPupdynbMQTBnZd31N&index=1 - видосики от ADV-IT
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html - установка офф документация

Вводное:

Ansible - Automation Configure Tool
Минимальные требования

Control Server - Master Server:
1. Linux only (RedHat, Debian, Centos, OS X, ubuntu)
2. Python 2.6 или Python 3.5+

Controlled Servers - Managed Servers:
Linux: Admin Username/Passwords или SSH Key и Python 2.6+
Windows: Admin Username/Passwords, Powershell 3.0 и запустить скрипт ConfigureRemotingForAnsible.ps1

Работа происходит через следующие порты:
Linux -> SSH Port 22
Windows -> WinRM Port 5986

Установка:

Установка на Ubuntu 16.04:
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

Установка на CentOS 7:
sudo yum install epel-release
sudo yum install ansible

Ansible - Установка на Amazon Linux через PIP
sudo pip install ansible


ansible --version - узнаем версию ansible

ansible подключение к клиентам

Пример генерации ключей

ssh-keygen - создаем пару ключей на сервере с которого будем подключатся.
ssh-copy-id username@IP_адрес_вашего_сервера - копирование открытого ключа

автоматизация...
ssh-keygen && for host in $(cat hosts.txt); do ssh-copy-id $host; done

Подключение:

cd ~ - перешли в домашний каталог
mkdir ansible - создали каталог ansible для удобства
cd /ansible - перешли в новый каталог ansible
touch host.txt - создадим специальный файл для подключения к хостам

nano host.txt - отредактируем
---host.txt--- если используются пароли
[staging_servers]
linux1 ansible_host=192.168.15.142 ansible_user=USERNAME1 ansible_pass=Mypassword123
--------------

nano host.txt - отредактируем
---host.txt--- если используются SSHKEY
[staging_servers]
linuxX ansible_host=192.168.15.142 ansible_user=USERNAME1  ansible_ssh_private_key_file=/home/USERNAME1/.ssh/id_rsa

[prod_servers]
linux1 ansible_host=192.168.15.145 ansible_user=USERNAME1  ansible_ssh_private_key_file=/home/USERNAME1/.ssh/nameSSHkey1.pem
linux2 ansible_host=192.168.15.145 ansible_user=USERNAME1  ansible_ssh_private_key_file=/home/USERNAME1/.ssh/nameSSHKey2.pem

[windows_servers]
windows1 ansible_host=192.168.15.147
windows2 ansible_host=192.168.15.146

[windows_servers:vars]
ansible_user = admin
ansible_password = PASSWORD@123 !!! можно убрать пароль из конфига, а при запуске команды ansible писать --ask-pass
ansible_port = 5986
ansible_connection = winrm
ansible_winrm_serv_cert_validation = ignore
--------------

Дополнительная настройка ansible.cfg

ansible --version - покажет версию, где находится конфиг файл ansible.cfg
/etc/ansible/ansible.cfg - в ubuntu тут

cd ~ansible - перешли в каталог ansible
tauch ansible.cfg - создадим пустой файл

nano ansible.cfg
---ansible.cfg---
[defaults]
host_key_cheking = false  - отключаем проверку для finger ssh-key 
inventory = /home/USERNAME/host.txt - файл настроек хостов

-----------------

Проверка ping:

cd ~ansible - перешли в каталог ansible

ansible -i host.txt all  -m ping  - запустили проверку в ответ прилетит PONG

-i host.txt  - файл с хостами
all - группа в данном случае для всех
-m ping - используем модуль ping для linux хостов
-m win_ping  - используем модуль ping для windows хостов

Если в ansible.cfg добавили invertory  то можно не писать опцию  -i host.txt

ansible all  -m ping  - запустили проверку в ответ прилетит PONG если все ок

ansible windows_servers  -m win_ping  - запустили проверку в ответ прилетит PONG если все ок
ansible windows_servers  -m win_ping --ask-pass - запустили проверку в ответ прилетит PONG если все ок

ansible invertory и файл host.txt

Файл пример:

Можно записывать так просто перечислить ip адреса
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5

Можно записывать имена серверов
name1
name2
name3
name4
name5

!!! Все хосты входят в группы
!!! Все хосты входят в группу all
!!! Все хосты которым не назначена группа, входят в группу ungrouped и all

[staging_DB]
192.168.0.10
192.168.0.11

[staging_WEB]
192.168.0.20
192.168.0.21

[staging_APP]
192.168.0.30
192.168.0.31

[staging_ALL:children]
staging_DB
staging_WEB
staging_APP

[prod_DB]
10.10.10.1
[prod_WEB]
10.10.10.2
[prod_APP]
10.10.10.3

[prod_ALL:children]
prod_DB
prod_WEB
prod_APP

[DB_ALL:children]
staging_DB
prod_DB

[APP_ALL:children]
staging_APP
prod_APP

[APP_ALL:vars]
message=Hello

[staging_servers]
linuxX ansible_host=192.168.15.142 ansible_user=USERNAME7  ansible_ssh_private_key_file=/home/USERNAME7/.ssh/id_rsa
 
[prod_servers]
linux1 ansible_host=192.168.15.145
linux2 ansible_host=192.168.15.146

[prod_servers:vars]
ansible_user=USERNAME1
ansible_ssh_private_key_file=/home/USERNAME1/.ssh/nameSSHKey1.pem 


[windows_servers]
windows1 ansible_host=192.168.15.147
windows2 ansible_host=192.168.15.146
 
[windows_servers:vars]
ansible_user = admin
ansible_password = PASSWORD@123 !!! можно убрать пароль из конфига, а при запуске команды ansible писать --ask-pass
ansible_port = 5986
ansible_connection = winrm
ansible_winrm_serv_cert_validation = ignore

ДОП

ansible-invertory --list - покажет все хосты и какие переменные к ним относятся
ansible-inventory --graph - - покажет все хосты и какие группы в виде дерева

ansible запуск ad-hoc команд, -m , ping , setup , shell , copy , file , get_url , yum , apt , service , uri , ansible-invertory , ansible-doc

ansible -i host.txt all  -m ping  - запустили проверку в ответ прилетит PONG
-i host.txt  - файл с хостами
all - группа в данном случае для всех
-m ping - используем модуль ping для linux хостов
-m win_ping  - используем модуль ping для windows хостов

Если в ansible.cfg добавили invertory  то можно не писать опцию  -i host.txt
ansible all  -m ping  - запустили проверку в ответ прилетит PONG если все ок
 
ansible all -m setup - выведет параметры всех серверов
ansible staging_servers  -m setup - выведет параметры группы taging_servers

ansible all -m shell -a "uptime" - выполнить на всех серверах команду uptime
-m shell - модуль шелл
-a аргумент (комманда) 
uptime

ansible all -m shell -a "df -h" - выполнить на всех серверах команду df -h (занятое место)

ansible all -m command -a "uptime" - тоже самое что и shell но в нем не будут работать переменные и спец символы !@#$%^&*(}| и тд

ansible all -m copy -a "src=xxx.txt dest=/home mode=777" - скопировать файл xxx.txt в каталог /home
ansible all -m copy -a "src=xxx.txt dest=/home mode=777" -b - повысить привилегии (sudo)
ansible all -m copy -a "src=xxx.txt dest=/home mode=777" -b --ask-become-pass - повысить привилегии и ввести пароль 
-b  - повысить привилегии
-m copy - модуль копирования

ansible all -m file -a "path=/home/XXX.txt state=absent" -b - удаление файла XXX.txt

ansible all -m get-url -a "url=http://example.com/path/file.conf dest=/home/foo.conf" 

ansible all -m get_url -a "url=http://example.com/path/file.conf dest=/home/foo.conf username=USERNAME password=USERNAME"


ansible all -m yum -a "name=httpd state=latest" -b - установка пакета stress на CentOS (проверял установит и на Debian)
ansible all -m yum -a "name=stress state=present" -b - установка пакета stress на CentOS (проверял установит и на Debian)
ansible all -m yum -a "name=stress state=absent" -b - удаление пакета stress на CentOS (проверял удалит и на Debian)

ansible all -m apt -a "name=apache2 state=present" -b  - установка apache2 на Debian
ansible all -m apt -a "name=apache2 state=absent" -b  - удаление apache2 на Debian


ansible all -m service -a "name=httpd state=started enabled=yes" - запускать веб сервер CentOS
ansible all -m service -a "name=apache2 state=started enabled=yes" - запускать веб сервер Debian


ansible all -m uri -a "url=https://bookflow.ru" - как бы тестик, проверить доступность страницы
ansible all -m uri -a "url=https://bookflow.ru return_content=yes" - как бы тестик, проверить доступность страницы, покажет страницу

ansible all -m shell -a "df -h " -vvvvv - дебаг(debug) выполнения команды ( чем больше "v"  тем больше дебагу)

ansible-doc -l - офф документация в консоли
ansible-doc -l | grep windows - поиск по windows
ansible-doc -l | grep ec2 - поиск по ec2

!!! https://docs.ansible.com/ - используй тут много полезного

ansible-invertory --list - покажет все хосты и какие переменные к ним относятся
ansible-inventory --graph - покажет все хосты и какие группы в виде дерева

Для работы -b и ошибка «msg»: «Missing sudo password»

!!! Вот такая ошибка "msg": "Failed to get information on remote file может появятся если сломали sudo
!!! "msg": "Missing sudo password" ошибка  появляется с опцией -b временно поможет опция --ask-become-pass
!!! 
sudo groupadd sudo - создать группу sudo в Ubuntu эта группа уже существует

sudo usermod -a -G sudo username - добавить вашего пользователя к этой группе
где username - имя вашего пользователя в системе

Отредактировать /etc/sudoers файл
sudo nano /etc/sudoers
----------------------
Найти строку ниже в этом файле (если нет, то создать)
%sudo   ALL=(ALL:ALL) ALL
и поменять на следующую
%sudo   ALL=(ALL:ALL) NOPASSWD: ALL
-----------------------

ansible формат yaml , файлов yml , примеры

0. myfile.yml

Обычный текстовый файл
--- всегда начинаются с двух минусов

... заканчиваются точками

1. myfile.yml

---
 - command1 первая команда начинается с одного минуса

 - command2 вторая команда минус должен располагаться четко под минусом первой команды
...

2. myfile.yml

---
 fruits:  список команд заканчивается на двоеточие, и начинается с минуса если списков несколько
      - apple 
      - orange
      - mango 

...

3. myfile.yml

---
 - fruits:  список команд заканчивается на двоеточие, и начинается с минуса если списков несколько
      - apple 
      - orange
      - mango 
 
 - vegetables:
      - carrots
      - cucumbers
 
...

4. myfile.yml

---
 - fruits: 
      - apple 
      - orange
      - mango 

  fruits: ['apple' , 'orange' , 'mango' ]

 - vegetables:
      - carrots
      - cucumbers
 
 - vasya:
     nick: vasek
     position: developer
     skills:
         - python
         - perl
         - php
 - petya:
     nick: pet
     postition: manager
     skills:
         - manage
         - make_noise

- petyak:
     nick: "pettya: krutoy"
     postition: manager
     skills:
         - manage
         - make_noise

 - kolya: {nick: kolyan, position: administrator, skills: killer }

 - kolya1: {nick: kolyan, position: administrator, skills: ['killer', 'cleaner' }



...

5. Популярный вид записи myfile.yml

- petya:
     nick: pet
     postition: manager
     skills:
         - manage
         - make_noise

ansible перенос переменных , group_vars

Дано host.txt:

[STAGING_SERVERS_WEB]
LinuxX1 ansible_host=192.168.30.10
LinuxX1 ansible_host=192.168.30.11 password=mysecret

[STAGING_SERVERS_WEB:vars]
ansible_user=user1
ansible_ssh_private_key_file=/home/user1/.ssh/super-key1.pem

[PROD_SERVERS_WEB]
Linux1 ansible_host=10.10.10.10
Linux1 ansible_host=10.20.20.11

[PROD_SERVERS_WEB:vars]
ansible_user=user1
ansible_ssh_private_key_file=/home/user1/.ssh/super-key2.pem

[STAGING_SERVERS_DB]
192.168.30.20
192.168.30.21

[PROD_SERVERS_DB]
10.10.10.20
10.10.10.21

[ALL_SERVERS_DB:children]
STAGING_SERVERS_DB
PROD_SERVERS_DB

[ALL_SERVERS_DB:vars]
db_endpoint=db.sytekxxx.com:4151
owner=vasya
location="Huston,TX"

Выносим переменные из файла host.txt

cd ~ansible - перешли в каталог ansible в домашнем каталоге пользователя (естественно в каталоге /etc/ansible/ у меня нет конфигов)
mkdir group_vars - создаем каталог group_vars в каталоге ansible 
cd group_vars - перешли в каталог group_vars
touch STAGING_SERVERS_WEB PROD_SERVERS_WEB ALL_SERVERS_DB - создаем файлы PROD_SERVERS_WEB и  ALL_SERVERS_DB

nano STAGING_SERVERS_WEB  - файл будет иметь YAML синтаксис (в начале файла ---, в конце файла ... , равно(=) заменить на двоеточие(:)
---STAGING_SERVERS_WEB---
---
ansible_user                 : user1
ansible_ssh_private_key_file : /home/user1/.ssh/super-key1.pem
...
----------------------


nano PROD_SERVERS_WEB  - файл будет иметь YAML синтаксис (в начале файла ---, в конце файла ... , равно(=) заменить на двоеточие(:)
---PROD_SERVERS_WEB---
---
ansible_user                 : user1
ansible_ssh_private_key_file : /home/user1/.ssh/super-key2.pem
...
----------------------

nano ALL_SERVERS_DB  - файл будет иметь YAML синтаксис (в начале файла ---, в конце файла ... , равно(=) заменить на двоеточие(:)
---ALL_SERVERS_DB---
---
db_endpoint : db.sytekxxx.com:4151
owner       : vasya
location    : "Huston,TX"
...
--------------------


nano host.txt - приводим к следующему виду
---host.txt---
[STAGING_SERVERS_WEB]
LinuxX1 ansible_host=192.168.30.10
LinuxX1 ansible_host=192.168.30.11 password=mysecret

[PROD_SERVERS_WEB]
Linux1 ansible_host=10.10.10.10
Linux1 ansible_host=10.20.20.11

[STAGING_SERVERS_DB]
192.168.30.20
192.168.30.21

[PROD_SERVERS_DB]
10.10.10.20
10.10.10.21

[ALL_SERVERS_DB:children]
STAGING_SERVERS_DB
PROD_SERVERS_DB
--------------

ansible playbook

вводное

!!! Пробелы ОЧЕНЬ ВАЖНЫ
!!! НЕ ИСПОЛЬЗУЙТЕ "TAB" будут ошибки на ровном месте 

ansible-playbook NAMEPLAYBOOK.yml - запуск плейбука

playbook0.yml ping

---
- name: Test connection to my servers
  hosts: all
  become: yes

  tasks:
   - name: Ping my servers
     ping:
...

playbook1.yml install httpd CentOS

---
- name: Install default Apache Web Servers
  hosts: all
  become: yes

  tasks:
  - name: Install Apache Web Server
    yum: name=httpd state=latest

  - name: Start Apache and Enable it on every boot
    service: name=httpd state=started enabled=yes
  
...

playbook2.yml install apache2 Debian

---
- name: Install default Apache Web Servers
  hosts: all
  become: yes

  tasks:
  - name: Install Apache Web Server
    yum: name=apache2 state=present

  - name: Start Apache and Enable it on every boot
    service: name=apache2 state=started enabled=yes
...

playbook3.yml install apache2 Debian and copy index.html

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_file: ./website/index.html
     destin_file: /var/www/html

  tasks:
  - name: Install Apache Web Server
    yum: name=apache2 state=present

  - name: Copy index html to Servers
    copy: src={{ source_file }} dest={{ destin_file }} mode=0555
    notify: Restart Apache

  - name: Start Apache and Enable it on every boot
    service: name=apache2 state=started enabled=yes

  handlers:
  - name: Restart Apache
    service: name=apache2 state=restarted
...

ansible переменные , Debug , Set_fact , Register

host.txt

ansible all -m setup - выведет параметры всех серверов
ansible staging_servers  -m setup - выведет параметры группы taging_servers


[staging_servers]
linux1 ansible_host=192.168.15.142 owner=LOL

playbook_debug.yml

---
- name: My super Playbook
  hosts: all
  become: yes

  vars:
     message1: privet
     message2: word
     secret  : LKKDKDKDKDLSDKLSKD

  tasks:

  - name: Print Sectret variable
    debug:
      var: secret

  - debug:
      msg: "Sekretnoe slovo {{ secret }}"

  - debug:
      msg: "Vladelec etogo servera --> {{ owner }} <--"

  - set_fact: full_message=" {{ message1 }} {{ message2 }} from {{ owner }}"

  - debug:
      var: full_message

  - debug:
      var: ansible_distribution

  - debug:
      var: ansible_all_ipv4_addresses

  - shell: uptime
    register: results

  - debug:
      var: results

  - debug:
      var: results.stdout
...

ansible блоки , условия , apache , copy , install , when , block

playbook.yml

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_file: ./website/index.html
     destin_file: /var/www/html

  tasks:
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Copy index html to Servers
         copy: src={{ source_file }} dest={{ destin_file }} mode=0555
         notify: Restart Apache RedHat

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Copy index html to Servers
        copy: src={{ source_file }} dest={{ destin_file }} mode=0555
        notify: Restart Apache Debian

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes

    when: ansible_os_family == "Debian"



  handlers:
  - name: Restart Apache Redhat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

ansible , циклы , loop , with_items , until , with_fileglob , copy , folder , копирование

playbook-loop.yml примеры циклов loop, with_items

---
- name: Loops Hello
  hosts: all
  become: yes

  tasks:

  - name: Say Hello to ALL
    debug: msg="Hello {{ item }}"
    loop:
        - "Vasya"
        - "Masha"
        - "Olga"
        - "Petr"

  - name: loop until example
    shell: echo -n Z >> myfile.txt && cat myfile.txt
    register: output
    delay: 2
    retries: 10
    until: output.stdout.find("ZZZZ") == false

  - name: Print Final Output
    debug:
      var:  output.stdout


#  - name: Install many packeg
#    apt: name={{ item }} state=present
#    with_items:
#            - apache2
#            - htop
#            - tree




...

playbook.yml install-and-copy-folder

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_folder: ./website
     destin_folder: /var/www/html

  tasks:
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes 


    when: ansible_os_family == "Debian"

  - name: Copy folder  to web  Servers
    copy: src={{ source_folder }}/{{ item }} dest={{ destin_folder }} mode=0555
    loop:
      - "file0.txt"
      - "file1.txt"
      - "file2.txt"
      - "file3.txt"
      - "file4.txt"
      - "file5.txt"
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian

  handlers:
  - name: Restart Apache RedHat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

playbook.yml install-and-copy-folder по маске

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_folder: ./website
     destin_folder: /var/www/html

  tasks:
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes

    when: ansible_os_family == "Debian"

  - name: Copy folder  to web  Servers
    copy: src={{ item }} dest={{ destin_folder }} mode=0555
    with_fileglob: "{{ source_folder }}/*.*"
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian

  handlers:
  - name: Restart Apache RedHat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

ansible , шаблоны , template , jinja , generate

index.2j

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="index.css">
    <title> Просто страничка для тестов</title>
  </head>

  <body>
     <p> hello MEN </p>
     <p> страница generate </p>
     </tr>
     <p> print owner: {{ owner }} </p>
     <p> print hostname: {{ ansible_hostname }} </p>
     <p> print fqdn: {{ ansible_fqdn }} </p>
     <p> print os: {{ ansible_os_family }} </p>
     <p> IP address: {{ ansible_default_ipv4.address }} </p>
  </body>
</html>

playbook.yml

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_folder: ./website
     destin_folder: /var/www/html

  tasks:
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes

    when: ansible_os_family == "Debian"

  - name: Generate INDEX.HTML file
    template: src={{ source_folder }}/index.j2 dest={{ destin_folder }}/index.html mode=555
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian


  - name: Copy folder  to web  Servers
    copy: src={{ source_folder }}/{{ item }} dest={{ destin_folder }} mode=0555
    loop:
      - "file0.txt"
      - "file1.txt"
      - "file2.txt"
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian

  handlers:
  - name: Restart Apache RedHat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

ansible role

вводное

cd ~ansible - зашли в домашний каталог ansible
mkdir roles - создали каталог roles
cd roles - зашли в каталог roles
ansible-galaxy init deploy_apache_web_site - создание роли, а точнее в каталоге roles, будут созданы каталоги и файлы
---------------------------------------
└── deploy_apache_web_site
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml
---------------------------------------

Наш playbook.yml который мы будем распихивать в роль deploy_apache_web_site

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars:
     source_folder: ./website
     destin_folder: /var/www/html

  tasks:
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes

    when: ansible_os_family == "Debian"

  - name: Generate INDEX.HTML file
    template: src={{ source_folder }}/index.j2 dest={{ destin_folder }}/index.html mode=555
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian


  - name: Copy folder  to web  Servers
    copy: src={{ source_folder }}/{{ item }} dest={{ destin_folder }} mode=0555
    loop:
      - "file0.txt"
      - "file1.txt"
      - "file2.txt"
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian

  handlers:
  - name: Restart Apache RedHat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

Планируем распил….. playbook.yml …

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  vars: 
     source_folder: ./website   --- это директива нам будет не нужна (так как есть спец каталог для файлов)
     destin_folder: /var/www/html --- эту запись добавим в defaults\main.yml

  tasks: --- все таски добавим в tasks\main.yml
  - name: Cheack and Print Linux Version
    debug: var=ansible_os_family

  - block:  # === BLOCK REDHAT ====
       - name: Install Apache Web Server for RedHat
         yum: name=httpd state=present

       - name: Start Apache and Enable it on every boot
         service: name=httpd state=started enabled=yes

    when: ansible_os_family == "RedHat"


  - block: # === BLOCK DEBIAN ====

      - name: Install Apache Web Server for Debian
        apt: name=apache2 state=present

      - name: Start Apache and Enable it on every boot
        service: name=apache2 state=started enabled=yes

    when: ansible_os_family == "Debian"

  - name: Generate INDEX.HTML file
    template: src={{ source_folder }}/index.j2 dest={{ destin_folder }}/index.html mode=555  --- тут надо будет кое что  поправить см ниже
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian


  - name: Copy folder  to web  Servers
    copy: src={{ source_folder }}/{{ item }} dest={{ destin_folder }} mode=0555 --- тут надо будет кое что  поправить см ниже
    loop:
      - "file0.txt"
      - "file1.txt"
      - "file2.txt"
    notify:
        - Restart Apache RedHat
        - Restart Apache Debian

  handlers: - все хендлеры положим в файл handlers\main.yml
  - name: Restart Apache RedHat
    service: name=httpd state=restarted
    when: ansible_os_family == "RedHat"

  - name: Restart Apache Debian
    service: name=apache2 state=restarted
    when: ansible_os_family == "Debian"

...

Файл website/index.j2 копулируем в каталог templates

Остальные файлы из каталога website копируем в каталог deploy_apache_web_site/files

С файлами получится вот так:

└── deploy_apache_web_site
    ├── defaults
    │   └── main.yml
    ├── files
    │   ├── file0.txt
    │   ├── file1.txt
    │   ├── file2.txt
    │   ├── file3.txt
    │   ├── file4.txt
    │   ├── file5.txt
    │   └── index.css
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    │   └── index.j2
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

Редактируем deploy_apache_web_site\defaults\main.yml

---
# defaults file for deploy_apache_web_site
destin_folder: /var/www/html

Редактируем deploy_apache_web_site\hendlers\main.yml

---
# handlers file for deploy_apache_web_site

- name: Restart Apache RedHat
  service: name=httpd state=restarted
  when: ansible_os_family == "RedHat"

- name: Restart Apache Debian
  service: name=apache2 state=restarted
  when: ansible_os_family == "Debian"

Редактируем deploy_apache_web_site\tasks\main.yml

---
# tasks file for deploy_apache_web_site
- name: Cheack and Print Linux Version
  debug: var=ansible_os_family

- block:  # === BLOCK REDHAT ====
     - name: Install Apache Web Server for RedHat
       yum: name=httpd state=present

     - name: Start Apache and Enable it on every boot
       service: name=httpd state=started enabled=yes

  when: ansible_os_family == "RedHat"


- block: # === BLOCK DEBIAN ====
    - name: Install Apache Web Server for Debian
      apt: name=apache2 state=present

    - name: Start Apache and Enable it on every boot
      service: name=apache2 state=started enabled=yes

  when: ansible_os_family == "Debian"

- name: Generate INDEX.HTML file
  template: src=index.j2 dest={{ destin_folder }}/index.html mode=555
  notify:
      - Restart Apache RedHat
      - Restart Apache Debian


- name: Copy folder  to web  Servers
  copy: src={{ item }} dest={{ destin_folder }} mode=0555
  loop:
    - "file0.txt"
    - "file1.txt"
    - "file2.txt"
  notify:
     - Restart Apache RedHat
     - Restart Apache Debian

Создаем файл playbook.yml для установки ролей

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  roles:
    - deploy_apache_web_site
    - deploy_db
    - deploy_vpn
    - deploy_xxx

...

Создаем файл playbook.yml для установки ролей с условием если ос linux

---
- name: Install Apache and Upload my Web Page
  hosts: all
  become: yes

  roles:
    - { role: deploy_apache_web_site, when: ansible_system == 'Linux' }
   

...

ansible-playbook playbook.yml  - ну собственно запуск установки роли

ansible внешние переменные extra-vars

В playbook.yml добавили переменную

---
- name: Install Apache and Upload my Web Page
  hosts: "{{ MYHOSTS }}"
  become: yes

  roles:
    - { role: deploy_apache_web_site, when: ansible_system == 'Linux' }
...

Использование переменной

ansible-playbook playbook10.yml -e "MYHOSTS=all"
ansible-playbook playbook10.yml -extra-var "MYHOSTS=NAME-HOST"
ansible-playbook playbook10.yml -extra-vats "MYHOSTS=NAME-GROUP"

ansible-playbook playbook10.yml -e "MYHOSTS=PROD owner=DENIS"

!!! Переменные переданные в extra-vars имеют наивысшие значение

ansible import , include , file , folder , generate

include_playbook.yml его будем уменьшать и использовать include / import

---
- name: My TEST Playbook
  hosts: all
  become: yes

  vars:
   mytext: "Privet MEN"

  tasks:
  - name: Ping test
    ping:

  - name: Create folder1
    file:
     path:  /home/secret/folder1
     state: directory
     mode:  0755

  - name: Create folder2
    file:
     path:  /home/secret/folder2
     state: directory
     mode:  0755

  - name: Create file1
    copy:
     dest: /home/secret/file1.txt
     content:
        Text Line1, in file1
        Text Line2, in file1
        Text Line3, {{ mytext }}

  - name: Create file2
    copy:
     dest: /home/secret/file2.txt
     content:
        Text Line1, in file2
        Text Line2, in file2
        Text Line3, {{ mytext }}

...

create_folder.yml

---
- name: Create folder1
  file:
   path:  /home/secret/folder1
   state: directory
   mode:  0755

- name: Create folder2
  file:
    path:  /home/secret/folder2
    state: directory
    mode:  0755

...

create_files.yml

---
- name: Create file1
  copy:
   dest: /home/secret/file1.txt
   content: |
        Text Line1, in file1
        Text Line2, in file1
        Text Line3, {{ mytext }}

- name: Create file2
  copy:
   dest: /home/secret/file2.txt
   content: |
        Text Line1, in file2
        Text Line2, in file2
        Text Line3, {{ mytext }}

...

include_playbook.yml

---
- name: My TEST Playbook
  hosts: all
  become: yes

  vars:
   mytext: "Privet MEN"

  tasks:
  - name: Ping test
    ping:

  - name: Create Folders
    include: create_folder.yml

  - name: Create Files
    import: create_files.yml

...

!!! Отличие import от include заключается в следующем
!!! Include читает из файлов значения, ansible подставляет значения при выполнении (дошел до строчки с include тогда и подставил)
!!! Import  читает и подставляет значения, ansible подставляет сразу все значения
!!! рекомендуют использовать include
!!! Также можно сократить запись


---
- name: My TEST Playbook
  hosts: all
  become: yes

  vars:
   mytext: "Privet MEN"

  tasks:
  - name: Ping test
    ping:

  - include: create_folder.yml
  - include: create_files.yml  mytext="Hello from Mosckow"

...

ansible delegate_to , выполнить где нужно , run_once , shell , copy

playbook.yml delegate_to

---
- name: My playbook create file
  hosts: all
  become: yes

  vars:
   mytext: "Privet ot bookflow"

  tasks:
  - name: Test ping
    ping:

  - name: Create File file1.txt
    copy:
      dest: /home/file1.txt
      content: |
         This is file1.txt
         On ohhh {{ mytext }}
    delegate_to: linux1

  - name: Create file file2.txt
    copy:
     dest: /home/file2.txt
     content: |
        This is File2
        Mytext {{ mytext }}
        lol lol lol lol lol

...

playbook.yml delegate_to на ansible master 127.0.0.1

---
- name: My playbook create file
  hosts: all
  become: yes

  vars:
   mytext: "Privet ot bookflow"

  tasks:
  - name: Test ping
    ping:

  - name: Unregister Server from Load Balance
    shell: echo this server {{ inventory_hostname }} was deregisterred from our load balancer, node name is {{ ansible_nodename }} >> /home/log.txt
    delegate_to: 127.0.0.1

  - name: Create File file1.txt
    copy:
      dest: /home/file1.txt
      content: |
         This is file1.txt
         On ohhh {{ mytext }}
    delegate_to: linux1

  - name: Create file file2.txt
    copy:
     dest: /home/file2.txt
     content: |
        This is File2
        Mytext {{ mytext }}
        lol lol lol lol lol

...

playbook.yml delegate_to , run_once выполнить один раз , reboot и ждем

---
- name: My playbook create file
  hosts: all
  become: yes

  vars:
   mytext: "Privet ot bookflow"

  tasks:
  - name: Test ping
    ping:

  - name: Unregister Server from Load Balance
    shell: echo this server {{ inventory_hostname }} was deregisterred from our load balancer, node name is {{ ansible_nodename }} >> /home/log.txt
    delegate_to: 127.0.0.1

  - name: Update my database
    shell: echo Update database
    run_once: true
    delegate_to: 127.0.0.1
   
  - name: Create File file1.txt
    copy:
      dest: /home/file1.txt
      content: |
         This is file1.txt
         On ohhh {{ mytext }}
    delegate_to: linux1

  - name: Create file file2.txt
    copy:
     dest: /home/file2.txt
     content: |
        This is File2
        Mytext {{ mytext }}
        lol lol lol lol lol

  - name: reboot my servers
    shell: sleep 4 && reboot now
    async: 1
    poll: 0

  - name: wait my server will come online
    wait_for:
      host: "{{ inventory_hostname }}"
      state: started
      delay: 5
      timeout: 40
    delegate_to: 127.0.0.1
...

ansible перехват и контроль ошибок , игнор , failed_when , result.rc , any_errors_fatal

playbook.yml пытаемся установить не существующий пакет treeee и выводим echo

---
- name:  Error find and control
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present

  - name: Tasks number2
    shell: echo Hellow world!

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml ignore_errors игнорим ошибки и выполняем следующие таски

---
- name:  Error find and control
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: echo Hellow world!

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml дебаг ignore_errors

---
- name:  Error find and control
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: ls -la /var/
    register: results

  - debug:
      var: results

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml failed_when

---
- name: Test ansible
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: echo Hellow world
    register: results
    failed_when: "'world' in results.stdout"

  - debug:
      var: results

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml failed_when result.rc

---
- name: Test ansible
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: echo Hellow world
    register: results
    failed_when: result.rc == 0
#    failed_when: "'world' in results.stdout"

  - debug:
      var: results

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml выполнится только там где есть file1.txt

---
- name: Test ansible
  hosts: all
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: cat /home/secret/file1.txt
    register: results

  - debug:
      var: results

  - name: Tasks number3
    shell: echo Privet Man!

...

playbook.yml any_errors_fatal

---
- name: Test ansible
  hosts: all
  any_errors_fatal : true
  become: yes

  tasks:
  - name: Tasks number1
    yum: name=treeee state=present
    ignore_errors: yes

  - name: Tasks number2
    shell: cat /home/secret/file71.txt
    register: results

  - debug:
      var: results

  - name: Tasks number3
    shell: echo Privet Man!

...

ansible , ansible-vault , хранение секретов , шифрованный файл , шифрованные строки

вводное

ansible-vault create mysecret.txt - создание специального зашифрованного файла для хранения секретов (AES256) (редактор vim)
ansible-vault view mysecret.txt - посмотреть зашифрованный файл (просто cat) 
ansible-vault edit mysecret.txt - редактировать зашифрованный файл (редактор vim)

ansible-vault encrypt playbook_vault.yml - шифруем файл playbook_vault.yml (AES256)
ansible-vault decrypt playbook_vault.yml - расшифровываем файл playbook_vault.yml

ansible-playbook playbook_vault.yml --ask-vault-pass - запуск зашифрованного playbook, ansible попросит ввести пароль
ansible-playbook  playbook_vault.yml --vault-password-file mypass.txt - запуск зашифрованного playbook, ansible будет искать пароль в mypass.txt (пароль просто записан текстом)

playbook_vault.yml — будем шифровать этот файл

---
- name: vault playbook
  hosts: all
  become: yes

  vars:
    admin_pass: Pass123

  tasks:
  - name: Install package tree
    yum: name=tree state=present

  - name: Create Config File
    copy:
      dest: "/home/secret/myconfig.conf"
      content: |
         port = 9092
         log = 7days
         home =  /home/secret/
         user = admin
         password = {{ admin_pass }}
...

Шифрование строк в ansible

ansible-vault encrypt_string - шифрование строки

ansible-vault encrypt_string --stdin-name "Mypassword" - шифрование строки
New Vault password: у нас спрашивают для пароль для расшифровки, ввел 1
Confirm New Vault password: вводим пароль для расшифровки еще раз 1
Reading plaintext input from stdin. (ctrl-d to end input) нажимаем Ctrl+d
Pass123 - это мы шифруем
Mypassword: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          39633633373832373034633265323832353636363733643431636535346535643532643439386435
          6638306639306430363664633036386332313133373231390a386338373232373765353964373634
          35363336353962646137663631366265336362323431393263356436313935373735366465363936
          3265633730376163390a376564336565316330393261373931356339656164366162633839666463
          6337
Encryption successful


Нас интересует вот это
 !vault |
          $ANSIBLE_VAULT;1.1;AES256
          39633633373832373034633265323832353636363733643431636535346535643532643439386435
          6638306639306430363664633036386332313133373231390a386338373232373765353964373634
          35363336353962646137663631366265336362323431393263356436313935373735366465363936
          3265633730376163390a376564336565316330393261373931356339656164366162633839666463
          6337




echo -n "$%^SecretWord&&^%" | ansible-vault encrypt_string - еще один вариант шифровать строку
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input)
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          37343432306532653463666138393336396366303664613332373337323730623034663639336530
          3561333338623638343532396130636461356638643931640a303436613561343634363965373863
          62663935313362363535663064316635643636613535386438366239623265633633663066396237
          6430396435323739370a343964613933633964353937336437346536656364313738323130613836
          35613038326338633439623063396264303961313639376466363332323362623866
Encryption successful

Шифрование строки в plabook.yml

---
- name: vault playbook
  hosts: all
  become: yes

  vars:
    admin_pass: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          39633633373832373034633265323832353636363733643431636535346535643532643439386435
          6638306639306430363664633036386332313133373231390a386338373232373765353964373634
          35363336353962646137663631366265336362323431393263356436313935373735366465363936
          3265633730376163390a376564336565316330393261373931356339656164366162633839666463
          6337

  tasks:
  - name: Install package tree
    yum: name=tree state=present

  - name: Create Config File
    copy:
      dest: "/home/secret/myconfig.conf"
      content: |
         port = 9092
         log = 7days
         home =  /home/secret/
         user = admin
         password = {{ admin_pass }}
...


ansible-playbook  playbook_vault.yml --ask-vault-pass - запуск playbook с зашифрованной строкой

источник b14esh.com