Ansible βασικά, χωρίς τα οποία τα βιβλία σας θα είναι ένα κομμάτι κολλώδους ζυμαρικού

Κάνω πολλές κριτικές για τον κώδικα Ansible άλλων και γράφω πολλά ο ίδιος. Κατά τη διάρκεια της ανάλυσης λαθών (τόσο των άλλων όσο και των δικών μου), καθώς και ορισμένων συνεντεύξεων, συνειδητοποίησα το κύριο λάθος που κάνουν οι χρήστες του Ansible - μπαίνουν σε πολύπλοκα πράγματα χωρίς να κατακτούν τα βασικά.

Για να διορθώσω αυτή την καθολική αδικία, αποφάσισα να γράψω μια εισαγωγή στο Ansible για όσους το γνωρίζουν ήδη. Σας προειδοποιώ, αυτό δεν είναι μια επανάληψη των ανθρώπων, πρόκειται για μια μακροχρόνια ιστορία με πολλά γράμματα και χωρίς φωτογραφίες.

Το αναμενόμενο επίπεδο του αναγνώστη είναι ότι έχουν ήδη γραφτεί αρκετές χιλιάδες γραμμές yamla, κάτι είναι ήδη σε παραγωγή, αλλά «κάπως όλα είναι στραβά».

Ονόματα

Το κύριο λάθος που κάνει ένας χρήστης του Ansible είναι ότι δεν γνωρίζει πώς λέγεται κάτι. Εάν δεν γνωρίζετε τα ονόματα, δεν μπορείτε να καταλάβετε τι λέει η τεκμηρίωση. Ένα ζωντανό παράδειγμα: κατά τη διάρκεια μιας συνέντευξης, ένα άτομο που φαινόταν να λέει ότι έγραψε πολλά στο Ansible δεν μπορούσε να απαντήσει στην ερώτηση "από ποια στοιχεία αποτελείται ένα playbook;" Και όταν πρότεινα ότι «η απάντηση ήταν αναμενόμενη ότι το βιβλίο παιχνιδιού αποτελείται από παιχνίδι», ακολούθησε το καταδικαστικό σχόλιο «δεν το χρησιμοποιούμε αυτό». Οι άνθρωποι γράφουν Ansible για χρήματα και δεν χρησιμοποιούν το παιχνίδι. Στην πραγματικότητα το χρησιμοποιούν, αλλά δεν ξέρουν τι είναι.

Ας ξεκινήσουμε λοιπόν με κάτι απλό: πώς λέγεται. Ίσως το γνωρίζετε αυτό ή ίσως όχι, επειδή δεν δώσατε προσοχή όταν διαβάσατε την τεκμηρίωση.

Το ansible-playbook εκτελεί το playbook. Ένα playbook είναι ένα αρχείο με την επέκταση yml/yaml, μέσα στο οποίο υπάρχει κάτι σαν αυτό:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

Έχουμε ήδη συνειδητοποιήσει ότι ολόκληρο αυτό το αρχείο είναι ένα playbook. Μπορούμε να δείξουμε πού είναι οι ρόλοι και πού είναι οι εργασίες. Που είναι όμως το παιχνίδι; Και ποια είναι η διαφορά μεταξύ παιχνιδιού και ρόλου ή βιβλίου παιχνιδιού;

Είναι όλα στην τεκμηρίωση. Και τους λείπει. Αρχάριοι - επειδή υπάρχουν πάρα πολλά και δεν θα θυμάστε τα πάντα ταυτόχρονα. Έμπειρος - γιατί "τετριμμένα πράγματα". Εάν είστε έμπειροι, διαβάστε ξανά αυτές τις σελίδες τουλάχιστον μία φορά κάθε έξι μήνες και ο κώδικάς σας θα γίνει κορυφαίος στην κατηγορία.

Λοιπόν, θυμηθείτε: Το Playbook είναι μια λίστα που αποτελείται από παιχνίδι και import_playbook.
Αυτό είναι ένα θεατρικό έργο:

- hosts: group1
  roles:
    - role1

και αυτό είναι επίσης ένα άλλο θεατρικό έργο:

- hosts: group2,group3
  tasks:
    - debug:

Τι είναι το παιχνίδι; Γιατί είναι αυτή;

Το παιχνίδι είναι ένα βασικό στοιχείο για ένα playbook, επειδή το play and only play συσχετίζει μια λίστα ρόλων ή/και εργασιών με μια λίστα κεντρικών υπολογιστών στους οποίους πρέπει να εκτελεστούν. Στα βαθιά βάθη της τεκμηρίωσης μπορείτε να βρείτε αναφορά delegate_to, πρόσθετα τοπικής αναζήτησης, ρυθμίσεις για το δίκτυο-cli, jump hosts κ.λπ. Σας επιτρέπουν να αλλάξετε ελαφρώς το μέρος όπου εκτελούνται οι εργασίες. Αλλά, ξεχάστε το. Κάθε μία από αυτές τις έξυπνες επιλογές έχει πολύ συγκεκριμένες χρήσεις και σίγουρα δεν είναι καθολικές. Και μιλάμε για βασικά πράγματα που πρέπει να γνωρίζει και να χρησιμοποιεί ο καθένας.

Αν θέλεις να παίξεις «κάτι» «κάπου», γράφεις play. Όχι ρόλος. Όχι ρόλος με ενότητες και εκπροσώπους. Το παίρνεις και γράφεις play. Στο οποίο, στο πεδίο hosts αναφέρετε πού να εκτελεστεί και σε ρόλους/εργασίες - τι να εκτελεστεί.

Απλό, σωστά; Πώς θα μπορούσε να είναι διαφορετικά;

Μία από τις χαρακτηριστικές στιγμές που οι άνθρωποι έχουν την επιθυμία να το κάνουν αυτό όχι μέσω του παιχνιδιού είναι ο «ρόλος που ρυθμίζει τα πάντα». Θα ήθελα να έχω έναν ρόλο που να ρυθμίζει τόσο τους διακομιστές του πρώτου τύπου όσο και τους διακομιστές του δεύτερου τύπου.

Ένα αρχετυπικό παράδειγμα είναι η παρακολούθηση. Θα ήθελα να έχω έναν ρόλο παρακολούθησης που θα διαμορφώνει την παρακολούθηση. Ο ρόλος παρακολούθησης εκχωρείται στους κεντρικούς υπολογιστές παρακολούθησης (σύμφωνα με το παιχνίδι). Αλλά αποδεικνύεται ότι για την παρακολούθηση πρέπει να παραδώσουμε πακέτα στους οικοδεσπότες που παρακολουθούμε. Γιατί να μην χρησιμοποιήσετε το delegate; Πρέπει επίσης να διαμορφώσετε τα iptables. αντιπρόσωπος? Πρέπει επίσης να γράψετε/διορθώσετε μια διαμόρφωση για το DBMS για να ενεργοποιήσετε την παρακολούθηση. αντιπρόσωπος! Και αν λείπει η δημιουργικότητα, τότε μπορείτε να κάνετε μια αντιπροσωπεία include_role σε έναν ένθετο βρόχο χρησιμοποιώντας ένα δύσκολο φίλτρο σε μια λίστα ομάδων και μέσα include_role μπορείτε να κάνετε περισσότερα delegate_to πάλι. Και φεύγουμε...

Μια καλή επιθυμία - να έχουμε έναν μόνο ρόλο παρακολούθησης, που «κάνει τα πάντα» - μας οδηγεί στην πλήρη κόλαση από την οποία τις περισσότερες φορές υπάρχει μόνο μία διέξοδος: να ξαναγράψουμε τα πάντα από την αρχή.

Πού έγινε το λάθος εδώ; Τη στιγμή που ανακαλύψατε ότι για να κάνετε την εργασία "x" στον οικοδεσπότη Χ έπρεπε να πάτε στον οικοδεσπότη Y και να κάνετε "y" εκεί, έπρεπε να κάνετε μια απλή άσκηση: να πάτε και να γράψετε play, που στον κεντρικό υπολογιστή Y κάνει το y. Μην προσθέσετε κάτι στο "x", αλλά γράψτε το από την αρχή. Ακόμη και με μεταβλητές με σκληρό κώδικα.

Φαίνεται ότι όλα στις παραπάνω παραγράφους λέγονται σωστά. Αλλά αυτό δεν είναι η περίπτωσή σας! Επειδή θέλετε να γράψετε επαναχρησιμοποιήσιμο κώδικα που να είναι DRY και σαν βιβλιοθήκη και πρέπει να αναζητήσετε μια μέθοδο για το πώς να το κάνετε.

Εδώ ελλοχεύει άλλο ένα σοβαρό λάθος. Ένα σφάλμα που μετέτρεψε πολλά έργα από ανεκτά γραμμένα (θα μπορούσε να είναι καλύτερα, αλλά όλα λειτουργούν και είναι εύκολο να ολοκληρωθούν) σε έναν πλήρη τρόμο που ούτε ο συγγραφέας δεν μπορεί να καταλάβει. Λειτουργεί, αλλά ο Θεός να μην αλλάξεις κάτι.

Το σφάλμα είναι: ο ρόλος είναι μια συνάρτηση βιβλιοθήκης. Αυτή η αναλογία έχει καταστρέψει τόσα πολλά καλά ξεκινήματα που είναι απλά λυπηρό να το παρακολουθείς. Ο ρόλος δεν είναι λειτουργία βιβλιοθήκης. Δεν μπορεί να κάνει υπολογισμούς και δεν μπορεί να πάρει αποφάσεις σε επίπεδο παιχνιδιού. Θυμίστε μου ποιες αποφάσεις παίρνει το παιχνίδι;

Ευχαριστώ, έχεις δίκιο. Το Play λαμβάνει μια απόφαση (ακριβέστερα, περιέχει πληροφορίες) σχετικά με τις εργασίες και τους ρόλους που θα εκτελέσει σε ποιους οικοδεσπότες.

Εάν αναθέσετε αυτήν την απόφαση σε έναν ρόλο, και μάλιστα με υπολογισμούς, καταδικάζετε τον εαυτό σας (και αυτόν που θα προσπαθήσει να αναλύσει τον κωδικό σας) σε μια άθλια ύπαρξη. Ο ρόλος δεν αποφασίζει πού θα εκτελεστεί. Αυτή η απόφαση λαμβάνεται με παιχνίδι. Ο ρόλος κάνει αυτό που του λένε, εκεί που του λένε.

Γιατί είναι επικίνδυνο ο προγραμματισμός στο Ansible και γιατί το COBOL είναι καλύτερο από το Ansible θα μιλήσουμε στο κεφάλαιο για τις μεταβλητές και το jinja. Προς το παρόν, ας πούμε ένα πράγμα - κάθε ένας από τους υπολογισμούς σας αφήνει πίσω του ένα ανεξίτηλο ίχνος αλλαγών στις καθολικές μεταβλητές και δεν μπορείτε να κάνετε τίποτα γι 'αυτό. Μόλις τα δύο «ίχνη» διασταυρώθηκαν, όλα χάθηκαν.

Σημείωση για το squeamish: ο ρόλος μπορεί σίγουρα να επηρεάσει τη ροή ελέγχου. Τρώω delegate_to και έχει λογικές χρήσεις. Τρώω meta: end host/play. Αλλά! Θυμάστε ότι διδάσκουμε τα βασικά; Ξέχασα delegate_to. Μιλάμε για τον πιο απλό και όμορφο κώδικα Ansible. Που είναι εύκολο να διαβαστεί, εύκολο να γραφτεί, εύκολο να διορθωθεί, εύκολο στη δοκιμή και εύκολο να ολοκληρωθεί. Για άλλη μια φορά λοιπόν:

play και μόνο το play αποφασίζει σε ποιους οικοδεσπότες θα εκτελεστεί.

Σε αυτή την ενότητα, ασχοληθήκαμε με την αντίθεση μεταξύ παιχνιδιού και ρόλου. Τώρα ας μιλήσουμε για τα καθήκοντα και τη σχέση ρόλου.

Καθήκοντα και ρόλοι

Σκεφτείτε να παίξετε:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

Ας πούμε ότι πρέπει να κάνετε το τρελό. Και μοιάζει foo: name=foobar state=present. Πού να το γράψω αυτό; σε προ; Θέση? Δημιουργία ρόλου;

...Και πού πήγαν τα καθήκοντα;

Ξεκινάμε πάλι με τα βασικά - τη συσκευή αναπαραγωγής. Αν επιμείνετε σε αυτό το θέμα, δεν μπορείτε να χρησιμοποιήσετε το παιχνίδι ως βάση για όλα τα άλλα και το αποτέλεσμά σας θα είναι "τρεμμένο".

Συσκευή αναπαραγωγής: οδηγία κεντρικών υπολογιστών, ρυθμίσεις για το ίδιο το παιχνίδι και προ_εργασίες, εργασίες, ρόλοι, ενότητες μετά_εργασίες. Οι υπόλοιπες παράμετροι για το παιχνίδι δεν είναι σημαντικές για εμάς τώρα.

Η σειρά των τμημάτων τους με καθήκοντα και ρόλους: pre_tasks, roles, tasks, post_tasks. Δεδομένου ότι σημασιολογικά η σειρά εκτέλεσης είναι μεταξύ tasks и roles δεν είναι σαφές, τότε οι βέλτιστες πρακτικές λένε ότι προσθέτουμε μια ενότητα tasks, μόνο αν όχι roles... Αν υπάρχει roles, τότε όλες οι συνημμένες εργασίες τοποθετούνται σε ενότητες pre_tasks/post_tasks.

Το μόνο που μένει είναι ότι όλα είναι σημασιολογικά ξεκάθαρα: πρώτον pre_tasks, τότε roles, τότε post_tasks.

Αλλά ακόμα δεν έχουμε απαντήσει στην ερώτηση: πού είναι η κλήση της ενότητας; foo γράφω? Χρειάζεται να γράψουμε έναν ολόκληρο ρόλο για κάθε ενότητα; Ή μήπως είναι καλύτερο να έχεις χοντρό ρόλο για όλα; Και αν όχι ρόλος, τότε πού να γράψω - πριν ή μετά;

Εάν δεν υπάρχει αιτιολογημένη απάντηση σε αυτές τις ερωτήσεις, τότε αυτό είναι ένα σημάδι έλλειψης διαίσθησης, δηλαδή αυτών των ίδιων «σαθρών θεμελίων». Ας το καταλάβουμε. Πρώτον, μια ερώτηση ασφαλείας: Εάν το παιχνίδι έχει pre_tasks и post_tasks (και δεν υπάρχουν εργασίες ή ρόλοι), τότε μπορεί κάτι να σπάσει αν εκτελέσω την πρώτη εργασία από post_tasks Θα το μεταφέρω μέχρι το τέλος pre_tasks?

Φυσικά, η διατύπωση της ερώτησης αφήνει να εννοηθεί ότι θα σπάσει. Τι ακριβώς όμως;

... Χειριστές. Η ανάγνωση των βασικών αποκαλύπτει ένα σημαντικό γεγονός: όλοι οι χειριστές ξεπλένονται αυτόματα μετά από κάθε ενότητα. Εκείνοι. όλες οι εργασίες από pre_tasks, στη συνέχεια όλοι οι χειριστές που ειδοποιήθηκαν. Στη συνέχεια εκτελούνται όλοι οι ρόλοι και όλοι οι χειριστές που ειδοποιήθηκαν στους ρόλους. Μετά post_tasks και τους χειριστές τους.

Έτσι, εάν σύρετε μια εργασία από post_tasks в pre_tasks, τότε πιθανώς θα το εκτελέσετε πριν εκτελεστεί ο χειριστής. για παράδειγμα, εάν σε pre_tasks ο διακομιστής web εγκαθίσταται και ρυθμίζεται και post_tasks κάτι του αποστέλλεται και, στη συνέχεια, μεταφέρετε αυτήν την εργασία στην ενότητα pre_tasks θα οδηγήσει στο γεγονός ότι τη στιγμή της "αποστολής" ο διακομιστής δεν θα λειτουργεί ακόμα και όλα θα σπάσουν.

Τώρα ας σκεφτούμε ξανά, γιατί χρειαζόμαστε pre_tasks и post_tasks? Για παράδειγμα, για να ολοκληρώσετε όλα τα απαραίτητα (συμπεριλαμβανομένων των χειριστών) πριν από την εκπλήρωση του ρόλου. ΕΝΑ post_tasks θα μας επιτρέψει να εργαστούμε με τα αποτελέσματα της εκτέλεσης ρόλων (συμπεριλαμβανομένων των χειριστών).

Ένας οξυδερκής ειδικός του Ansible θα μας πει τι είναι. meta: flush_handlers, αλλά γιατί χρειαζόμαστε flush_handlers εάν μπορούμε να βασιστούμε στη σειρά εκτέλεσης των τμημάτων στο παιχνίδι; Επιπλέον, η χρήση του meta: flush_handlers μπορεί να μας δώσει απροσδόκητα πράγματα με διπλότυπους χειριστές, δίνοντάς μας περίεργες προειδοποιήσεις όταν χρησιμοποιούνται when у block και τα λοιπά. Όσο καλύτερα γνωρίζετε το ansible, τόσο περισσότερες αποχρώσεις μπορείτε να ονομάσετε για μια «δύσκολο» λύση. Και μια απλή λύση - χρησιμοποιώντας μια φυσική διαίρεση μεταξύ προ/ρόλων/μετά - δεν προκαλεί αποχρώσεις.

Και, πίσω στο «foo» μας. Που να το βάλω; Σε προ, μετά ή ρόλους; Προφανώς, αυτό εξαρτάται από το αν χρειαζόμαστε τα αποτελέσματα του χειριστή για foo. Εάν δεν υπάρχουν, τότε το foo δεν χρειάζεται να τοποθετηθεί ούτε στο pre ούτε στο post - αυτές οι ενότητες έχουν ιδιαίτερη σημασία - εκτελώντας εργασίες πριν και μετά το κύριο σώμα κώδικα.

Τώρα η απάντηση στην ερώτηση "ρόλος ή καθήκον" καταλήγει σε αυτό που ήδη παίζεται - εάν υπάρχουν εργασίες εκεί, τότε πρέπει να τις προσθέσετε στις εργασίες. Εάν υπάρχουν ρόλοι, πρέπει να δημιουργήσετε έναν ρόλο (ακόμα και από μία εργασία). Επιτρέψτε μου να σας υπενθυμίσω ότι οι εργασίες και οι ρόλοι δεν χρησιμοποιούνται ταυτόχρονα.

Η κατανόηση των βασικών στοιχείων του Ansible παρέχει λογικές απαντήσεις σε φαινομενικά γευστικά ερωτήματα.

Καθήκοντα και ρόλοι (μέρος δεύτερο)

Τώρα ας συζητήσουμε την κατάσταση όταν μόλις ξεκινάτε να γράφετε ένα βιβλίο. Πρέπει να φτιάξετε φούστα, μπαρ και μπαζ. Είναι αυτά τα τρία καθήκοντα, ένας ρόλος ή τρεις ρόλοι; Συνοψίζοντας το ερώτημα: σε ποιο σημείο πρέπει να ξεκινήσετε να γράφετε ρόλους; Τι νόημα έχει να γράφεις ρόλους όταν μπορείς να γράφεις εργασίες;... Τι είναι ένας ρόλος;

Ένα από τα μεγαλύτερα λάθη (το έχω ήδη μιλήσει) είναι να πιστεύουμε ότι ένας ρόλος είναι σαν μια λειτουργία στη βιβλιοθήκη ενός προγράμματος. Πώς μοιάζει μια γενική περιγραφή συνάρτησης; Αποδέχεται ορίσματα εισαγωγής, αλληλεπιδρά με παρενέργειες, κάνει παρενέργειες και επιστρέφει μια τιμή.

Τώρα, προσοχή. Τι μπορεί να γίνει από αυτό στον ρόλο; Είστε πάντα ευπρόσδεκτοι να καλέσετε παρενέργειες, αυτή είναι η ουσία ολόκληρου του Ansible - να δημιουργήσετε παρενέργειες. Υπάρχουν παράπλευρες αιτίες; Στοιχειώδης. Αλλά με "περάστε μια τιμή και επιστρέψτε την" - εκεί δεν λειτουργεί. Πρώτον, δεν μπορείς να δώσεις αξία σε έναν ρόλο. Μπορείτε να ορίσετε μια καθολική μεταβλητή με μέγεθος παιχνιδιού διάρκειας ζωής στην ενότητα vars για τον ρόλο. Μπορείτε να ορίσετε μια καθολική μεταβλητή με διάρκεια ζωής εντός του ρόλου. Ή ακόμα και με τη διάρκεια ζωής των βιβλίων (set_fact/register). Αλλά δεν μπορείτε να έχετε "τοπικές μεταβλητές". Δεν μπορείς να "πάρεις μια αξία" και "να την επιστρέψεις".

Το κύριο πράγμα προκύπτει από αυτό: δεν μπορείτε να γράψετε κάτι στο Ansible χωρίς να προκαλέσετε παρενέργειες. Η αλλαγή των καθολικών μεταβλητών είναι πάντα μια παρενέργεια για μια συνάρτηση. Στο Rust, για παράδειγμα, η αλλαγή μιας καθολικής μεταβλητής είναι unsafe. Και στο Ansible είναι η μόνη μέθοδος για να επηρεάσεις τις τιμές για έναν ρόλο. Σημειώστε τις λέξεις που χρησιμοποιούνται: όχι "πέρασε μια τιμή στον ρόλο", αλλά "αλλαγή των τιμών που χρησιμοποιεί ο ρόλος". Δεν υπάρχει απομόνωση μεταξύ των ρόλων. Δεν υπάρχει απομόνωση μεταξύ εργασιών και ρόλων.

Итого: ένας ρόλος δεν είναι λειτουργία.

Τι καλό έχει ο ρόλος; Πρώτον, ο ρόλος έχει προεπιλεγμένες τιμές (/default/main.yaml), δεύτερον, ο ρόλος έχει πρόσθετους καταλόγους για την αποθήκευση αρχείων.

Ποια είναι τα οφέλη των προεπιλεγμένων τιμών; Επειδή στην πυραμίδα του Maslow, τον μάλλον παραμορφωμένο πίνακα των μεταβλητών προτεραιοτήτων του Ansible, οι προεπιλογές ρόλων είναι οι πιο χαμηλής προτεραιότητας (μείον τις παραμέτρους της γραμμής εντολών Ansible). Αυτό σημαίνει ότι εάν πρέπει να παρέχετε προεπιλεγμένες τιμές και να μην ανησυχείτε μήπως παρακάμψουν τις τιμές από το απόθεμα ή τις μεταβλητές ομάδας, τότε οι προεπιλογές ρόλων είναι το μόνο κατάλληλο μέρος για εσάς. (Λέω ψέματα λίγο - υπάρχουν κι άλλα |d(your_default_here), αλλά αν μιλάμε για σταθερές θέσεις, τότε μόνο προεπιλογές ρόλων).

Τι άλλο είναι υπέροχο με τους ρόλους; Γιατί έχουν τους δικούς τους καταλόγους. Αυτοί είναι κατάλογοι για μεταβλητές, τόσο σταθερές (δηλαδή υπολογισμένες για το ρόλο) όσο και δυναμικές (υπάρχει είτε μοτίβο είτε αντί-μοτίβο - include_vars με {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.). Αυτοί είναι οι κατάλογοι για files/, templates/. Επίσης, σας επιτρέπει να έχετε τα δικά σας modules και plugins (library/). Όμως, σε σύγκριση με τις εργασίες σε ένα playbook (το οποίο μπορεί επίσης να έχει όλα αυτά), το μόνο πλεονέκτημα εδώ είναι ότι τα αρχεία δεν απορρίπτονται σε ένα σωρό, αλλά σε πολλούς ξεχωριστούς σωρούς.

Μια ακόμη λεπτομέρεια: μπορείτε να δοκιμάσετε να δημιουργήσετε ρόλους που θα είναι διαθέσιμοι για επαναχρησιμοποίηση (μέσω γαλαξίας). Με την εμφάνιση των συλλογών, η διανομή ρόλων μπορεί να θεωρηθεί σχεδόν ξεχασμένη.

Έτσι, οι ρόλοι έχουν δύο σημαντικά χαρακτηριστικά: έχουν προεπιλογές (ένα μοναδικό χαρακτηριστικό) και σας επιτρέπουν να δομήσετε τον κώδικά σας.

Επιστρέφοντας στην αρχική ερώτηση: πότε να κάνετε εργασίες και πότε να κάνετε ρόλους; Οι εργασίες σε ένα βιβλίο παιχνιδιού χρησιμοποιούνται συχνότερα είτε ως «κόλλα» πριν/μετά τους ρόλους ή ως ανεξάρτητο δομικό στοιχείο (τότε δεν πρέπει να υπάρχουν ρόλοι στον κώδικα). Ένα σωρό κανονικών εργασιών αναμεμειγμένο με ρόλους είναι ξεκάθαρη προχειρότητα. Θα πρέπει να τηρείτε ένα συγκεκριμένο στυλ - είτε μια εργασία είτε έναν ρόλο. Οι ρόλοι παρέχουν διαχωρισμό οντοτήτων και προεπιλογών, οι εργασίες σάς επιτρέπουν να διαβάζετε τον κώδικα πιο γρήγορα. Συνήθως, πιο «στάσιμος» (σημαντικός και πολύπλοκος) κώδικας τοποθετείται σε ρόλους και τα βοηθητικά σενάρια γράφονται σε στυλ εργασίας.

Είναι δυνατό να κάνετε το import_role ως εργασία, αλλά αν το γράψετε αυτό, τότε να είστε έτοιμοι να εξηγήσετε στη δική σας αίσθηση ομορφιάς γιατί θέλετε να το κάνετε αυτό.

Ένας οξυδερκής αναγνώστης μπορεί να πει ότι οι ρόλοι μπορούν να εισάγουν ρόλους, οι ρόλοι μπορεί να έχουν εξαρτήσεις μέσω του galaxy.yml, και υπάρχει επίσης ένα τρομερό και τρομερό include_role — Σας υπενθυμίζω ότι βελτιώνουμε τις δεξιότητες στη βασική Ansible και όχι στη γυμναστική.

Χειριστές και εργασίες

Ας συζητήσουμε ένα άλλο προφανές πράγμα: τους χειριστές. Το να ξέρεις πώς να τα χρησιμοποιείς σωστά είναι σχεδόν τέχνη. Ποια είναι η διαφορά μεταξύ ενός χειριστή και ενός σύρματος;

Εφόσον θυμόμαστε τα βασικά, εδώ είναι ένα παράδειγμα:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

Οι χειριστές του ρόλου βρίσκονται στο rolename/handlers/main.yaml. Οι χειριστές ψαχουλεύουν μεταξύ όλων των συμμετεχόντων στο παιχνίδι: το pre/post_tasks μπορεί να τραβήξει τους χειριστές ρόλων και ένας ρόλος μπορεί να τραβήξει τους χειριστές από το παιχνίδι. Ωστόσο, οι κλήσεις "πολλαπλών ρόλων" στους χειριστές προκαλούν πολύ περισσότερο wtf από την επανάληψη ενός ασήμαντου χειριστή. (Ένα άλλο στοιχείο των βέλτιστων πρακτικών είναι να προσπαθήσετε να μην επαναλάβετε τα ονόματα των χειριστών).

Η κύρια διαφορά είναι ότι η εργασία εκτελείται πάντα (ανεπαρκώς) (συν/πλην ετικέτες και when), και ο χειριστής - κατά αλλαγή κατάστασης (ειδοποιήστε τις πυρκαγιές μόνο εάν έχει αλλάξει). Τι σημαίνει αυτό? Για παράδειγμα, το γεγονός ότι όταν κάνετε επανεκκίνηση, εάν δεν άλλαξε, τότε δεν θα υπάρχει χειριστής. Γιατί μπορεί να χρειάζεται να εκτελέσουμε τον χειριστή όταν δεν υπήρξε αλλαγή στην εργασία δημιουργίας; Για παράδειγμα, επειδή κάτι έσπασε και άλλαξε, αλλά η εκτέλεση δεν έφτασε στον χειριστή. Για παράδειγμα, επειδή το δίκτυο ήταν προσωρινά εκτός λειτουργίας. Η διαμόρφωση έχει αλλάξει, η υπηρεσία δεν έχει επανεκκινηθεί. Την επόμενη φορά που θα το ξεκινήσετε, η διαμόρφωση δεν αλλάζει πλέον και η υπηρεσία παραμένει στην παλιά έκδοση της διαμόρφωσης.

Η κατάσταση με τη ρύθμιση παραμέτρων δεν μπορεί να λυθεί (πιο συγκεκριμένα, μπορείτε να εφεύρετε ένα ειδικό πρωτόκολλο επανεκκίνησης για τον εαυτό σας με σημαίες αρχείων, κ.λπ., αλλά αυτό δεν είναι πλέον «βασικό ανώμαλο» σε οποιαδήποτε μορφή). Αλλά υπάρχει μια άλλη κοινή ιστορία: εγκαταστήσαμε την εφαρμογή, την καταγράψαμε .service-αρχείο, και τώρα το θέλουμε daemon_reload и state=started. Και το φυσικό μέρος για αυτό φαίνεται να είναι ο χειριστής. Αλλά αν το κάνετε όχι χειριστή αλλά εργασία στο τέλος μιας λίστας εργασιών ή ρόλου, τότε θα εκτελείται άσκοπα κάθε φορά. Κι ας έσπασε το playbook στη μέση. Αυτό δεν λύνει καθόλου το πρόβλημα επανεκκίνησης (δεν μπορείτε να κάνετε μια εργασία με το χαρακτηριστικό επανεκκίνησης, επειδή η ανικανότητα έχει χαθεί), αλλά σίγουρα αξίζει να κάνετε κατάσταση=έναρξη, η συνολική σταθερότητα των βιβλίων αναπαραγωγής αυξάνεται, επειδή ο αριθμός των συνδέσεων και η δυναμική κατάσταση μειώνεται.

Μια άλλη θετική ιδιότητα του χειριστή είναι ότι δεν φράζει την έξοδο. Δεν υπήρξαν αλλαγές - καμία επιπλέον παράβλεψη ή εντάξει στην έξοδο - πιο ευανάγνωστη. Είναι επίσης μια αρνητική ιδιότητα - εάν βρείτε ένα τυπογραφικό λάθος σε μια γραμμικά εκτελούμενη εργασία κατά την πρώτη κιόλας εκτέλεση, τότε οι χειριστές θα εκτελεστούν μόνο όταν αλλάξουν, π.χ. υπό ορισμένες συνθήκες - πολύ σπάνια. Για παράδειγμα, για πρώτη φορά στη ζωή μου πέντε χρόνια μετά. Και, φυσικά, θα γίνει τυπογραφικό λάθος στο όνομα και όλα θα σπάσουν. Και αν δεν τα εκτελέσετε δεύτερη φορά, δεν υπάρχει καμία αλλαγή.

Ξεχωριστά, πρέπει να μιλήσουμε για τη διαθεσιμότητα των μεταβλητών. Για παράδειγμα, εάν ειδοποιήσετε μια εργασία με βρόχο, τι θα υπάρχει στις μεταβλητές; Μπορείτε να μαντέψετε αναλυτικά, αλλά δεν είναι πάντα ασήμαντο, ειδικά αν οι μεταβλητές προέρχονται από διαφορετικά μέρη.

... Άρα οι χειριστές είναι πολύ λιγότερο χρήσιμοι και πολύ πιο προβληματικοί από όσο φαίνονται. Εάν μπορείτε να γράψετε κάτι όμορφα (χωρίς διακοσμητικά στοιχεία) χωρίς χειριστές, είναι καλύτερα να το κάνετε χωρίς αυτούς. Αν δεν λειτουργήσει όμορφα, είναι καλύτερα μαζί τους.

Ο διαβρωτικός αναγνώστης σωστά επισημαίνει ότι δεν έχουμε συζητήσει listenότι ένας χειριστής μπορεί να καλέσει το notify για έναν άλλο χειριστή, ότι ένας χειριστής μπορεί να περιλαμβάνει import_tasks (που μπορεί να περιλαμβάνει include_role με with_items), ότι το σύστημα χειριστή στο Ansible είναι Turing-complete, ότι οι χειριστές από το include_role τέμνονται με περίεργο τρόπο με τους χειριστές από το παιχνίδι, κλπ. .δ. - όλα αυτά σαφώς δεν είναι τα «βασικά»).

Αν και υπάρχει ένα συγκεκριμένο WTF που είναι στην πραγματικότητα ένα χαρακτηριστικό που πρέπει να έχετε κατά νου. Εάν η εργασία σας εκτελείται με delegate_to και έχει ειδοποιήσει, τότε ο αντίστοιχος χειριστής εκτελείται χωρίς delegate_to, δηλ. στον οικοδεσπότη όπου έχει ανατεθεί το παιχνίδι. (Αν και ο χειριστής, φυσικά, μπορεί να έχει delegate_to Ιδιο).

Ξεχωριστά, θέλω να πω λίγα λόγια για τους επαναχρησιμοποιήσιμους ρόλους. Πριν εμφανιστούν οι συλλογές, υπήρχε μια ιδέα ότι θα μπορούσατε να κάνετε καθολικούς ρόλους που θα μπορούσαν να είναι ansible-galaxy install και πήγα. Λειτουργεί σε όλα τα λειτουργικά συστήματα όλων των παραλλαγών σε όλες τις καταστάσεις. Λοιπόν, η γνώμη μου: δεν λειτουργεί. Οποιοσδήποτε ρόλος με μάζα include_vars, υποστηρίζοντας 100500 θήκες, είναι καταδικασμένη στην άβυσσο των σφαλμάτων της γωνίας. Μπορούν να καλυφθούν με μαζικές δοκιμές, αλλά όπως με κάθε δοκιμή, είτε έχετε ένα καρτεσιανό γινόμενο των τιμών εισόδου και μια συνολική συνάρτηση, είτε έχετε «καλυμμένα μεμονωμένα σενάρια». Γνώμη μου είναι ότι είναι πολύ καλύτερο αν ο ρόλος είναι γραμμικός (κυκλωματική πολυπλοκότητα 1).

Τα λιγότερα αν (ρητά ή δηλωτικά - στη μορφή when ή μορφή include_vars ανά σύνολο μεταβλητών), τόσο καλύτερος είναι ο ρόλος. Μερικές φορές πρέπει να κάνετε κλαδιά, αλλά, επαναλαμβάνω, όσο λιγότερα είναι, τόσο το καλύτερο. Οπότε φαίνεται καλός ρόλος με το galaxy (δουλεύει!) με ένα σωρό when μπορεί να είναι λιγότερο προτιμότερος από τον «δικό του» ρόλο από πέντε εργασίες. Η στιγμή που ο ρόλος με το γαλαξία είναι καλύτερος είναι όταν ξεκινάς να γράφεις κάτι. Η στιγμή που χειροτερεύει είναι όταν κάτι σπάει και έχεις την υποψία ότι είναι λόγω του «ρόλου με τον γαλαξία». Το ανοίγετε και υπάρχουν πέντε εγκλείσματα, οκτώ φύλλα εργασιών και μια στοίβα when'Ov... Και πρέπει να το καταλάβουμε αυτό. Αντί για 5 εργασίες, μια γραμμική λίστα στην οποία δεν υπάρχει τίποτα να σπάσει.

Στα επόμενα μέρη

  • Λίγα λόγια για το απόθεμα, τις μεταβλητές ομάδας, το πρόσθετο host_group_vars, το hostvars. Πώς να δέσετε τον Γόρδιο κόμπο με μακαρόνια. Μεταβλητές πεδίου και προτεραιότητας, μοντέλο μνήμης Ansible. "Λοιπόν πού αποθηκεύουμε το όνομα χρήστη για τη βάση δεδομένων;"
  • jinja: {{ jinja }} — μαλακή πλαστελίνη nosql notype nosense. Είναι παντού, ακόμα και εκεί που δεν το περιμένεις. Λίγο για !!unsafe και νόστιμο γιαμλ.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο