Ansible

Allikas: Kuutõrvaja
Redaktsioon seisuga 20. jaanuar 2020, kell 20:51 kasutajalt Jj (arutelu | kaastöö) (Mõned playbookis kasutatavate tööde näited)

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

Või kopeerime kõigisse masinatesse sama hosts faili

# ansible all -m copy -a "src=hosts dest=/etc/hosts"

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 zabbix agendi, kopeerib konfiguratsiooni ning paneb selle tööle.

# -*- coding: utf-8; indent-tabs-mode: nil; tab-width: 2; -*-

---
- name: Setup ssh keys
  become: yes
  hosts: all
  tasks:
    - name: Enable package repositories
      yum: name={{ item }}
      with_items:
        - https://repo.zabbix.com/zabbix/4.4/rhel/7/x86_64/zabbix-release-4.4-1.el7.noarch.rpm

    - name: Install packages
      package: name={{ item }}
      with_items:
        - zabbix-agent

    - name: Configure Zabbix agent
      copy: src=./monitoring/zabbix_agentd.conf dest=/etc/zabbix/zabbix_agentd.conf owner=zabbix group=zabbix mode='0660'

    - name: Enable and start Zabbix agent
      service: name=zabbix-agent state=started enabled=yes

Nende käivitamiseks

# ansible-playbook test.yml

Kindlas grupis serveritele käivitamiseks

# ansible-playbook -l debian test.yml

Võimalik on playbooki käivitada vaid ka ühele hostile

# ansible-playbook --limit <node_name> install.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={{ 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={{ 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

Mõned playbookis kasutatavate tööde näited

Igasugune probleemide lahendamine algab alati hosti poolt saadaolevate muutujate näitamisest

 -   name: "Ansible | List all known variables and facts"
     debug:
       var: hostvars['host']

Kontrollimiseks kas ip aadressi on võimalik pingida

 - name: Check VIP
   local_action: shell ping -q -c 1 -W 1 "{{ ip }}"
   register: res
   retries: 5
   until: ('0% packet loss' in res.stdout)
   failed_when: ('100.0% packet loss' in res.stdout)
   changed_when: no

Croni failide loomine, eelnevalt on vajalik tekitada ansible seadistusse databases muutuja

 - name: Loo cronjob PostgreSQL varundamiseks
   cron:
     name: "{{ item.name }} backup"
     weekday: "0-6"
     minute: "30"
     hour: "02"
     user: postgres
     job: "pg_dump {{ item.name }} | gzip -9 > /var/lib/pgsql/backups/{{ item.name }}-$(date +'%Y%m%dT%H%M%S').sql.gz"
     cron_file: "{{ item.name }}-backup"
   with_items: "{{ databases }}"

Cron mis eemaldab postgresi vanu varukoopiaid

 - name: Create Eemalda vanad PostgreSQL varukoopiad
   cron:
     name: Eemalda vanad PostgreSQL varukoopiad
     weekday: "0-6"
     minute: "40"
     hour: "02"
     user: postgres
     job: "ls -tp /var/lib/pgsql/backups/ | grep -v '/$' | tail -n +30 | xargs -I {} rm -- {}"
     cron_file: remove_old_postgresql_backups

Kopeeri files kaustas olev fail userparameter.conf zabbixi konfiguratsiooni kausta

 - name: Copy userparameter.conf
   copy: src=userparameter_memory.conf dest=/etc/zabbix/zabbix_agentd.d/userparameter.conf owner=zabbix group=zabbix mode='0660'

Systemd abil teenuse restartimine

 - name: Restart zabbix-agent
   systemd: name=zabbix-agent state=restarted daemon_reload=yes

Firewalld tulemüüris pordi avamine

 - name: Opening port 10050
   firewalld: port=10050/tcp permanent=true state=enabled

Centosis paki paigaldamine

 - name: install zabbix-agent
   yum: name=zabbix-agent state=latest

Zabbix agendi süsteemi käivitumisel startimine

 - name: Enable and start  zabbix-agent
   service: name=zabbix-agent state=started enabled=yes

Self signed sertifikaatide genereerimine, vaja on tekitada web_server_name muutuja mis sisaldab domeeni

 - name: Generate an OpenSSL private key
   openssl_privatekey:
     path: /etc/pki/tls/private/kasutaja.key
 
 - name: Generate an OpenSSL Certificate Signing Request
   openssl_csr:
     path: /etc/pki/tls/certs/kasutaja.csr
     privatekey_path: /etc/pki/tls/private/kasutaja.key
     common_name: "{{ web_server_name }}"
 
 - name: Generate a Self Signed OpenSSL certificate
   openssl_certificate:
     path: /etc/pki/tls/certs/kasutaja.crt
     privatekey_path: /etc/pki/tls/private/kasutaja.key
     csr_path: /etc/pki/tls/certs/kasutaja.csr
     provider: selfsigned

Haagi NFS share

- name: Mount NFS share
  become: true
  mount:
    fstype: nfs
    opts: defaults
    src: {{ nfs_server }}:{{ nfs_directory }}
    path: {{ nfs_directory }}
    state: mounted

Lisa faili lõppu uus rida

- name: Insert a line at the end of a file
  lineinfile:
    path: /etc/test
    line: test

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

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

Mitme erineva tingimuse kontrollimiseks tuleb need paigaldada üksteise alla

when:
  - ansible_os_family == "RedHat"
  - security|d() !=  or kernel|d() !=  or specified_packages|d() != 

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"

Register abil salvestatud muutujaid saab kasutada ka teises ülesandes, nt saame küsida ketta UUID koodi ning kasutada seda mountimisel

- name: Get UUID for disk
  command: blkid -s UUID -o value /dev/vdb
  register: disk_blkid

- name: Mount up device by UUID
  mount:
    path: /srv
    src: 'UUID={{ disk_blkid.stdout|quote }}'
    fstype: xfs
    opts: noatime
    state: mounted

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

Lokaalses arvutis olevate failide olemasolu on samuti võimalik kontrollida

- name: get file stat to be able to perform a check in the following task
  local_action: stat path=/path/to/file
  register: file

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

 - name: add several users
   user:
     name: "{{ item }}"
     groups: "wheel"
     state: present
   with_items:
      - testuser1
      - testuser2

Keerukam näide kus nimekiri teises failis

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: {{ 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