Nedolgo nazaj sem moral napisati več knjig Ansible, da bi pripravil strežnik za uvedbo aplikacije Rails. In, presenetljivo, nisem našel preprostega priročnika po korakih. Nisem želel kopirati knjige nekoga drugega, ne da bi razumel, kaj se dogaja, in na koncu sem moral prebrati dokumentacijo in vse zbrati sam. Morda lahko komu pomagam pospešiti ta proces s pomočjo tega članka.
Prva stvar, ki jo morate razumeti, je, da vam ansible ponuja priročen vmesnik za izvajanje vnaprej določenega seznama dejanj na oddaljenem strežniku(-ih) prek SSH. Tu ni nobene čarovnije, ne morete namestiti vtičnika in zagotoviti uvedbe svoje aplikacije brez izpadov z dockerjem, spremljanjem in drugimi dobrotami, ki so že pripravljene. Če želite napisati knjigo iger, morate vedeti, kaj točno želite narediti in kako to narediti. Zato nisem zadovoljen z že pripravljenimi knjigami iger iz GitHuba ali članki, kot je: "Kopiraj in zaženi, bo delovalo."
Kaj potrebujemo?
Kot sem že rekel, če želite napisati knjigo iger, morate vedeti, kaj želite narediti in kako to narediti. Odločimo se, kaj potrebujemo. Za aplikacijo Rails bomo potrebovali več sistemskih paketov: nginx, postgresql (redis itd.). Poleg tega potrebujemo posebno različico rubyja. Najbolje ga je namestiti preko rbenv (rvm, asdf...). Izvajanje vsega tega kot root uporabnik je vedno slaba ideja, zato morate ustvariti ločenega uporabnika in konfigurirati njegove pravice. Po tem morate našo kodo naložiti na strežnik, kopirati konfiguracije za nginx, postgres itd. in zagnati vse te storitve.
Posledično je zaporedje dejanj naslednje:
- Prijavite se kot root
- namestitev sistemskih paketov
- ustvarite novega uporabnika, konfigurirajte pravice, ključ ssh
- konfigurirajte sistemske pakete (nginx itd.) in jih zaženite
- Ustvarimo uporabnika v bazi (bazo lahko ustvarite takoj)
- Prijavite se kot nov uporabnik
- Namestite rbenv in ruby
- Namestitev svežnja
- Nalaganje kode aplikacije
- Zagon strežnika Puma
Poleg tega je zadnje stopnje mogoče izvesti s capistranom, vsaj izven škatle lahko kopira kodo v imenike izdaje, preklopi izdajo s simbolno povezavo po uspešni uvedbi, kopira konfiguracije iz skupnega imenika, znova zažene pumo itd. Vse to je mogoče storiti z uporabo Ansible, ampak zakaj?
Struktura datoteke
Ansible ima stroge
Simple Playbook
Playbook je datoteka yml, ki s posebno sintakso opisuje, kaj naj naredi Ansible in kako. Ustvarimo prvo knjigo iger, ki ne dela ničesar:
---
- name: Simple playbook
hosts: all
Tukaj preprosto rečemo, da se naša knjiga igranja imenuje Simple Playbook
in da mora biti njegova vsebina izvedena za vse gostitelje. Lahko ga shranimo v imenik /ansible z imenom playbook.yml
in poskusite zagnati:
ansible-playbook ./playbook.yml
PLAY [Simple Playbook] ************************************************************************************************************************************
skipping: no hosts matched
Ansible pravi, da ne pozna nobenega gostitelja, ki bi ustrezal seznamu vseh. Navedeni morajo biti v posebnem
Ustvarimo ga v istem imeniku ansible:
123.123.123.123
Tako preprosto določimo gostitelja (v idealnem primeru gostitelja našega VPS za testiranje ali pa lahko registrirate localhost) in ga shranimo pod imenom inventory
.
Ansible lahko poskusite zagnati z datoteko popisa:
ansible-playbook ./playbook.yml -i inventory
PLAY [Simple Playbook] ************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
PLAY RECAP ************************************************************************************************************************************
Če imate dostop ssh do navedenega gostitelja, se bo ansible povezal in zbral informacije o oddaljenem sistemu. (privzeta NALOGA [Zbiranje dejstev]), po kateri bo podal kratko poročilo o izvedbi (PLAY RECAP).
Povezava privzeto uporablja uporabniško ime, pod katerim ste prijavljeni v sistem. Najverjetneje ne bo na gostitelju. V datoteki playbook lahko določite, katerega uporabnika želite uporabiti za povezavo z uporabo direktive remote_user. Prav tako so lahko informacije o oddaljenem sistemu za vas pogosto nepotrebne in ne izgubljajte časa z njihovim zbiranjem. To opravilo je mogoče tudi onemogočiti:
---
- name: Simple playbook
hosts: all
remote_user: root
become: true
gather_facts: no
Poskusite znova zagnati priročnik in se prepričajte, da povezava deluje. (Če ste določili uporabnika root, morate določiti tudi direktivo become: true, da pridobite povišane pravice. Kot je zapisano v dokumentaciji: become set to ‘true’/’yes’ to activate privilege escalation.
čeprav ni povsem jasno zakaj).
Morda boste prejeli napako, ki jo povzroči dejstvo, da ansible ne more določiti tolmača Python, potem ga lahko določite ročno:
ansible_python_interpreter: /usr/bin/python3
Z ukazom lahko ugotovite, kje imate python whereis python
.
Namestitev sistemskih paketov
Ansibleova standardna distribucija vključuje veliko modulov za delo z različnimi sistemskimi paketi, tako da nam iz kakršnega koli razloga ni treba pisati bash skriptov. Zdaj potrebujemo enega od teh modulov za posodobitev sistema in namestitev sistemskih paketov. Na svojem VPS imam Ubuntu Linux, zato za namestitev paketov uporabljam apt-get
и
Dopolnimo naš zvezek s prvimi nalogami:
---
- name: Simple playbook
hosts: all
remote_user: root
become: true
gather_facts: no
tasks:
- name: Update system
apt: update_cache=yes
- name: Install system dependencies
apt:
name: git,nginx,redis,postgresql,postgresql-contrib
state: present
Naloga je točno tista naloga, ki jo bo Ansible izvajal na oddaljenih strežnikih. Nalogi damo ime, da lahko spremljamo njeno izvedbo v dnevniku. In s sintakso določenega modula opišemo, kaj mora narediti. V tem primeru apt: update_cache=yes
- pravi posodobitev sistemskih paketov z uporabo modula apt. Drugi ukaz je nekoliko bolj zapleten. Seznam paketov posredujemo modulu apt in povemo, da so state
bi moral postati present
, kar pomeni, da namestite te pakete. Na podoben način jim lahko rečemo, naj jih izbrišejo ali posodobijo tako, da preprosto spremenijo state
. Upoštevajte, da za delo rails s postgresql potrebujemo paket postgresql-contrib, ki ga zdaj nameščamo. Še enkrat, to morate vedeti in narediti; ansible sam po sebi tega ne bo naredil.
Poskusite znova zagnati priročnik in preverite, ali so paketi nameščeni.
Ustvarjanje novih uporabnikov.
Za delo z uporabniki ima Ansible tudi modul - uporabnik. Dodajmo še eno nalogo (že znane dele priročnika sem skril za komentarje, da ga ne bi vsakič v celoti kopiral):
---
- name: Simple playbook
# ...
tasks:
# ...
- name: Add a new user
user:
name: my_user
shell: /bin/bash
password: "{{ 123qweasd | password_hash('sha512') }}"
Ustvarimo novega uporabnika, mu nastavimo schell in geslo. In potem naletimo na številne težave. Kaj pa, če morajo biti uporabniška imena različna za različne gostitelje? In shranjevanje gesla v obliki čistega besedila v priročniku je zelo slaba ideja. Za začetek vstavimo uporabniško ime in geslo v spremenljivke, proti koncu članka pa bom pokazal, kako šifriramo geslo.
---
- name: Simple playbook
# ...
tasks:
# ...
- name: Add a new user
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
Spremenljivke so v knjigah iger nastavljene z dvojnimi zavitimi oklepaji.
Navedli bomo vrednosti spremenljivk v datoteki popisa:
123.123.123.123
[all:vars]
user=my_user
user_password=123qweasd
Upoštevajte direktivo [all:vars]
- pravi, da so naslednji blok besedila spremenljivke (vars) in so uporabne za vse gostitelje (all).
Zanimiv je tudi dizajn "{{ user_password | password_hash('sha512') }}"
. Stvar je v tem, da ansible ne namesti uporabnika prek user_add
kot bi to naredili ročno. In vse podatke shrani neposredno, zato moramo tudi geslo vnaprej pretvoriti v zgoščeno vrednost, kar ta ukaz tudi naredi.
Dodajmo našega uporabnika v skupino sudo. Pred tem pa se moramo prepričati, da takšna skupina obstaja, ker tega nihče ne bo naredil namesto nas:
---
- name: Simple playbook
# ...
tasks:
# ...
- name: Ensure a 'sudo' group
group:
name: sudo
state: present
- name: Add a new user
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
groups: "sudo"
Vse je precej preprosto, imamo tudi skupinski modul za ustvarjanje skupin, s sintakso, ki je zelo podobna apt. Potem je dovolj, da to skupino registrirate uporabniku (groups: "sudo"
).
Temu uporabniku je koristno dodati tudi ključ ssh, da se lahko z njim prijavimo brez gesla:
---
- name: Simple playbook
# ...
tasks:
# ...
- name: Ensure a 'sudo' group
group:
name: sudo
state: present
- name: Add a new user
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
groups: "sudo"
- name: Deploy SSH Key
authorized_key:
user: "{{ user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
V tem primeru je dizajn zanimiv "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
— kopira vsebino datoteke id_rsa.pub (vaše ime je lahko drugačno), to je javni del ključa ssh in ga naloži na seznam avtoriziranih ključev za uporabnika na strežniku.
Vloge
Vse tri naloge za ustvarjanje uporabe zlahka razvrstimo v eno skupino nalog, pri čemer bi bilo dobro to skupino shraniti ločeno od glavnega playbooka, da se ne bi preveč razraščala. V ta namen ima Ansible
Glede na datotečno strukturo, navedeno na samem začetku, morajo biti vloge postavljene v ločen imenik vlog, za vsako vlogo obstaja ločen imenik z istim imenom, znotraj imenika nalog, datotek, predlog itd.
Ustvarimo datotečno strukturo: ./ansible/roles/user/tasks/main.yml
(main je glavna datoteka, ki bo naložena in izvedena, ko je vloga povezana z playbook; z njo se lahko povežejo druge datoteke vlog). Zdaj lahko vse naloge, povezane z uporabnikom, prenesete v to datoteko:
# Create user and add him to groups
- name: Ensure a 'sudo' group
group:
name: sudo
state: present
- name: Add a new user
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
groups: "sudo"
- name: Deploy SSH Key
authorized_key:
user: "{{ user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
V glavnem priročniku morate določiti uporabo uporabniške vloge:
---
- name: Simple playbook
hosts: all
remote_user: root
gather_facts: no
tasks:
- name: Update system
apt: update_cache=yes
- name: Install system dependencies
apt:
name: git,nginx,redis,postgresql,postgresql-contrib
state: present
roles:
- user
Prav tako je morda smiselno posodobiti sistem pred vsemi drugimi opravili; za to lahko preimenujete blok tasks
v kateri so opredeljeni v pre_tasks
.
Nastavitev nginx
Nginx bi že morali imeti nameščen; moramo ga konfigurirati in zagnati. Naredimo to takoj v vlogi. Ustvarimo datotečno strukturo:
- ansible
- roles
- nginx
- files
- tasks
- main.yml
- templates
Zdaj potrebujemo datoteke in predloge. Razlika med njima je v tem, da ansible neposredno kopira datoteke, takšne kot so. In predloge morajo imeti pripono j2 in lahko uporabljajo spremenljive vrednosti z istimi dvojnimi zavitimi oklepaji.
Omogočimo nginx main.yml
mapa. Za to imamo modul systemd:
# Copy nginx configs and start it
- name: enable service nginx and start
systemd:
name: nginx
state: started
enabled: yes
Tukaj ne rečemo le, da je treba nginx zagnati (torej ga zaženemo), ampak takoj rečemo, da mora biti omogočen.
Zdaj pa kopirajmo konfiguracijske datoteke:
# Copy nginx configs and start it
- name: enable service nginx and start
systemd:
name: nginx
state: started
enabled: yes
- name: Copy the nginx.conf
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
- name: Copy template my_app.conf
template:
src: my_app_conf.j2
dest: /etc/nginx/sites-available/my_app.conf
owner: root
group: root
mode: '0644'
Ustvarimo glavno konfiguracijsko datoteko nginx (lahko jo vzamete neposredno s strežnika ali pa jo napišete sami). In tudi konfiguracijsko datoteko za našo aplikacijo v imeniku sites_available (to ni potrebno, je pa uporabno). V prvem primeru za kopiranje datotek uporabimo modul za kopiranje (datoteka mora biti v /ansible/roles/nginx/files/nginx.conf
). V drugem kopiramo predlogo in nadomestimo vrednosti spremenljivk. Predloga mora biti notri /ansible/roles/nginx/templates/my_app.j2
). In lahko izgleda nekako takole:
upstream {{ app_name }} {
server unix:{{ app_path }}/shared/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name {{ server_name }} {{ inventory_hostname }};
root {{ app_path }}/current/public;
try_files $uri/index.html $uri.html $uri @{{ app_name }};
....
}
Bodite pozorni na vložke {{ app_name }}
, {{ app_path }}
, {{ server_name }}
, {{ inventory_hostname }}
— to so vse spremenljivke, katerih vrednosti bo Ansible nadomestil v predlogo pred kopiranjem. To je uporabno, če uporabljate priročnik za različne skupine gostiteljev. Dodamo lahko na primer svojo datoteko inventarja:
[production]
123.123.123.123
[staging]
231.231.231.231
[all:vars]
user=my_user
user_password=123qweasd
[production:vars]
server_name=production
app_path=/home/www/my_app
app_name=my_app
[staging:vars]
server_name=staging
app_path=/home/www/my_stage
app_name=my_stage_app
Če zdaj zaženemo naš playbook, bo opravil določene naloge za oba gostitelja. Toda hkrati bodo spremenljivke za uprizoritvenega gostitelja drugačne od produkcijskih, ne samo v vlogah in knjigah iger, ampak tudi v konfiguracijah nginx. {{ inventory_hostname }}
jih ni treba navesti v popisni datoteki - to
Če želite imeti datoteko inventarja za več gostiteljev, vendar izvajati samo za eno skupino, lahko to storite z naslednjim ukazom:
ansible-playbook -i inventory ./playbook.yml -l "staging"
Druga možnost je, da imate ločene datoteke inventarja za različne skupine. Lahko pa združite oba pristopa, če imate veliko različnih gostiteljev.
Vrnimo se k nastavitvi nginx. Po kopiranju konfiguracijskih datotek moramo ustvariti simbolno povezavo v sitest_enabled do my_app.conf iz sites_available. In znova zaženite nginx.
... # old code in mail.yml
- name: Create symlink to sites-enabled
file:
src: /etc/nginx/sites-available/my_app.conf
dest: /etc/nginx/sites-enabled/my_app.conf
state: link
- name: restart nginx
service:
name: nginx
state: restarted
Tukaj je vse preprosto - spet ansible moduli z dokaj standardno sintakso. Vendar obstaja ena točka. Nima smisla vsakič znova zagnati nginx. Ali ste opazili, da ne pišemo ukazov, kot je: "naredi to takole", sintaksa izgleda bolj kot "to bi moralo imeti to stanje". In najpogosteje ansible deluje natanko tako. Če skupina že obstaja ali je sistemski paket že nameščen, bo ansible preveril to in preskočil nalogo. Prav tako datoteke ne bodo kopirane, če se popolnoma ujemajo s tem, kar je že na strežniku. To lahko izkoristimo in znova zaženemo nginx le, če so bile konfiguracijske datoteke spremenjene. Za to obstaja direktiva registra:
# Copy nginx configs and start it
- name: enable service nginx and start
systemd:
name: nginx
state: started
enabled: yes
- name: Copy the nginx.conf
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
register: restart_nginx
- name: Copy template my_app.conf
template:
src: my_app_conf.j2
dest: /etc/nginx/sites-available/my_app.conf
owner: root
group: root
mode: '0644'
register: restart_nginx
- name: Create symlink to sites-enabled
file:
src: /etc/nginx/sites-available/my_app.conf
dest: /etc/nginx/sites-enabled/my_app.conf
state: link
- name: restart nginx
service:
name: nginx
state: restarted
when: restart_nginx.changed
Če se ena od konfiguracijskih datotek spremeni, bo narejena kopija in spremenljivka bo registrirana restart_nginx
. In samo če je bila ta spremenljivka registrirana, se bo storitev znova zagnala.
In, seveda, morate dodati vlogo nginx v glavni playbook.
Nastavitev postgresql
Omogočiti moramo postgresql z uporabo systemd na enak način, kot smo to storili z nginxom, poleg tega pa ustvariti uporabnika, ki ga bomo uporabljali za dostop do baze podatkov in baze same.
Ustvarimo vlogo /ansible/roles/postgresql/tasks/main.yml
:
# Create user in postgresql
- name: enable postgresql and start
systemd:
name: postgresql
state: started
enabled: yes
- name: Create database user
become_user: postgres
postgresql_user:
name: "{{ db_user }}"
password: "{{ db_password }}"
role_attr_flags: SUPERUSER
- name: Create database
become_user: postgres
postgresql_db:
name: "{{ db_name }}"
encoding: UTF-8
owner: "{{ db_user }}"
Ne bom opisoval, kako dodati spremenljivke v inventar, to je bilo že velikokrat storjeno, kot tudi sintakso modulov postgresql_db in postgresql_user. Več informacij najdete v dokumentaciji. Tu je najbolj zanimiva direktiva become_user: postgres
. Dejstvo je, da ima privzeto le uporabnik postgres dostop do podatkovne baze postgresql in samo lokalno. Ta direktiva nam omogoča izvajanje ukazov v imenu tega uporabnika (če seveda imamo dostop).
Prav tako boste morda morali dodati vrstico v pg_hba.conf, da omogočite novemu uporabniku dostop do baze podatkov. To lahko storite na enak način, kot smo spremenili konfiguracijo nginx.
In seveda, morate dodati vlogo postgresql v glavni priročnik.
Namestitev ruby prek rbenv
Ansible nima modulov za delo z rbenv, ampak se namesti s kloniranjem repozitorija git. Zato ta problem postane najbolj nestandarden. Ustvarimo vlogo zanjo /ansible/roles/ruby_rbenv/main.yml
in začnimo ga izpolnjevati:
# Install rbenv and ruby
- name: Install rbenv
become_user: "{{ user }}"
git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenv
Ponovno uporabimo direktivo become_user za delo pod uporabnikom, ki smo ga ustvarili za te namene. Ker je rbenv nameščen v domačem imeniku in ne globalno. Prav tako uporabljamo modul git za kloniranje repozitorija, pri čemer določimo repo in dest.
Nato moramo registrirati rbenv init v bashrc in tam dodati rbenv v PATH. Za to imamo modul lineinfile:
- name: Add rbenv to PATH
become_user: "{{ user }}"
lineinfile:
path: ~/.bashrc
state: present
line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"'
- name: Add rbenv init to bashrc
become_user: "{{ user }}"
lineinfile:
path: ~/.bashrc
state: present
line: 'eval "$(rbenv init -)"'
Nato morate namestiti ruby_build:
- name: Install ruby-build
become_user: "{{ user }}"
git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-build
In končno namestite ruby. To se naredi prek rbenv, to je preprosto z ukazom bash:
- name: Install ruby
become_user: "{{ user }}"
shell: |
export PATH="${HOME}/.rbenv/bin:${PATH}"
eval "$(rbenv init -)"
rbenv install {{ ruby_version }}
args:
executable: /bin/bash
Povemo kateri ukaz izvršiti in s čim. Vendar tukaj naletimo na dejstvo, da ansible ne zažene kode, ki jo vsebuje bashrc, preden zažene ukaze. To pomeni, da bo treba rbenv definirati neposredno v istem skriptu.
Naslednja težava je posledica dejstva, da lupinski ukaz nima stanja z ansibilnega vidika. To pomeni, da ne bo samodejnega preverjanja, ali je ta različica rubyja nameščena ali ne. To lahko naredimo sami:
- name: Install ruby
become_user: "{{ user }}"
shell: |
export PATH="${HOME}/.rbenv/bin:${PATH}"
eval "$(rbenv init -)"
if ! rbenv versions | grep -q {{ ruby_version }}
then rbenv install {{ ruby_version }} && rbenv global {{ ruby_version }}
fi
args:
executable: /bin/bash
Vse kar ostane je, da namestite bundler:
- name: Install bundler
become_user: "{{ user }}"
shell: |
export PATH="${HOME}/.rbenv/bin:${PATH}"
eval "$(rbenv init -)"
gem install bundler
In še enkrat, dodajte našo vlogo ruby_rbenv v glavno knjigo iger.
Datoteke v skupni rabi.
Na splošno bi lahko nastavitev dokončali tukaj. Nato ostane le še zagnati capistrano in ta bo sam kopiral kodo, ustvaril potrebne imenike in zagnal aplikacijo (če je vse pravilno nastavljeno). Vendar capistrano pogosto zahteva dodatne konfiguracijske datoteke, kot npr database.yml
ali .env
Lahko jih kopirate tako kot datoteke in predloge za nginx. Obstaja samo ena subtilnost. Preden kopirate datoteke, morate zanje ustvariti strukturo imenikov, nekako takole:
# Copy shared files for deploy
- name: Ensure shared dir
become_user: "{{ user }}"
file:
path: "{{ app_path }}/shared/config"
state: directory
določimo samo en imenik in ansible bo po potrebi samodejno ustvaril nadrejene.
Ansible trezor
Naleteli smo že na dejstvo, da lahko spremenljivke vsebujejo tajne podatke, kot je uporabniško geslo. Če ste ustvarili .env
datoteko za prijavo in database.yml
potem mora biti takih kritičnih podatkov še več. Dobro bi jih bilo skriti pred radovednimi očmi. V ta namen se uporablja
Ustvarimo datoteko za spremenljivke /ansible/vars/all.yml
(tukaj lahko ustvarite različne datoteke za različne skupine gostiteljev, tako kot v datoteki popisa: production.yml, staging.yml itd.).
Vse spremenljivke, ki morajo biti šifrirane, je treba prenesti v to datoteko z uporabo standardne sintakse yml:
# System vars
user_password: 123qweasd
db_password: 123qweasd
# ENV vars
aws_access_key_id: xxxxx
aws_secret_access_key: xxxxxx
aws_bucket: bucket_name
rails_secret_key_base: very_secret_key_base
Nato lahko to datoteko šifrirate z ukazom:
ansible-vault encrypt ./vars/all.yml
Seveda boste morali pri šifriranju nastaviti geslo za dešifriranje. Po klicu tega ukaza lahko vidite, kaj bo v datoteki.
S ansible-vault decrypt
datoteko je mogoče dešifrirati, spremeniti in nato znova šifrirati.
Za delovanje vam ni treba dešifrirati datoteke. Shranite ga šifrirano in zaženete priročnik z argumentom --ask-vault-pass
. Ansible bo zahteval geslo, pridobil spremenljivke in izvedel naloge. Vsi podatki bodo ostali šifrirani.
Celoten ukaz za več skupin gostiteljev in ansible trezor bo videti nekako takole:
ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass
Vendar vam ne bom izdal celotnega besedila knjig in vlog, napišite ga sami. Ker je ansible tak - če ne razumete, kaj je treba storiti, potem tega ne bo naredil namesto vas.
Vir: www.habr.com