Ansible

Allikas: Kuutõrvaja

Sissejuhatus

Ansible on Chefi, Puppeti ja Salti laadne konfiguratsioonide ja pakettide paigalduse automatiseerimise ning suure hulga masinate üheaegseks halduseks mõeldud tarkvara. Selle üheks tugevuseks on lihtsus, töö toimub üle ssh ning lihtne süntaks lubab kergesti bashi skriptide ja how-to laadsete õpetusi ansible keelde portida.

Paigaldus

# apt-get install ansible

Kõisse masinaisse tuleb paigaldada SSH võti

# ssh-keygen -t rsa'

Ja kopeerime järgneva käsuga ükshaaval kõigisse masinaisse

# ssh-copy-id -i .ssh/id_rsa.pub kautaja@vm1

Kliendi defineerimine toimub failis /etc/ansible/hosts näiteks lisame ühe kliendi gruppi test

[test]
10.20.0.20

Neid gruppe võib teha terve hulga, nt kõik masinad ära jaotada opsüsteemide järgi

[debian]
vm1
vm2
vm3

[centos]
confluence
vm-server1
gitlab

[ubuntu]
trusty-mirror
media-centre
nas

Nimega defineerimise korral tuleb siis muidugi lisada hosts faili vastav seos

Käsurealt kasutamine

Ansible kasutab enamuse asjade tegemiseks mooduleid. Nende abil paigaldab ta tarkvara, kopeerib faile jne. Sedalaadi kasutamist nimetatakse tavaliselt ad-hoc kasutamiseks ning kasutada saab kõiki moodulite parameetreid. Näiteks kasutame esimese näitajana moodulit ping ja teeme kõikide nodede korrasoleku kontrolli

# ansible all -m ping

Küsime nodedelt hostname käsku

# ansible -m shell -a "hostname" all

Samamoodi võib käsurealt otse teha ka jõhkramaid toiminguid, nt midagi installida

# ansible all -s -m shell -a 'apt-get install nginx'

Kindlas grupis nt grupis debian käskude käivitamiseks. Samamoodi käib ka üksikutes masinates playboopide käivitamine

# ansible -l debian -m ping

Kõigi kasutatavate moodulite nimekirja leiab https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

Tekitame kasutaja ja genereerime talle parooli

ansible all -m user -a "name=ants shell=/bin/bash home=/home/ants createhome=true password={ { 'parool' | password_hash('sha512') } }"

Playbook

Playbookid on .yml failid, kus defineeritakse Ansible tegevused ja tegevuste järjekord. Ühe tavalise playbooki ülesehitus on järgnev

#YAML faili päis
---
 # millistes serverites playbook käivitatakse, antud juhul kõigis
- hosts: all
 tasks:
 - name: esimene ülesanne
 ping:

NB! Tabuleeritus on ansible konfis väga oluline ja võib sageli põhjustada arusaamatuid vigu. See võib olla uskumatult tüütu kui sageli võib mõni moodul anda raskesti mõistetavat viga seepärst, et mõne käsu ees on liiga palju või vähe tühikuid.

Näiteks lihtne playbook mis paigaldab ngxinxi apt moodulit kasutades ning paneb selle tööle.

---
- hosts: debian
  tasks:
    - name: Installs nginx web server
      apt: pkg=nginx state=installed update_cache=true
      notify:
        - start nginx

  handlers:
    - name: start nginx
      service: name=nginx state=started

Nende käivitamiseks

# ansible-playbook test.yml

Kindlas grupis serveritele käivitamiseks

# ansible-playbook -l debian test.yml

Keerukam lahendus, mis juba lisaks paigaldab vaikimisi nginx konfi ja tõmbab alla ka gitist veebiserveri sisu

---
- hosts: debian
  sudo: yes
  
  tasks: 

  - name: paigaldame nginx
    apt: name=nginx state=installed update_cache=yes

  - name: loome nginxile konfiguratsiooni
    template: src=templates/nginx.conf.j2 dest=/etc/nginx/nginx.conf
    notify: restart nginx

  - name: paigaldame veebiserverisse sisu
    git: repo=https://github.com/jweissig/episode-47.git
         dest=/usr/share/nginx/html/
         version=release-0.01

  - name: start
    service: name=nginx state=started

  handlers:

  - name: restart nginx
    service: name=nginx state=restarted

Kolmas näide

---
- hosts: debian
  tasks:
    - name: "Install Apache, MySQL, and PHP5"
      apt: name=Mall:Item state=present
      with_items:
        - apache2
        - mysql-server
        - python-mysqldb
        - php5
        - php-pear
        - php5-mysql

    - name: "Turn on Apache and MySQL and set them to run on boot"
      service: name=Mall:Item state=started enabled=yes
      with_items:
        - apache2
        - mysql

    - name: Create a test database
      mysql_db: name=testDb
                state=present

   - name: Create a new user for connections
     mysql_user: name=webapp 
                 password=mypassword 
                 priv=*.*:ALL state=present

Neljas, kus kasutatakse ka olekute registreerimist ja nende alusel tegevuse jätkamist koos notify käsuga

tasks:
   - name: Add Nginx Repository
     apt_repository:
       repo: ppa:nginx/stable
       state: present
     register: ppastable

   - name: Install Nginx
     apt:
       pkg: nginx
       state: installed
       update_cache: true
     when: ppastable|success
     notify:
      - Start Nginx

Muutujad ja olekud

Kõige lihtsam viis on lisada muutujaid nagu nt kasutajad, paroolid jms playbooki algusse var sektsiooni

 vars:
   NORMAL_USER_NAME: 'yourusername'

Keerukamate süsteemide ja playbookide puhul on mõistlik koguda muutujaid masina ja grupipõhiselt kaustadesse host_vars ja group_vars. Tekitame näiteks masina test1 jaoks faili host_vars/test1' ja lisame sinna mingi muutuja

"test_db_passord": "a_super_secret",

Seda muutujat (ja veel ka teisi) saame näha käsuga

$ ansible -m debug -a "var=hostvars[inventory_hostname]" test1

Saab teha ka selliseid muutujate võrdlusi

vars:
  epic: true
Then a conditional execution might look like:

tasks:
    - shell: echo "This certainly is epic!"
      when: epic

Või välistada

tasks:
    - shell: echo "This certainly isn't epic!"
      when: not epic

Või siis lihtsalt kontrollida nende eksisteerimist

 - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
   when: foo is defined
 
 - fail: msg="Bailing out. this play requires 'bar'"
   when: bar is not defined

Võimalik on ka eri masina rollides pärida teiste masinate host_vars all olevaid muutujaid

"{{ hostvars['test1']['mysql_password']}}"

Üks olulisem muutujate tekitamise vahend on käsk register. Antud näites saab koguda uname -r töödeldud väljundi muutujasse kernel_shell_output ja seda kasutada kohe hetk hiljem võrdluses kas kerneli versioon on sobiv

  - name: Get Kernel version
    shell: uname -r | egrep '^[0-9]*\.[0-9]*' -o
    register: kernel_shell_output
  - name: Add cstate and reboot bios if kernel is 4.8
    shell: echo "do what yo need to do"
    when: kernel_shell_output.stdout == "4.8"

Kogume stat mooduli abil kasutaja faili kohta infot ning salvestame selle kasutaja_exists muutujasse

- name: config | check kasutaja file
  stat:
    path: /srv/db/kasutaja
  register: kasutaja_exists

Neid kogutud andmeid saame nüüd kasutavad when tingimusega teise moodulite juures. Näiteks kontrollida faili olemasolu, selle õigusi või omanikku. Näiteks saame faili olemasolu korral kopeerida sinna kausta veel midagi

 - name: config | copy skript files
   copy:
     src: "{{ item.src }}"
     dest: "{{ item.dest }}"
     owner: "{{ item.owner }}"
     group: "{{ item.group }}"
     mode: "{{ item.mode }}"
   with_items:
       - { src: 'kasutaja.sh', dest: '/srv/failover.sh', owner: 'test', group: 'test', mode: '0700' }
   when: kasutaja_exists.stat.exists == True

selleks, et näha mis muutujate väärtused on mis on kasutaja_exista alla kogutud võib lisada konfi rea

- debug:
    msg: "binary_path: { { kasutaja_exists } }"

Muutujate nimekirja kasutamine

files.yml:

---
modules:
  - firmware-system-p89-2.56_2018_01_22-1.1.i386.rpm
  - firmware-smartarray-ea3138d8e8-6.30-1.1.x86_64.rpm

Playbook:

---
- hosts: my_hosts
  vars_files:
    - files.yml
  tasks:
    - name: print module name one by one
      debug:
        msg: "{{ item }}"
      with_items: "{{ modules }}"

Nimekiri saab olla ka rohkemate valikutega:

 - name: create users
 user: name={{ item.name }} group={{ item.group }} state=present shell={{ item.shell }}
 with_items:
 - { name: 'user1', group: 'group1', shell: '/bin/bash' }
 - { name: 'daemon-user', group: 'group2', shell: '/sbin/nologin' }

Ning luua lausa eraldi tabeleid kõikvõimaliku infoga ning neid töödelda:

---
users:
  alice:
    name: Alice Appleworth
    telephone: 123-456-7890
  bob:
    name: Bob Bananarama
    telephone: 987-654-3210

tasks:
  - name: Print phone records
    debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
    with_dict: users

Template kasutamine

Templatedega saab luua vaikekonfe, mis paigaldamise ajal täidetakse vastavalt masinale sobiva infoga. Näiteks haproxyle konfi puhul käiks see järgnevalt

Esimesena tuleb luua templaatide kataloog

mkdir templates

Seejärel tekitame näiteks haproxy konfiguratsiooni

nano templates/haproxy.cfg.j2

Konfi lisame järgnevad read

 global
   log 127.0.0.1 local0 notice
   maxconn 2000
   user haproxy
   group haproxy 
 
 defaults
   log     global
   mode    http
   option  httplog
   option  dontlognull
   retries 3
   option redispatch
   timeout connect  5000
   timeout client  10000
   timeout server  10000
 
 listen {{haproxy_app_name}} 0.0.0.0:80
  mode {{haproxy_mode}}
  stats {{haproxy_enable_stats}}
  {% if haproxy_enable_stats == 'enable' %}
  stats uri /haproxy?stats
  stats realm Strictly\ Private
  {% for user in haproxy_stats_users %}
  stats auth {{user.username}}:{{user.password}}
  {% endfor %}
  {% endif %}
  balance {{haproxy_algorithm}}
  option httpclose
  option forwardfor
  {% for server in haproxy_backend_servers %}
  server {{server.name}} {{server.ip}}:{{server.port}} {{server.paramstring}}
  {% endfor %}

Järgmisena defineerime konfitemplates olevad muutujad playbooki

vars:
  haproxy_app_name: myapp
  haproxy_mode: http
  haproxy_enable_stats: enable 
  haproxy_algorithm: roundrobin
  haproxy_backend_servers:
    - {name: server1, ip: 10.133.181.247, port: 80, paramstring: cookie A check}
    - {name: server2, ip: 10.133.186.46, port: 80, paramstring: cookie A check}
  haproxy_stats_users:
   - {username: joe, password: soap}

Ja kõige viimasena seome konfi ja template kokku

- name: Update HAProxy config
  template: src=templates/haproxy.cfg 
        dest=/etc/haproxy/haproxy.cfg 
        backup=yes


If-else abil on võimalik luua ka keerukamaid tingimuste konstruktsioone. Näiteks kui konfiguratsioonis on võti defineeritud seadistatakse muutuja number üheks kui pole siis kaheks

{% if key| default(false) %}
 muutuja: 1
{% else %}
  muutuja = 2
{% endif %}

Aga nii saab seadistada ka teisi muutujaid nt

{% if filepath == '/var/opt/tomcat_1' %}
  {% set tomcat_value = tomcat_1_value %}
{% else %}
  {% set tomcat_value = tomcat_2_value %}
{% endif %}

Samuti saab kirjutada konfiguratsiooni vastavalt masina gruppi kuuluvuse alusel

{% for host in groups['serverid'] %}
...
{% endfor %}

Või genereerida tsükli alusel infot

 {% for id in range(100,200) %}  
 192.168.0.{{ id }} client{{ "%02d"|format(id-200) }}.vpn  
 {% endfor %}

Moodulid

Ansible sisaldab lisaks suurt hulka mooduleid praktiliselt kõige tegemiseks. Moodulite nimekirja näeb

# ansible-doc -l

Näiteks saab importida mooduli abil postgresi dump faili

---
- hosts: postgres-server
  tasks:
  - name: Restore db server
    postgresql_db: name=example state=import target=/example.sql

Samuti on võimalik apache veebiserverit seadistada spetsiifilise mooduli abil

   - name: enabled mod_rewrite
     apache2_module: name=rewrite state=present

Postfixi installimisel küsimustele vastamine

---
- name: Set Postfix option hostname
  debconf: 
    name=postifx 
    question="postfix/mailname" 
    value="sandbox" 
    vtype="string"

- name: Set Postfix option type as internet site
  debconf: 
    name=postfix 
    question="postfix/main_mailer_type" 
    value="'Internet Site'" 
    vtype="string"

- name: install postfix
  apt: name=postfix state=present

Rollid

Rollid on hea vahend, mille abil grupeerida hulga erinevaid taske ning infot, mis vaja nende taskide saavutamiseks.

Ühe rolli struktuur näeb väljajärgnev, tehniliselt on roll nagu väike ansible playbooki kaust playbooki kausta sees

roles
|__ defaults

    |__ main.yml - Sisaldab vaikimisi seadistavaid muutujaid

|__ files        - Failid mis kopeeritakse ilma muutusteta hosti ümber

|__ templates    - jinja2 formaadis templaadid, mis sisaldavad vajalikke muutujaid, et genereerida igale hostile sobivaid konfiguratsoone-faile
|__ tasks        - each play can contain multiple task, and each task can perform multiple actions.
    |__ main.yml

|__ meta         - Keskkonna info, autor, litsents jms
    |__ main.yml

|__ vars         - Erinevad muutujad
    |__ main.yml

|__ handlers     - Taskid, mis käivitatakse teiste taskide eduka lõpetamise korral, nt teenustele tehtavad restardid.

Tühja rolliskeleti loomiseks nimega nginx

# ansible-galaxy init nginx

Valmis rolle saab otsida ja tõmmata internetist

# ansible-galaxy search elasticsearch --author geerlingguy

Found 5 roles matching your search:

Name                              Description
 ----                              -----------
geerlingguy.elasticsearch         Elasticsearch for Linux.
geerlingguy.elasticsearch-curator Elasticsearch curator for Linux.
geerlingguy.filebeat              Filebeat for Linux.
geerlingguy.kibana                Kibana for Linux.
geerlingguy.logstash              Logstash for Linux.

https://cloudrkt.com/roles-like-a-boss.html lisalugemist rollide struktuurist ja nende koostamisest

Ansible vault

Ansible vault pakub võimaluse mingeid olulisemaid paroole ja faile. Tavaliselt kürpteeritakse group_vars kaustas olevad failid. Paroolifail, automaatseks lahtikrüpteerimiseks tuleb süsteemis paigaldada /root/.ansible/pgpool-ansible/vault_password faili

Ühe yms faili krüpteerimiseks

ansible-vault encrypt defaults/main.yml

Seejärel küsib programm kaks korda parooli ja krüpteerib faili ära. Selle muutmiseks on käsk

ansible-vault edit defaults/main.yml

Editori seadmistamiseks mis käivitatakse on keskkonnamuutuja $EDITOR.

Järgneva käsuga saab krüoteerida ühe muutuja

ansible-vault encrypt_string 'abc123' --name mysql_password
mysql_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          32363163316532353639316531396132353930353732353634343835313533626166656233356438
          6666616638663266383563346233373432633761303434650a313265393664663863356466356430
          39626361396361663234323539656232373264303637306165643632343438313839363961326136
          3732393639646635630a363165653266613532643433323435373762623137646437343830623235
          3731
Encryption successful

Seda kas muutuja sisu on õige saab testida debugi abil

- debug:
    msg: "mysql Pwd: Mall:Mysql password"

Lingid

http://jensd.be/587/linux/tips-tricks-for-ansible

https://github.com/randohinn/KnowHow/blob/master/docs/Vorgurakendused/ansible.rst

https://github.com/asjalik/ansible

http://docs.ansible.com/ansible/latest/proxmox_module.html

http://docs.ansible.com/ansible/latest/mysql_db_module.html

https://github.com/rhwlo/ansible-playbooks/blob/master/mailserver.yml

https://github.com/asjalik/ansible eestikeeles