Ansible
Sisukord
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
Ansible kasutuselevõtuks pole vaja palju teha. Piisab kui paigaldada masinasse, kus hakkame ansible käske käivitama, ansible kliendi. Hallatavatesse masinatesse klienti tarvis pole, piisava vaid ssh võtmest.
Ansible kliendi paigaldamiseks
# apt-get install ansible
Kõisse hallatavasse masinatesse tuleb paigaldada SSH võti. Selleks genereerime ta esmalt valmis
# ssh-keygen -t rsa'
Ja kopeerime järgneva käsuga ükshaaval ükshaaval kõigisse serveritesse
# ssh-copy-id -i .ssh/id_rsa.pub kasutaja@test-node
Kliendi defineerimine toimub aktiivses kataloogis asuvas failis nimega hosts, näiteks lisame sinna test-node nimelist serveri ning loome talle gruppi nimega serverid
[serverid] test-node ansible_host=10.20.0.20
Selliseid gruppe võib luua piiramatul hulgal, ning juba ühes grupis olevaid masinaid võib jagada ka teiste gruppide alla
[debian] test-node5 [centos] test-node3 test-node4 [ubuntu] test-node1 test-node2 [serverid] test-node1 ansible_host=10.20.0.20 test-node2 ansible_host=10.20.0.21 test-node3 ansible_host=10.20.0.22 test-node4 ansible_host=10.20.0.23 test-node5 ansible_host=10.20.0.24
Käsurealt kasutamine
Ansible kasutab kõigi 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 käivitame kõigi hosts failis olevate masinate pihta moodulit ping ja kontrollime kas noded on võimelised meile vastama
# 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 aktiivses kataloogis oleva 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') } }"
Kõigi masina poolt saadaolevate muutujate vaatamiseks
$ ansible -m debug -a "var=hostvars[inventory_hostname]" test1
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 kõigi muutujate uurimisest
- name: "Ansible | List all known variables and facts"
debug:
var: hostvars['host']
Host masina välise IP aadressi hankimiseks
- name: get server ip
shell: curl ifconfig.co
register: ip
Koodis saab seda kasutada järgneva muutujana
"{{ ip.stdout_lines[0] }}"
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
Failis muutuja nimega TOKEN muutmiseks
- name: Eeplace string replace: path: /etc/zabbix/mingiskript.conf regexp: 'TOKEN' replace: kood
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 saame kasutada ansibl playbookides ning template failides järgneva koodiga
{{ a_super_secret }}
Muutujaid on võimalik varustada ka vaikeväärtusega, nt kui virtual_router_id pole kuskil defineeritud seadistatakse selleks 1
{{ virtual_router_id | default('1') }}
Lisaks saab muutujate alusel luua playbooki tingimusi
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. Lisaks muutujate asendamisele võib luua neisse failidesse ka keerukamaid konstruktsioone näiteks kasutada if-else võrdlusi stiilis
{% if lb_priority == 101 %}
state MASTER
{% else %}
state BACKUP
{% endif %}
Terviklik näide haproxy configuratsiooni templatest, kus võetakse serverite loed ning muud vajalikud muutujad playbookist
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 }}"
Kui sa ei taha, et see sisu logisse jõuaks, siis kasuta taski juures lisaks
no_log: True
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