Ansible Playbook vs Role: Bila Perlu Gunakan Setiap Satu
Ketahui perbezaan antara Ansible playbook dan role untuk automasi anda. Kami jelaskan bila anda perlu beralih daripada fail YAML rata kepada struktur direktori role.
Perbezaan antara Ansible playbook dan role
Ansible playbook ialah fail yang anda jalankan dengan ansible-playbook. Ia memetakan sekumpulan hos kepada tugasan yang perlu dilaksanakan. Ansible role pula ialah direktori dengan struktur tetap yang mengandungi tasks, templates, handlers dan default variables, dan playbook akan memanggilnya mengikut nama. Sintaks task di dalam kedua-duanya adalah sama, jadi ini bukan persoalan tentang apa yang boleh anda lakukan. Ini adalah persoalan tentang penggunaan semula.
Mulakan dengan playbook yang rata. Satu site.yml yang mengandungi senarai tasks: adalah bentuk yang tepat untuk automasi pertama anda, dan ia kekal sesuai untuk tempoh yang lebih lama daripada jangkaan kebanyakan orang. Tukar kepada role apabila blok tugasan yang sama perlu dijalankan untuk kumpulan hos kedua, atau apabila fail tersebut melebihi kira-kira 100 baris dan anda tidak lagi dapat mencari tugasan dengan menatal.
Jika anda belum menulisnya lagi, mulakan dengan playbook pertama terhadap satu VPS dan kembali semula apabila ia mula berkembang.
Apabila playbook rata adalah jawapan yang tepat
Playbook rata adalah pilihan yang tepat apabila tugasan hanya dilakukan sekali, atau pada satu hos sahaja, atau apabila tiada orang lain yang akan membacanya. Melakukan provisioning pada satu pelayan aplikasi, atau menampal (patch) satu mesin sebelum tempoh penyelenggaraan: kedua-duanya tidak memerlukan struktur direktori yang kompleks. Penggunaan role menambah tujuh direktori dan satu lapisan indirection. Jika pemanggil tunggal hanyalah playbook yang berada di sebelahnya, indirection tersebut tidak memberikan sebarang faedah malah menyukarkan anda kerana perlu melompat ke fail lain setiap kali ingin membaca arahan yang sebenar.
Playbook rata tidak lagi menjadi pilihan yang tepat pada satu ketika, dan saat itu mudah untuk dikenal pasti. Anda menyalin satu blok tugas ke dalam playbook kedua. Salinan itulah tandanya. Bermula dari saat itu, setiap pembetulan perlu dibuat dua kali, dan suatu hari nanti, ia pasti hanya akan dibuat sekali sahaja.
Kandungan sebenar direktori peranan
roles/common/
defaults/main.yml
vars/main.yml
tasks/main.yml
handlers/main.yml
templates/99-hardening.conf.j2
files/
meta/main.ymltasks/main.ymlialah titik masuk. Ansible menjalankan fail ini apabila peranan dipanggil, dan setiap direktori lain adalah pilihan.defaults/main.ymlmenyimpan pemboleh ubah yang dijangka akan ditindih oleh pemanggil. Ia merupakan sumber keutamaan paling rendah dalam Ansible, jadi hampir semua perkara lain mengatasi nilainya.vars/main.ymlmenyimpan pemboleh ubah yang tidak dijangka akan ditindih oleh pemanggil. Ia berada di atas inventori dari segi keutamaan, yang merupakan pernyataan yang kuat. Gunakannya dengan jarang.handlers/main.ymlmenyimpan tugasan yang dicetuskan olehnotify. Pengendali (handler) dijalankan pada akhir play, sekali sahaja, tidak kira berapa banyak tugasan yang memberitahunya.files/menyimpan fail yang disalin secara verbatim oleh modulcopy, dantemplates/menyimpan templat Jinja2 yang dirender oleh modultemplate. Di dalam peranan, anda merujuk kedua-duanya dengan nama fail sahaja tanpa laluan, kerana Ansible mencari direktori peranan itu sendiri terlebih dahulu.meta/main.ymlmengisytiharkan dependensi peranan dan metadata yang dibaca oleh Ansible Galaxy.
Susun atur ini bukan sekadar pilihan gaya. Ansible mencari dalam laluan tepat ini, jadi templat yang anda letakkan dalam roles/common/template/ (kata tunggal) tidak akan ditemui sama sekali.
Bina peranan umum dengan ansible-galaxy init
mkdir -p ~/infra/roles
cd ~/infra
ansible-galaxy init --init-path roles commonPerintah tersebut menulis keseluruhan rangka di bawah roles/common, termasuk direktori yang tidak akan anda gunakan dan stub main.yml yang hanya mengandungi ---. Padamkan fail yang dibiarkan kosong. vars/main.yml yang kosong tidak menjejaskan Ansible, tetapi ia menyembunyikan fail mana dalam peranan tersebut yang sebenarnya penting.
Sekarang, isikan fail yang melaksanakan tugasan. Mulakan dengan defaults, kerana ia merupakan antara muka awam bagi peranan tersebut.
# roles/common/defaults/main.yml
---
common_packages:
- ufw
- fail2ban
- unattended-upgrades
common_admin_group: admins
common_permit_root_login: "no"
common_password_authentication: "no"Gunakan tanda petikan untuk "no" dan "yes". Ansible menghuraikan YAML menggunakan PyYAML, yang membaca no kosong sebagai boolean false, jadi baris konfigurasi yang dirender menjadi PermitRootLogin False dan sshd akan menolaknya. Tanda petikan mengekalkan nilai tersebut sebagai rentetan (string).
# roles/common/tasks/main.yml
---
- name: Install the base packages
ansible.builtin.apt:
name: "{{ common_packages }}"
state: present
update_cache: true
cache_valid_time: 3600
- name: Create the admin group
ansible.builtin.group:
name: "{{ common_admin_group }}"
state: present
- name: Install the sshd hardening drop-in
ansible.builtin.template:
src: 99-hardening.conf.j2
dest: /etc/ssh/sshd_config.d/99-hardening.conf
owner: root
group: root
mode: "0644"
validate: /usr/sbin/sshd -t -f %s
notify: Restart sshd# roles/common/handlers/main.yml
---
- name: Restart sshd
ansible.builtin.service:
name: ssh
state: restarted# roles/common/templates/99-hardening.conf.j2
# Managed by Ansible. Local edits are overwritten on the next run.
PermitRootLogin {{ common_permit_root_login }}
PasswordAuthentication {{ common_password_authentication }}Pada Debian dan Ubuntu, unit systemd dipanggil ssh, manakala pada sistem keluarga RHEL, ia adalah sshd. Handler yang menamakan unit yang salah hanya akan gagal apabila sesuatu benar-benar mengubah templat, itulah sebabnya masalah ini biasanya timbul selepas beberapa minggu.
Baris validate adalah perkara paling berguna dalam tugasan tersebut. Ansible merender templat ke fail sementara, menggantikan laluan fail tersebut untuk %s, dan menjalankan perintah. Destinasi hanya akan diganti jika perintah tersebut keluar dengan kod 0. Masukkan arahan yang tidak sah ke dalam templat dan jalankan semula: tugasan akan gagal dengan failed to validate, /etc/ssh/sshd_config.d/99-hardening.conf yang sebenar tidak disentuh, dan anda masih mempunyai pelayan yang boleh diakses. Perlu diingat bahawa semakan ini menguji lebih daripada sekadar sintaks anda. Jika sshd -t tidak dapat membaca kunci hos, ia akan keluar dengan sshd: no hostkeys available -- exiting. dan Ansible melaporkan failed to validate yang sama, jadi baca msg modul tersebut sebelum menyalahkan templat.
Cara playbook memanggil peranan
# site.yml
---
- name: Base configuration for every server
hosts: all
become: true
roles:
- common# inventory.ini
[local]
localhost ansible_connection=localansible-playbook -i inventory.ini site.ymlPlay tersebut harus berakhir dengan failed=0 dalam ringkasan. Hantarkan parameter di tapak panggilan menggunakan bentuk yang dikembangkan, iaitu cara satu peranan melayani dua kumpulan hos:
roles:
- role: common
common_admin_group: ops
common_permit_root_login: prohibit-passwordTerdapat satu peraturan susunan yang mengejutkan hampir semua orang. Sesuatu play boleh mengandungi pre_tasks, roles, tasks dan post_tasks, dan Ansible akan menjalankannya mengikut susunan tersebut tanpa mengira susunan yang anda tulis dalam fail. Letakkan tasks: di atas roles: dan peranan tersebut tetap akan dijalankan terlebih dahulu. Jadi, jika sesuatu perkara mesti berlaku sebelum peranan, ia perlu diletakkan dalam pre_tasks:, bukan di bahagian atas tasks:.
- name: Ordering demonstration
hosts: local
gather_facts: false
pre_tasks:
- name: Runs first
ansible.builtin.debug:
msg: pre
roles:
- common
tasks:
- name: Runs after the role
ansible.builtin.debug:
msg: task
post_tasks:
- name: Runs last
ansible.builtin.debug:
msg: postUntuk memanggil peranan dari dalam senarai tugas dan bukannya menggunakan kunci roles:, gunakan import_role atau include_role.
tasks:
- name: Static, read when the playbook is parsed
ansible.builtin.import_role:
name: common
- name: Dynamic, resolved when the task runs
ansible.builtin.include_role:
name: postgres
when: "'db' in group_names"import_role adalah statik. Ansible membaca peranan tersebut pada masa penghuraian (parse time) dan tugas-tugasnya menjadi sebahagian daripada play, jadi ansible-playbook --list-tasks site.yml akan menyenaraikannya dan tag pada import akan terpakai pada setiap tugas di dalamnya. include_role adalah dinamik. Tiada apa-apa yang dibaca sehingga tugas tersebut dijalankan, itulah yang membolehkan anda menentukan nama peranan daripada pemboleh ubah atau gelung. Kekurangannya ialah tugas-tugas tersebut tidak kelihatan kepada --list-tasks dan --start-at-task.
Satu perangkap wujud di sini. when: pada tugas include_role dinilai sebelum defaults/main.yml peranan yang disertakan berada dalam skop. Tulis when: common_packages | length > 0 pada include dan pelaksanaan akan terhenti dengan 'common_packages' is undefined, walaupun pemboleh ubah tersebut ditakrifkan dalam peranan yang anda sertakan itu sendiri. Penyelesaiannya adalah dengan mengalihkan togol tersebut keluar daripada peranan: letakkannya dalam group_vars/all.yml, di mana ia berada dalam skop di mana-mana sahaja, dan biarkan nilai lalai peranan untuk nilai yang digunakan oleh peranan itu sendiri.
Pemboleh ubah mana yang menang: defaults, group_vars, vars, extra vars
Ansible mendokumentasikan lebih daripada dua puluh tahap keutamaan pemboleh ubah. Empat daripadanya menyelesaikan hampir setiap perdebatan sebenar, dan berikut adalah susunannya daripada yang paling lemah kepada yang paling kuat.
roles/<name>/defaults/main.ymlberada hampir di bahagian bawah. Hampir apa sahaja yang anda tetapkan di tempat lain akan mengatasinya, itulah sebabnya ia merupakan tempat yang sesuai untuk parameter boleh laras bagi sesuatu peranan (role).group_vars/danhost_vars/berada di tengah. Di sinilah jawapan khusus tapak anda diletakkan, dan ia mengatasi nilai lalai peranan dengan kemas.roles/<name>/vars/main.ymlberada di atashost_vars. Nilai yang anda letakkan di sini tidak boleh diatasi daripada inventori. Simpan ia untuk perkara yang diperlukan oleh peranan tersebut bagi mengekalkan konsistensi dalaman, seperti nama pakej yang perlu sepadan dengan nama servis.- Parameter peranan yang dihantar di tapak panggilan mengatasi
vars/main.yml, dan-epada baris perintah mengatasi segala-galanya, termasuk parameter peranan.
Anda boleh melihat proses penyelesaian ini dalam masa kira-kira satu minit. Berikan satu nilai lalai dan satu pemboleh ubah peranan kepada peranan kecil, kemudian tetapkan nama yang sama dalam host_vars.
# roles/prec/defaults/main.yml
---
prec_tunable: from-defaults
prec_internal: from-defaults# roles/prec/vars/main.yml
---
prec_internal: from-rolevars# host_vars/localhost.yml
---
prec_tunable: from-hostvars
prec_internal: from-hostvars# roles/prec/tasks/main.yml
---
- name: Show which value survived
ansible.builtin.debug:
msg: "tunable={{ prec_tunable }} internal={{ prec_internal }}"ansible-playbook -i inventory.ini prec.yml
ansible-playbook -i inventory.ini prec.yml -e prec_internal=from-cliJalankan pertama mencetak tunable=from-hostvars internal=from-rolevars. Inventori mengatasi nilai lalai peranan tetapi kalah kepada pemboleh ubah peranan. Jalankan kedua mencetak internal=from-cli, kerana extra vars berada di kedudukan paling atas dan tiada apa-apa di bawahnya yang boleh mengubahnya. Itulah juga sebabnya -e sesuai untuk jalankan sekali sahaja tetapi salah jika digunakan dalam skrip yang anda simpan: ia secara senyap mengatasi setiap keputusan yang dipertimbangkan dalam repositori anda.
Peraturan kerja: jika anda mahu sesuatu nilai boleh ditetapkan, letakkannya dalam defaults/. Meletakkannya dalam vars/ memberitahu setiap pengguna peranan pada masa hadapan bahawa inventori mungkin tidak boleh mengubahnya. Kadangkala itu adalah maksud anda, tetapi biasanya ia adalah satu kesilapan.
Buktikan peranan tersebut adalah idempoten: jalankan dua kali
Jalankan Ansible yang boleh dipercayai akan menghasilkan keputusan yang sama pada kali kedua dan melaporkan bahawa tiada perubahan dilakukan. Jalankan playbook dua kali dan baca rumusan (recap) yang diberikan.
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.ymlRumusan kedua sepatutnya kelihatan seperti ini:
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0changed=0 bermaksud setiap modul telah memeriksa keadaan semasa dan mendapati kerja tersebut telah pun selesai. changed=2 pada larian kedua bermaksud dua tugasan tidak dapat membezakan keadaan, jadi ia akan terus menulis semula fail dan memulakan semula servis selama-lamanya. Punca biasa ialah command atau shell, kerana Ansible tidak mempunyai cara untuk mengetahui apa yang dilakukan oleh arahan sewenang-wenangnya.
# traps.yml
---
- name: Command modules do not know what they changed
hosts: local
gather_facts: false
tasks:
- name: This appends a line on every run
ansible.builtin.shell: "echo run >> /tmp/grow.txt"
- name: This appends a line only once
ansible.builtin.shell: "echo run >> /tmp/guarded.txt"
args:
creates: /tmp/guarded.txtJalankan playbook itu dua kali, kemudian kira baris yang mengandungi wc -l /tmp/grow.txt /tmp/guarded.txt. /tmp/grow.txt mengandungi dua baris dan /tmp/guarded.txt mengandungi satu. Pada larian kedua, tugasan yang dikawal (guarded task) tidak dilaksanakan langsung, dan hasilnya membawa mesej skipped, since /tmp/guarded.txt exists, kerana creates memberikan modul produk yang boleh dilihat untuk dicari terlebih dahulu. Apabila sesuatu arahan tidak meninggalkan produk sedemikian, daftarkan outputnya dan buat keputusan sendiri dengan changed_when.
ansible-playbook --check --diff site.yml meramalkan perubahan tanpa melaksanakannya, dan --diff mencetak baris tepat yang akan ditulis semula oleh templat. Baca output tersebut dengan satu peringatan: tugasan shell dan command dilangkau dalam mod semakan (check mode), jadi pelan yang kelihatan bersih masih boleh menyembunyikan kerja yang akan dilakukan.
Satu lagi lajur dalam rumusan tersebut memerlukan perhatian yang sama: hos yang tidak dapat dihubungkan oleh Ansible dikira di bawah unreachable dan bukannya failed, dan tiada satu pun tugasannya dijalankan. Oleh itu, tentukan lebih awal sama ada satu hos yang tidak boleh dicapai harus menghentikan keseluruhan larian sebelum anda menghalakan peranan ini kepada lebih daripada beberapa buah mesin.
Mengapa Ansible menyatakan peranan tidak ditemui
Ansible mencari direktori roles/ di sebelah fail playbook, kemudian di dalam roles_path. Carian ini mengikut lokasi playbook, bukan shell anda.
ERROR! the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonelyMesej tersebut bermaksud site.yml dan roles/ tidak lagi selari, dan ia mencetak laluan yang telah dicuba sebagai bantuan. Pastikan kedua-duanya berada dalam direktori yang sama. Menjalankan arahan dari direktori induk adalah dibolehkan, kerana laluan playbook adalah perkara yang diambil kira:
ansible-playbook -i infra/inventory.ini infra/site.ymlTerdapat versi masalah yang sama tetapi lebih senyap. Ansible mengabaikan ansible.cfg dalam direktori semasa apabila direktori tersebut boleh ditulis oleh sesiapa sahaja (world writable), kerana mana-mana pengguna pada sistem boleh meletakkan konfigurasi di sana dan mengubah tindakan yang dijalankan oleh anda.
[WARNING]: Ansible is being run in a world writable directory (/tmp/infra), ignoring it as an ansible.cfg source.Tetapan roles_path dan inventory anda kemudiannya tiada secara senyap, dan carian peranan gagal atas sebab yang tiada kaitan dengan peranan. ansible --version mencetak config file yang sebenarnya dimuatkan, dan ansible-config dump --only-changed mencetak setiap tetapan yang berbeza daripada lalai terbina dalam. Semak kedua-duanya apabila sesuatu proses berjalan seolah-olah konfigurasi anda tidak wujud.
Perkongsian peranan: requirements.yml dan versi yang dipinkan
Peranan yang ditulis oleh orang lain perlu dipasang, bukan disalin. Isytiharkannya sekali sahaja:
# requirements.yml
---
roles:
- name: postgres
src: https://github.com/example/ansible-role-postgres
scm: git
version: v1.4.0ansible-galaxy install -r requirements.yml -p galaxy_rolesSentiasa tetapkan version. Tanpanya, anda akan mendapat apa sahaja kandungan cawangan lalai pada hari anda menjalankan perintah tersebut, menyebabkan penggunaan (deployment) yang berjaya bulan lepas gagal walaupun tiada perubahan dalam repositori anda sendiri. Halakan roles_path ke direktori muat turun, dan pastikan direktori tersebut tidak dimasukkan ke dalam git:
# ansible.cfg
[defaults]
inventory = inventory.ini
roles_path = ./galaxy_rolesPeranan dalam roles/ bersebelahan dengan playbook masih ditemui, kerana laluan tersebut sentiasa dicari sebagai tambahan kepada roles_path. Oleh itu, peranan anda sendiri kekal dikomit dan disemak, manakala peranan pihak ketiga adalah muat turun yang boleh dihasilkan semula dan dipinkan pada tag tertentu.
Apabila peranan bukan lagi penyelesaiannya
Peranan ialah unit guna semula dalam satu pelaksanaan Ansible. Ia tidak mencipta pelayan atau rekod DNS di penyedia anda, dan cubaan untuk menjadikannya melakukan perkara tersebut akan menyebabkan playbook menjadi sesuatu yang tidak mahu diselenggara oleh sesiapa. pembahagian kerja antara Ansible dan Terraform wajar dibaca sebelum anda bermula. Peranan juga tidak menggantikan reka bentuk inventori: sebaik sahaja anda menguruskan lebih daripada beberapa buah mesin, cara anda mengumpul dan mencapai pelayan tersebut adalah lebih penting daripada cara tugasan difailkan.
Pengukuhan (hardening) yang dipasang oleh peranan common ini juga memerlukan keputusan tersendiri. Konfigurasi tambahan di atas hanya menetapkan dua arahan dan tidak lebih daripada itu, jadi baca tetapan SSH yang sebenarnya berbaloi untuk diubah dan cara membolehkan Ubuntu melaksanakan kemas kini keselamatan secara automatik sebelum anda memutuskan perkara yang perlu dimasukkan ke dalam peranan untuk setiap hos yang anda miliki.
FAQ
Bilakah saya perlu menukar playbook Ansible kepada role?
Apabila blok tugas yang sama perlu dijalankan dalam play kedua, atau terhadap kumpulan hos kedua. Menyalin tugas antara playbook adalah petanda, kerana mulai saat itu setiap pembetulan perlu dilakukan dua kali dan suatu hari nanti ia hanya akan dilakukan sekali. Playbook tunggal yang mempunyai kira-kira 100 baris dan hanya menyasarkan satu kumpulan tidak mendapat manfaat daripada role, malah direktori tambahan menjadikannya lebih sukar untuk dibaca.
Adakah role dijalankan sebelum tugas dalam play yang sama?
Ya. Ansible menjalankan pre_tasks, kemudian semua yang disenaraikan di bawah roles:, kemudian tasks:, kemudian post_tasks:, dan ia mengabaikan susunan kunci tersebut muncul dalam fail anda. Menulis tasks: di atas roles: tidak menyebabkan tugas tersebut dijalankan terlebih dahulu. Jika sesuatu perlu berlaku sebelum role, letakkannya dalam pre_tasks:.
Mengapa nilai group_vars saya tidak mengatasi role?
Semak sama ada pemboleh ubah ditetapkan dalam vars/main.yml role tersebut dan bukannya defaults/main.yml. vars/ berada di atas group_vars dan host_vars dalam susunan keutamaan Ansible, jadi inventori tidak boleh mengatasinya. Alihkan pemboleh ubah tersebut ke defaults/main.yml, yang berada hampir di bahagian bawah susunan dan merupakan tempat yang betul untuk sebarang perkara yang perlu diubah oleh pemanggil. Untuk mengesahkan bahawa keutamaan adalah puncanya dan bukannya kesilapan taip, jalankan sekali dengan -e name=value, yang mengatasi setiap sumber lain.
Mengapa Ansible menyatakan role tidak ditemui?
Carian bermula bersebelahan dengan fail playbook, jadi site.yml dan roles/ mesti berada dalam direktori yang sama. Ralat tersebut mencetak laluan yang telah dicuba, seperti dalam the role 'common' was not found in /home/deploy/lonely/roles:/home/deploy/lonely. Menjalankan playbook daripada direktori induk adalah dibolehkan, kerana carian mengikut laluan playbook dan bukannya direktori kerja shell anda. Jika anda bergantung pada roles_path daripada ansible.cfg, pastikan fail tersebut dimuatkan dengan ansible --version, kerana direktori kerja yang boleh ditulis oleh semua orang (world writable) akan menyebabkan Ansible mengabaikannya.
Adakah saya perlu menggunakan ansible-galaxy init untuk mencipta role?
Tidak. Role hanyalah direktori dengan nama yang dijangkakan, jadi mkdir -p roles/common/tasks berserta tasks/main.yml sudah menjadi role yang berfungsi. ansible-galaxy init --init-path roles common menjimatkan masa menaip dan memberikan anda rangka penuh, termasuk meta/main.yml dan stub README. Padamkan direktori yang anda biarkan kosong, kerana vars/main.yml yang kosong menyembunyikan fail mana dalam role yang sebenarnya melakukan sesuatu.