Το προφίλ μας στο Google Plus
0

Προγραμματική διαχείριση μηχανών στο cloud

Οι σύγχρονες πρακτικές για τη διαχείριση υπολογιστικών πόρων και υπηρεσιών ενθαρρύνουν τη θεώρηση του εικονικού ή/και του φυσικού hardware ως κάτι που είναι πάντα διαθέσιμο, κάπου στο cloud ή έστω στο server room.

Για λόγους που αφορούν στην ελαχιστοποίηση του κόστους, του χρόνου προετοιμασίας αλλά και του ρίσκου, αντί για την απευθείας διαχείριση hardware, λειτουργικών συστημάτων και υπηρεσιών εφαρμόζουμε πρακτικές που βασίζονται αφενός στη λογική του Infrastructure as Code, αφετέρου στη φιλοσοφία των configuration management systems. Ουσιαστικά, αυτό σημαίνει ότι αντί να παιδευόμαστε και να σκοτιζόμαστε με το υλικό, το σχετικό λογισμικό και τις ιδιαιτερότητές τους, φροντίζουμε και γράφουμε κώδικα περιγράφοντας τι ακριβώς θέλουμε να πετύχουμε. Αντί να συνδεόμαστε σε κάποιο απομακρυσμένο μηχάνημα μέσω SSH και να τροποποιούμε το configuration, π.χ., ενός web server ή ενός load balancer, γράφουμε κώδικα που περιγράφει πώς ακριβώς ρυθμίζεται και συμπεριφέρεται ο web server ή ο load balancer. Συχνά μάλιστα οι περιγραφές αυτές είναι φορητές, υπό την έννοια ότι μπορούν ν’ αποθηκεύονται, π.χ., σ’ ένα Git repository, και υπό προϋποθέσεις να εφαρμόζονται από οποιονδήποτε ενδιαφερόμενο σε οποιονδήποτε server. Άλλο παράδειγμα: Αντί να φροντίζουμε για την παρουσία και τη ρύθμιση ενός πλήθους μηχανημάτων τα οποία θα συγκροτήσουν ένα cluster, γράφουμε κώδικα για το provisioning των κόμβων του cluster στο cloud ενός IaaS provider. Σκεφτείτε εξάλλου και την περίπτωση ενός developer, ο οποίος συμμετέχει σε πρότζεκτ ανάπτυξης μιας εφαρμογής που θα τρέχει στο cloud και θα είναι δημόσια προσβάσιμη. Κατά την ανάπτυξη, για τον έλεγχο της εφαρμογής είναι δυνατόν να χρησιμοποιείται hardware στο οποίο, με κάποιον τρόπο, έχουν πρόσβαση όλοι οι εμπλεκόμενοι στο πρότζεκτ. Σε μια τέτοια περίπτωση είναι απαραίτητο να εξομοιώνονται όσο το δυνατόν καλύτερα το περιβάλλον και οι συνθήκες που θα ισχύουν στο λεγόμενο production. Εναλλακτικά, η ανάπτυξη κι ο έλεγχος θα μπορούσαν να πραγματοποιούνται απευθείας στο cloud (π.χ., σε περιβάλλον OpenStack, στο cloud της Amazon ή σ’ εκείνο της DigitalOcean). Το provisioning των μηχανών θα επιτυγχάνεται προγραμματικά κι αυτοματοποιημένα. Οι σχετικοί πόροι θα είναι δυνατόν να δημιουργούνται από μηδενική βάση κατά το deployment και να καταστρέφονται μετά το πέρας των ελέγχων. Μιλάμε μ’ άλλα λόγια για εφήμερη υποδομή, ώστε αν μη τι άλλο το κόστος φιλοξενίας να διατηρείται σε εξαιρετικά χαμηλά επίπεδα. Επίσης, ακριβώς επειδή η διαχείριση της υποδομής γίνεται προγραμματικά, η διαμόρφωση του σχετικού περιβάλλοντος είναι εύκολη υπόθεση ενώ και τα όποια λάθη αντιμετωπίζονται με την κατάλληλη τροποποίηση του κώδικα, π.χ., του εκάστοτε configuration management system.

Στο παρόν άρθρο κάνουμε τα πρώτα μας βήματα στον κόσμο του Infrastructure as Code, καθώς και μια πολύ σύντομη βόλτα σ’ αυτόν του Configuration Management. Οι δύο αυτοί όροι δείχνουν να σημαίνουν το ίδιο πράγμα, στην πραγματικότητα όμως κάτι τέτοιο δεν ισχύει: το Infrastructure as Code αφορά στη διαχείριση εικονικών ή/και φυσικών servers, ενώ το Configuration Management αφορά στη διαμόρφωση λειτουργικών συστημάτων ή/και υπηρεσιών που φιλοξενούν οι servers. Ως όχημα για το σύντομο ταξίδι μας θα έχουμε το cloud της DigitalOcean. Κι επειδή υποψιαζόμαστε ότι κανείς, ποτέ, δεν παρομοίωσε ένα σύννεφο μ’ ένα όχημα, ας αφήσουμε αμέσως τις εισαγωγές πριν λυγίσουμε ανεπανόρθωτα τις ελευθερίες έκφρασης που παρέχει ο γραπτός λόγος.

Προαπαιτούμενα και δημιουργία API token
Προκειμένου να εφαρμόσετε κι εσείς όλα όσα περιγράφουμε και παρουσιάζουμε στο παρόν άρθρο, θα χρειαστεί να έχετε τα ακόλουθα.

  • Υπολογιστή με λειτουργικό σύστημα Linux, FreeBSD, OpenBSD ή Mac OS X. Είστε σε μηχάνημα με Windows; Και πάλι θα μπορέσετε να μας ακολουθήσετε, ωστόσο θα δουλέψετε λίγο περισσότερο για την προετοιμασία του όλου περιβάλλοντος. Εναλλακτικά, προτείνουμε να στραφείτε σε κάποιο VirtualBox ή VMware VM, με Linux.
  • Γνώση περί των αρχείων JSON αλλά και του εργαλείου ονόματι Packer της Hashicorp, το οποίο πρέπει να είναι ήδη εγκατεστημένο στον υπολογιστή σας. Αν δεν γνωρίζετε για το Packer ή για τα αρχεία JSON, κάντε τώρα ένα διάλειμμα και διαβάστε το σχετικό μας άρθρο.
  • Λογαριασμό στη DigitalOcean. Πώς είπατε; Δεν έχετε αλλά ετοιμαζόσαστε να δημιουργήσετε έναν; Ωραία, κάντε το, αλλά ακολουθώντας αυτό το referral URL. Κατ’ αυτόν τον τρόπο κερδίζετε 10 δολάρια σε credit, ενώ στηρίζετε και το hosting του deltaHacker.
  • Ένα token για το DigitalOcean API, κατάλληλο για ανάγνωση αλλά και για εγγραφή. Συνδεθείτε στο λογαριασμό σας στη DigitalOcean και βεβαιωθείτε ότι είστε στο κεντρικό dashboard. Κάντε κλικ στο API (βλ. κατακόρυφο πλαίσιο αριστερά) και στη νέα σελίδα που θα φορτώσει άλλο ένα κλικ στο Tokens/Keys. Στην ενότητα Personal access tokens πατήστε στο μεγάλο κουμπί Generate New Token (δεξιά). Θα εμφανιστεί ένα pop-up box και στη θυρίδα Token name θα χρειαστεί να πληκτρολογήσετε ένα όνομα για το υπό δημιουργία token. Πριν πατήσετε στο μπλε κουμπί Generate Token, βεβαιωθείτε ότι είναι τσεκαρισμένο το κουτάκι Write (optional). Το νέο token και το αντίστοιχο όνομα θα τα δείτε στην ενότητα Personal access tokens. Αντιγράψτε το token (με τ’ όνομά του) σε ένα ασφαλές μέρος, διότι α) μόνον εσείς πρέπει να το γνωρίζετε και β) όταν αργότερα έλθετε ξανά σ’ αυτή τη σελίδα θα διαπιστώσετε ότι το token δεν παρατίθεται (εξακολουθεί να υφίσταται, όμως για λόγους ασφαλείας δεν φαίνεται).

Για το νέο DigitalOcean API token (επιτρέπεται να έχουμε περισσότερα από ένα) πληκτρολογούμε ένα περιγραφικό ή απλά φιλικό όνομα (1) και φροντίζουμε ώστε εκτός από δικαιώματα ανάγνωσης να παρέχει και δικαιώματα εγγραφής (2). Η δημιουργία του token γίνεται με κλικ στο κουμπί Generate Token (3).

Για το νέο DigitalOcean API token (επιτρέπεται να έχουμε περισσότερα από ένα) πληκτρολογούμε ένα περιγραφικό ή απλά φιλικό όνομα (1) και φροντίζουμε ώστε εκτός από δικαιώματα ανάγνωσης να παρέχει και δικαιώματα εγγραφής (2). Η δημιουργία του token γίνεται με κλικ στο κουμπί Generate Token (3).

Ιδού το νέο μας token (είναι σκοπίμως σκιασμένο), για πρόσβαση στο DigitalOcean API με δικαιώματα ανάγνωσης αλλά και εγγραφής. Οφείλουμε να το αντιγράψουμε άμεσα σε κάποιο ασφαλές μέρος, όπου μόνον εμείς έχουμε πρόσβαση. Σημειωτέον πως όταν αργότερα έλθουμε ξανά σ' αυτή τη σελίδα, το token δεν θα φαίνεται.

Ιδού το νέο μας token (είναι σκοπίμως σκιασμένο), για πρόσβαση στο DigitalOcean API με δικαιώματα ανάγνωσης αλλά και εγγραφής. Οφείλουμε να το αντιγράψουμε άμεσα σε κάποιο ασφαλές μέρος, όπου μόνον εμείς έχουμε πρόσβαση. Σημειωτέον πως όταν αργότερα έλθουμε ξανά σ’ αυτή τη σελίδα, το token δεν θα φαίνεται.

Όλα όσα δείχνουμε στη συνέχεια έγιναν από περιβάλλον Mac OS X. Παρόμοια θα εργαστείτε κι από περιβάλλον Linux/*BSD. Επαναλαμβάνουμε ότι αν είστε σε υπολογιστή με Windows, τότε όλα θα είναι πολύ ευκολότερα αν εργαστείτε μέσα από VM με Linux. Αν για κάποιο λόγο αυτό δεν είναι εφικτό, τότε η έρευνα για τις εγκαταστάσεις και τις ρυθμίσεις του περιβάλλοντος εργασίας θα γίνει από εσάς, χωρίς τη βοήθειά μας, αφού δεν έχουμε πρόσβαση σε μηχάνημα με Windows. (Σοβαρά τώρα, υπομονή και καλή σας τύχη.)

Παραδείγματα χρήσης του API
Στον δικτυακό τόπο της DigitalOcean υπάρχει πλήρης τεκμηρίωση για το API που παρέχει η εταιρεία. Χάρη σ’ αυτό είμαστε σε θέση να διαχειριζόμαστε droplets (VMs), storage volumes και γενικά πόρους στο cloud της DigitalOcean. Γενικά, ό,τι κάνουμε από το web dashboard μπορούμε να το κάνουμε και προγραμματικά, π.χ., για τις ανάγκες ενός συστήματος αυτοματοποίησης ή μιας εφαρμογής που αναπτύσσουμε. Η επικοινωνία με το API γίνεται μέσω απλών HTTPS requests, π.χ., με τη βοήθεια του εργαλείου curl. Δεν έχει φυσικά νόημα να αναπαράγουμε εδώ το επίσημο κείμενο τεκμηρίωσης, αξίζει όμως να δούμε μερικά απλά παραδείγματα ώστε να μπαίνουμε σιγά σιγά στο κλίμα.

Κατ’ αρχάς οφείλουμε ν’ αναθέσουμε το token που δημιουργήσαμε πριν λίγο σε μια μεταβλητή περιβάλλοντος, έστω την TOKEN, ώστε να μη χρειάζεται να το πληκτρολογούμε κάθε φορά που απευθύνουμε ένα request προς το DigitalOcean API. Πολύ απλά, στο τερματικό μας γράφουμε κάτι σαν

export TOKEN=paste_the_token_here

όπου στη θέση του paste_the_token_here εννοείται πως βάζουμε το ίδιο το token. Τώρα, προκειμένου να δούμε όλα τα droplet μας στο cloud της DigitalOcean γράφουμε:

curl -X GET "https://api.digitalocean.com/v2/droplets" \
-H "Authorization: Bearer $TOKEN"

Για απλή λήψη πληροφοριών, η μέθοδος στην οποία καταφεύγουμε είναι η GET. Τα αποτελέσματα επιστρέφονται υπό τη μορφή ενός JSON object, το οποίο στερείται λευκών χαρακτήρων ή χαρακτήρων αλλαγής γραμμής. Για ένα οποιοδήποτε πρόγραμμα αυτό δεν αποτελεί πρόβλημα. Εμείς, όμως, κοιτάζουμε τώρα το τερματικό μας κι όσο να ‘ναι δυσκολευόμαστε να βγάλουμε άκρη.

Το πρώτο μας request προς το DigitalOcean API γίνεται μέσω της μεθόδου GET κι αποσκοπεί στην εξαγωγή πληροφοριών περί των droplet που έχουμε στο cloud της εταιρείας. Τις σχετικές πληροφορίες τις λαμβάνουμε υπό τη μορφή ενός αντικειμένου JSON. Ένα JSON object είναι μια χαρά για τη μηχανή. Όμως από το συγκεκριμένο output απουσιάζουν λευκοί χαρακτήρες και χαρακτήρες αλλαγής γραμμής, κι αυτό δεν είναι ό,τι καλύτερο για την αποφυγή πονοκεφάλων.

Το πρώτο μας request προς το DigitalOcean API γίνεται μέσω της μεθόδου GET κι αποσκοπεί στην εξαγωγή πληροφοριών περί των droplet που έχουμε στο cloud της εταιρείας. Τις σχετικές πληροφορίες τις λαμβάνουμε υπό τη μορφή ενός αντικειμένου JSON. Ένα JSON object είναι μια χαρά για τη μηχανή. Όμως από το συγκεκριμένο output απουσιάζουν λευκοί χαρακτήρες και χαρακτήρες αλλαγής γραμμής, κι αυτό δεν είναι ό,τι καλύτερο για την αποφυγή πονοκεφάλων.

Το αποτέλεσμα θα ήταν πολύ πιο ευανάγνωστο αν στο JSON object υπήρχαν λευκοί χαρακτήρες, καθώς και χαρακτήρες αλλαγής γραμμής. Μια ιδέα είναι να περάσουμε το output του request από τον interpreter της Python, έχοντας φορτώσει το module ονόματι json.tool. Πληκτρολογούμε…

curl -X GET "https://api.digitalocean.com/v2/droplets" \
-H "Authorization: Bearer $TOKEN" | python -m json.tool

…και τώρα το αποτέλεσμα είναι πολύ πιο ευανάγνωστο.

Με λίγη επεξεργασία από το κατάλληλο module της Python, το JSON object που επιστρέφει το request μας προς το DigitalOcean API μορφοποιείται αυτόματα και γίνεται human readable.

Με λίγη επεξεργασία από το κατάλληλο module της Python, το JSON object που επιστρέφει το request μας προς το DigitalOcean API μορφοποιείται αυτόματα και γίνεται human readable.

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

curl -X GET "https://api.digitalocean.com/v2/droplets" \
-H "Authorization: Bearer $TOKEN" > req_result.json

Παρατηρήστε ότι αποφασίσαμε να προσπεράσουμε την επεξεργασία από το προαναφερθέν module της Python. Αντίθετα, αποθηκεύσαμε απευθείας το αποτέλεσμα του request στο αρχείο req_result.json. Το αρχείο αυτό μπορούμε ν’ ανοίξουμε με ένα εργαλείο που γνωρίζει περί αρχείων JSON και πώς να τα μορφοποιεί. O web browser είναι ένα από αυτά τα εργαλεία, παρεμπιπτόντως.

Ανεξαρτήτως αν ένα αρχείο JSON περιλαμβάνει λευκούς χαρακτήρες ή χαρακτήρες αλλαγής γραμμής, ο Firefox ξέρει πώς να το αναπτύσσει και να το παρουσιάζει σε μορφή human readable. Παρατηρήστε ότι επιτρέπει ακόμη και την ανάπτυξη ή το μάζεμα arrays/objects.

Ανεξαρτήτως αν ένα αρχείο JSON περιλαμβάνει λευκούς χαρακτήρες ή χαρακτήρες αλλαγής γραμμής, ο Firefox ξέρει πώς να το αναπτύσσει και να το παρουσιάζει σε μορφή human readable. Παρατηρήστε ότι επιτρέπει ακόμη και την ανάπτυξη ή το μάζεμα arrays/objects.

Ελάτε τώρα να δούμε όλα τα distribution images που διαθέτει η DigitalOcean, με βάση τα οποία δημιουργούμε VMs με διαφορετικά χαρακτηριστικά και guest OSes. Ξεκινάμε λαμβάνοντας κι αποθηκεύοντας τις σχετικές πληροφορίες σε ένα αρχείο JSON (που για άλλη μια φορά ονομάζουμε req_result.json):

curl -X GET -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.digitalocean.com/v2/images?type=distribution" > \
req_result.json

Το περιεχόμενό του req_result.json είναι σε συμπτυγμένη μορφή, οπότε ας το εξετάσουμε με την άνεσή μας περνώντας το πρώτα από το Python module ονόματι json.tool και μετά από το less:

cat req_result.json | python -m json.tool | less

Βλέπουμε ότι κάθε distribution image περιγράφεται λεπτομερώς από ένα array. Ενδιαφέροντα κλειδιά μέσα στα arrays είναι τα distribution (η διανομή του αντίστοιχου image) και slug (ένα μοναδικό αλφαριθμητικό που χαρακτηρίζει το λειτουργικό του image). Το κλειδί slug είναι σημαντικό ειδικά όταν αναφερόμαστε –πάντα προγραμματικά– σε ένα VM. Ας φτιάξουμε, για παράδειγμα, ένα νέο droplet με λειτουργικό σύστημα το FreeBSD 11.1. Το slug του image στο οποίο θα βασίζεται το νέο droplet είναι το freebsd-11-1-x64. Για τη δημιουργία της νέας μας εικονικής μηχανής, στο τερματικό μας πληκτρολογούμε κάτι σαν το ακόλουθο:

curl -X POST "https://api.digitalocean.com/v2/droplets" \
-d '{"name":"deltabsd","region":"fra1","size":"s-2vcpu-2gb","image":"freebsd-11-1-x64","ssh_keys":["5e:f2:20:48:8e:b6:4c:b1:bf:b1:6c:2b:3b:23:f7:f7"],"tags":["deltaHacker","FreeBSD"]}' \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"

Ακολουθούν ορισμένες απαραίτητες διευκρινίσεις.

  • Τα δεδομένα της μεθόδου POST, τα οποία χάρη στην παράμετρο -d του curl αποστέλλονται στο /v2/droplets endpoint του API, περικλείονται σε απλά εισαγωγικά κι οφείλουμε να τα γράψουμε σε μία γραμμή μόνο.
  • Ουσιαστικά, ανάμεσα στα απλά εισαγωγικά της παραμέτρου -d ενθέτουμε ένα JSON object που περιγράφει το υπό δημιουργία droplet. Ανάμεσα στα ζεύγη της μορφής κλειδί:τιμή δεν πρέπει να εισάγουμε κενά, ούτε γύρω από τα κόμματα.
  • Η τιμή του κλειδιού size εκλέγεται από το σύνολο των slug που αντιστοιχούν στα προκαθορισμένα μεγέθη droplets της DigitalOcean. Προκειμένου να δούμε όλα τα σχετικά slug, σε ένα τερματικό γράφουμε: curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" "https://api.digitalocean.com/v2/sizes" | python -m json.tool | less. Εξετάζοντας το αντικείμενο που επιστρέφεται, βλέπουμε ότι το slug s-2vcpu-2gb σημαίνει εικονική μηχανή με δίσκο μεγέθους 60GiB, 2GiB μνήμης RAM, καθώς και δύο πυρήνες. Παρατηρήστε επίσης και κάποια άλλα ενδιαφέροντα χαρακτηριστικά, όπως ο δωρεάν όγκος δεδομένων από το VM (outbound traffic), το μηνιαίο αλλά και το ωριαίο κόστος, καθώς και η διαθεσιμότητα στα διάφορα datacenters της εταιρείας στον πλανήτη.
  • Στο κλειδί ssh_keys αντιστοιχίζεται ένα array με ένα ή περισσότερα fingerprint δημοσίων κλειδιών SSH, τα οποία έχουμε ήδη ανεβασμένα στο λογαριασμό μας στη DigitalOcean. Στο παράδειγμά μας το array έχει ένα μόνο fingerprint, το οποίο αντιστοιχεί στο δημόσιο κλειδί SSH από το λογαριασμό του χρήστη μας στο laptop των δοκιμών. Το νέο FreeBSD VM θα έχει στο λογαριασμό του χρήστη root, συγκεκριμένα στο αρχείο ~/.ssh/authorized_keys, το αντίστοιχο δημόσιο κλειδί. Έτσι, από το laptop θα είμαστε σε θέση να συνδεόμαστε μέσω SSH απευθείας στο λογαριασμό του root στο FreeBSD droplet, χωρίς να πληκτρολογούμε κάποιο password.

Δείτε παρακαλούμε τα screenshots που ακολουθούν, διαβάστε βεβαίως και τις αντίστοιχες περιγραφές.

Δημιουργία νέου droplet στο datacenter της DigitalOcean, στη Φρανκφούρτη (πράσινη περιοχή). Το νέο VM έχει 2GiB RAM, δύο πυρήνες, δίσκο χωρητικότητας 60GiB και λειτουργικό σύστημα το FreeBSD 11.1 64bit. Χρησιμοποιούμε τη μέθοδο POST και τα δεδομένα που στέλνουμε στο κατάλληλο endpoint του API αποτελούν ένα JSON object, το οποίο γράφουμε σε μία γραμμή και χωρίς χρήση λευκών χαρακτήρων. Παρατηρήστε ότι μετά από επιτυχημένη χρήση του API για δημιουργία νέου droplet, στο τερματικό παίρνουμε ένα JSON object με όλα τα μεταδεδομένα που χαρακτηρίζουν τη νέα μηχανή (γκρι περιοχή).

Δημιουργία νέου droplet στο datacenter της DigitalOcean, στη Φρανκφούρτη (πράσινη περιοχή). Το νέο VM έχει 2GiB RAM, δύο εικονικούς πυρήνες, δίσκο χωρητικότητας 60GiB και λειτουργικό σύστημα το FreeBSD 11.1 64bit. Χρησιμοποιούμε τη μέθοδο POST και τα δεδομένα που στέλνουμε στο κατάλληλο endpoint του API αποτελούν ένα JSON object, το οποίο γράφουμε σε μία γραμμή και χωρίς χρήση λευκών χαρακτήρων. Παρατηρήστε ότι μετά από επιτυχημένη χρήση του API για δημιουργία νέου droplet, στο τερματικό παίρνουμε ένα JSON object με όλα τα μεταδεδομένα που χαρακτηρίζουν τη νέα μηχανή (γκρι περιοχή).

Ξεκινώντας τους πειραματισμούς μας με το DigitalOcean API, συχνά θα θέλουμε να παρακολουθούμε την εξέλιξη διαφόρων εργασιών μέσα από το web dashboard του λογαριασμού μας. Στο παράδειγμα μόλις ζητήσαμε τη δημιουργία νέου droplet με FreeBSD και τώρα το βλέπουμε να δημιουργείται.

Ξεκινώντας τους πειραματισμούς μας με το DigitalOcean API, συχνά θα θέλουμε να παρακολουθούμε την εξέλιξη διαφόρων εργασιών μέσα από το web dashboard του λογαριασμού μας. Στο παράδειγμα μόλις ζητήσαμε τη δημιουργία νέου droplet με FreeBSD και τώρα το βλέπουμε να δημιουργείται.

Στο droplet που μόλις ζητήσαμε να δημιουργηθεί, προγραμματικά και μέσω του DigitalOcean API, φροντίσαμε να υποδείξουμε το fingerprint του SSH public key που έχει ο χρήστης μας στο τοπικό μηχάνημα. Το ίδιο το δημόσιο κλειδί ήταν ήδη ανεβασμένο στο λογαριασμό μας στη DigitalOcean κι αυτομάτως τοποθετήθηκε στο αρχείο ~/.ssh/authorized_keys, στο λογαριασμό του χρήστη root στο νέο VM.

Στο droplet που μόλις ζητήσαμε να δημιουργηθεί, προγραμματικά και μέσω του DigitalOcean API, φροντίσαμε να υποδείξουμε το fingerprint του SSH public key που έχει ο χρήστης μας στο τοπικό μηχάνημα. Το ίδιο το δημόσιο κλειδί ήταν ήδη ανεβασμένο στο λογαριασμό μας στη DigitalOcean κι αυτομάτως τοποθετήθηκε στο αρχείο ~/.ssh/authorized_keys, στο λογαριασμό του χρήστη root στο νέο VM.

Τα fingerprints δύο δημοσίων κλειδιών SSH που έχουμε αποθηκευμένα στο λογαριασμό μας, στη DigitalOcean. Δημιουργώντας ένα νέο VM, είτε από το web dashboard είτε προγραμματικά, έχουμε δυνατότητα για τοποθέτηση ενός ή περισσοτέρων δημοσίων κλειδιών στο αρχείο ~/.ssh/authorized_keys, στο λογαριασμό του root. Έτσι, από τα τοπικά μηχανήματα στα οποία βρίσκονται τα αντίστοιχα ιδιωτικά κλειδιά, θα είμαστε σε θέση να συνδεόμαστε αυτόματα στο VM χωρίς πληκτρολόγηση password.

Τα fingerprints δύο δημοσίων κλειδιών SSH που έχουμε αποθηκευμένα στο λογαριασμό μας, στη DigitalOcean. Δημιουργώντας ένα νέο VM, είτε από το web dashboard είτε προγραμματικά, έχουμε δυνατότητα για τοποθέτηση ενός ή περισσοτέρων δημοσίων κλειδιών στο αρχείο ~/.ssh/authorized_keys, στο λογαριασμό του root. Έτσι, από τα τοπικά μηχανήματα στα οποία βρίσκονται τα αντίστοιχα ιδιωτικά κλειδιά, θα είμαστε σε θέση να συνδεόμαστε αυτόματα στο VM χωρίς πληκτρολόγηση password.

Πώς απαλλασσόμαστε από ένα droplet που δεν χρειαζόμαστε άλλο; Ο προφανής τρόπος είναι να το καταστρέψουμε (destroy) μέσα από το web dashboard του λογαριασμού μας, όμως εδώ ενδιαφερόμαστε για το πώς εργαζόμαστε προγραμματικά:

curl -X DELETE -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.digitalocean.com/v2/droplets/99336865"

Παρατηρήστε ότι το endpoint περιλαμβάνει το ID του υπό καταστροφή VM. Το πώς βρίσκουμε το ID ενός droplet (VM) νομίζουμε ότι δεν χρειάζεται να το αναφέρουμε, ενώ είναι και περιττό να υπογραμμίσουμε πόσο τεράστια προσοχή οφείλουμε να δίνουμε στα DELETE requests. Πειραματιστείτε με το API της DigitalOcean, έχοντας ως οδηγό και την επίσημη τεκμηρίωση.

API wrappers
Το curl είναι ό,τι πρέπει για την εξοικείωσή μας με το API της DigitalOcean. Όταν όμως αρχίζουμε να ασχολούμαστε λίγο περισσότερο σοβαρά με την προγραμματική διαχείριση πόρων στο cloud, πολύ γρήγορα συνειδητοποιούμε ότι δεν βολεύει να υποχρεώνουμε τα scripts ή τις εφαρμογές μας να καταφεύγουν σε “εξωτερικά” εργαλεία σαν το curl. Ευτυχώς, συζητώντας για τα θετικά του οικοσυστήματος της DigitalOcean μπορούμε ν’ αναφέρουμε τόσο την ευρύτητά του, όσο και την πληθώρα των ευκολιών που παρέχονται σε χρήστες και developers. Στο προκείμενο, αυτό σημαίνει ότι για το API της εταιρείας παρέχονται wrappers για γνωστές γλώσσες προγραμματισμού (π.χ., Python, Ruby, Go), καθώς και για κάπως λιγότερο γνωστές (π.χ., Scala, Haskell). Δείτε και διαβάστε περισσότερα για τους διαθέσιμους API wrappers στη σχετική σελίδα της DigitalOcean.

Διαχείριση μέσω command line client
Επιπλέον της απευθείας πρόσβασης στο DigitalOcean API, π.χ., μέσω του curl, αλλά και των wrappers για διάφορες γλώσσες προγραμματισμού, μία εναλλακτική που έχουμε είναι να καταφύγουμε σε κάποιο εργαλείο για τη γραμμή εντολών. Το doctl είναι το επίσημο command line tool της DigitalOcean για τη διαχείριση πόρων στο cloud της εταιρείας. Στη σελίδα του doctl στο GitHub παρέχονται αναλυτικές οδηγίες για την εγκατάστασή του. Γενικά, η όλη διαδικασία είναι αρκετά απλή. Αν, π.χ., τρέχουμε Mac OS X, τότε σε ένα τερματικό αρκεί να δώσουμε brew install doctl. Αν πάλι τρέχουμε Linux και για τη διανομή διατίθεται το Snap, τότε γράφουμε sudo snap install doctl.

Μετά την εγκατάσταση του doctl και πριν αρχίσουμε να το χρησιμοποιούμε, οφείλουμε να προχωρήσουμε –για μία φορά μόνο ανά τοπικό λογαριασμό χρήστη– σε μία σύντομη διαδικασία ταυτοποίησης (authentication) με τη DigitalOcean. Προς τούτο, χρειάζεται να έχουμε ένα API token με δικαιώματα τόσο ανάγνωσης, όσο και εγγραφής. Σε περίπτωση που δεν έχετε API token δημιουργήστε ένα τώρα (βλ. αρχική ενότητα “Προαπαιτούμενα και δημιουργία API token”). Με το token μας, λοιπόν, πραγματοποιούμε authentication από το τερματικό γράφοντας doctl auth init. Θα μας ζητηθεί να πληκτρολογήσουμε το token. Αν το έχουμε αντιγράψει στο clipboard, μας επιτρέπεται να το επικολλήσουμε. Πατάμε [Enter] και, σχεδόν ακαριαία, στο τερματικό παίρνουμε το μήνυμα “Validating token… OK”. Σε διαφορετική περίπτωση είτε δεν έχουμε δώσει το σωστό token, είτε η σύνδεση με τη DigitalOcean δεν είναι εφικτή, είτε βιώνουμε τα αποτελέσματα του πολύ γνωστού Κάτι Δεν Πάει Καλά (TM) φαινομένου. Πληκτρολογώντας doctl χωρίς κάτι άλλο και πατώντας [Enter], παίρνουμε μια πρώτη βοήθεια για το πώς χρησιμοποιούμε το εργαλείο.

Οι τέσσερις εντολές που δέχεται το doctl. Κάθε μία από αυτές καταλαβαίνει μία ή περισσότερες υποεντεολές.

Οι τέσσερις εντολές που δέχεται το doctl. Κάθε μία από αυτές καταλαβαίνει μία ή περισσότερες υποεντολές.

Βλέπουμε ότι σε πρώτο επίπεδο το doctl δέχεται τέσσερις εντολές: account, auth, compute και version. Κάθε μία από αυτές δέχεται μία ή περισσότερες υποεντολές. Προκειμένου να πάρουμε βοήθεια για μία εντολή (ή υποεντολή), γράφουμε κάτι σαν doctl commanddoctl command subcommand) και πατάμε [Enter]. Προτείνουμε να εξερευνήσετε λίγο τις διαθέσιμες εντολές — και κυρίως τις υποεντολές που καταλαβαίνουν. Φυσικά, ο καλύτερος τρόπος για να μάθετε το doctl είναι να ξεκινήσετε να το χρησιμοποιείτε. Ας δούμε, λοιπόν, μερικά παραδείγματα χρήσης.

Ποια είναι τα droplets που έχουμε ήδη φτιάξει στο λογαριασμό μας; Τα βλέπουμε πληκτρολογώντας doctl compute droplet list. Ουσιαστικά, στο doctl δίνουμε την εντολή compute ακολουθούμενη από την υποεντολή droplet και μετά από άλλη μία υποεντολή, τη list. Δείτε στο screenshot το αποτέλεσμα από το δικό μας account στη DigitalOcean.

Η λίστα με τα droplets μας στη DigitalOcean, όπως μας επιστρέφει το doctl. Αν και δεν έχουμε πολλά droplets, το αποτέλεσμα που παίρνουμε δείχνει κάπως μπερδεμένο. Ευτυχώς, είναι εύκολο να το κάνουμε περισσότερο ευανάγνωστο.

Η λίστα με τα droplets μας στη DigitalOcean, όπως μας επιστρέφει το doctl. Αν και δεν έχουμε πολλά droplets, το αποτέλεσμα που παίρνουμε δείχνει κάπως μπερδεμένο. Ευτυχώς, είναι εύκολο να το κάνουμε περισσότερο ευανάγνωστο.

Η έξοδος της παραπάνω εντολής γίνεται πολύ περισσότερο ευανάγνωστη αν παραλείψουμε μία ή περισσότερες στήλες. Στο παράδειγμά μας τα δύο droplets δεν έχουν ούτε ιδιωτικές διευθύνσεις IPv4/IPv6, ούτε volumes συνδεδεμένα. Οι αντίστοιχες στήλες, λοιπόν, δεν χρειάζονται. Αλλά και μεταξύ των άλλων στηλών, πολύ πιθανό να υπάρχουν κάποιες που δεν ενδιαφέρουν. Ας δώσουμε λοιπόν ξανά την εντολή, αυτή τη φορά υποδεικνύοντας τις στήλες που μας ενδιαφέρουν: doctl compute droplet list --format "ID,Name,PublicIPv4,Memory,VCPUs,Disk,Region". Κατά τα αναμενόμενα, το νέο αποτέλεσμα είναι συμμαζεμένο κι ευανάγνωστο.

Με τη χρήση της παραμέτρου --format υποδεικνύουμε τις στήλες που πραγματικά μας ενδιαφέρουν, έτσι η λίστα με τα droplets γίνεται πολύ περισσότερο ευανάγνωστη.

Με τη χρήση της παραμέτρου --format υποδεικνύουμε τις στήλες που πραγματικά μας ενδιαφέρουν, έτσι η λίστα με τα droplets γίνεται πολύ περισσότερο ευανάγνωστη.

Πάμε τώρα να φτιάξουμε ένα νέο droplet, αυτή τη φορά με το Debian 9. Χρειάζεται κατ’ αρχάς να δούμε τη λίστα με τα distribution images που προσφέρει η DigitalOcean, οπότε γράφουμε: doctl compute image list-distribution.

Η λίστα με τα distribution images που παρέχει η DigitalOcean, όπως μας την επιστρέφει το εργαλείο doctl.

Η λίστα με τα distribution images που παρέχει η DigitalOcean, όπως μας την επιστρέφει το εργαλείο doctl.

Όχι ότι δεν είναι εύκολο να βγάλουμε άκρη από το συγκεκριμένο output, αλλά θα μπορούσαμε να παραλείψουμε κάποιες στήλες που για το προκείμενο δεν μας ενδιαφέρουν. Παράδειγμα: doctl compute image list-distribution --format "Name,Distribution,Slug"

Ιδού η προηγούμενη λίστα, αυτή τη φορά χωρίς κάποιες στήλες που δεν μας ενδιαφέρουν. Συγκεκριμένα, αυτή που μας ενδιαφέρει περισσότερο για τη δημιουργία νέου droplet είναι η Slug.

Ιδού η προηγούμενη λίστα, αυτή τη φορά χωρίς κάποιες στήλες που δεν μας ενδιαφέρουν. Συγκεκριμένα, αυτή που μας ενδιαφέρει περισσότερο για τη δημιουργία νέου droplet είναι η Slug.

Εστιάζοντας την προσοχή μας στη στήλη Slug, αυτό για το droplet που σκοπεύουμε να φτιάξουμε είναι το debian-9-x64. Ας δούμε λίγο και τα fingerprint των δημοσίων κλειδιών που έχουμε ήδη ανεβάσει στο λογαριασμό μας, στη DigitalOcean. Απλά πληκτρολογούμε: doctl compute ssh-key list.

Τα fingerprint των δύο δημοσίων κλειδιών που έχουμε ανεβασμένα στο λογαριασμό μας, στη DigitalOcean. Το κλειδί που θέλουμε να υπάρχει στο root account, στο νέο droplet, είναι εκείνο με όνομα mbpr15 (το laptop εργασίας). Σημειώνουμε, λοιπόν, το αντίστοιχο fingerprint.

Τα fingerprint των δύο δημοσίων κλειδιών που έχουμε ανεβασμένα στο λογαριασμό μας, στη DigitalOcean. Το κλειδί που θέλουμε να υπάρχει στο root account, στο νέο droplet, είναι εκείνο με όνομα mbpr15 (το laptop εργασίας). Σημειώνουμε, λοιπόν, το αντίστοιχο fingerprint.

Είμαστε έτοιμοι να δημιουργήσουμε το νέο μας droplet στο cloud της DigitalOcean. Πληκτρολογούμε:

doctl compute droplet create deltadbn \
--size 1gb --image debian-9-x64 --region fra1 \
--ssh-keys 5e:f2:20:48:8e:b6:4c:b1:bf:b1:6c:2b:3b:23:f7:f7

Η εντολή που μόλις δώσαμε είναι νομίζουμε προφανές το τι κάνει. Ίσως αναρωτιέστε για τα slug περί size και region. Δεν είπαμε πώς τα βρίσκουμε, αλλά κι αυτό γίνεται πανεύκολα: απλά γράφουμε doctl compute size list και doctl compute region list αντίστοιχα.

Δημιουργία νέου droplet στο cloud της DigitalOcean, με χρήση του επίσημου command line client της εταιρείας.

Δημιουργία νέου droplet στο cloud της DigitalOcean, με χρήση του επίσημου command line client της εταιρείας.

Γενικά, για την απομακρυσμένη σύνδεση στο νέο droplet χρειάζεται να γνωρίζουμε είτε το δημόσιο IP του, είτε το domain name του. (Η DigitalOcean παρέχει και υπηρεσία DNS, την οποία μάλιστα μπορούμε να διαχειριζόμαστε και με το doctl.) Με χρήση του doctl, πάντως, αρκεί να θυμόμαστε το όνομα του droplet και συνδεόμαστε στο λογαριασμό του root κάπως έτσι: doctl compute ssh deltadbn.

Σύνδεση στο λογαριασμό root του νέου Debian droplet, χωρίς να γνωρίζουμε το δημόσιο IP ούτε το domain name του. Το μόνο που χρειάζεται να θυμόμαστε είναι το όνομά του και, χάρη στο doctl, συνδεόμαστε άμεσα μέσω SSH.

Σύνδεση στο λογαριασμό root του νέου Debian droplet, χωρίς να γνωρίζουμε το δημόσιο IP ούτε το domain name του. Το μόνο που χρειάζεται να θυμόμαστε είναι το όνομά του και, χάρη στο doctl, συνδεόμαστε άμεσα μέσω SSH.

Τα VMs που δημιουργούμε προγραμματικά κατά πάσα πιθανότητα είναι εφήμερα, υπό την έννοια ότι τα χρησιμοποιούμε στο πλαίσιο μιας συγκεκριμένης εργασίας και μετά, όταν δεν τα χρειαζόμαστε άλλο, τα καταστρέφουμε. Για τη διαγραφή του droplet που φτιάξαμε πριν λίγο, αρκεί να γνωρίζουμε το ID του και να γράψουμε κάτι τέτοιο: doctl compute droplet delete 108808943.

Διαγραφή droplet με τη βοήθεια του doctl. Επειδή πρόκειται για ενέργεια μη αναστρέψιμη, το πρόγραμμα μάς ρωτά αν πράγματι θέλουμε να προχωρήσουμε στη διαγραφή. Στις περιπτώσεις που είμαστε 110% βέβαιοι γι' αυτό που πρόκειται ν' ακολουθήσει, αρκεί να προσθέτουμε την παράμετρο --force και το doctl δεν θα ζητά επιβεβαίωση.

Διαγραφή droplet με τη βοήθεια του doctl. Επειδή πρόκειται για ενέργεια μη αναστρέψιμη, το πρόγραμμα μάς ρωτά αν πράγματι θέλουμε να προχωρήσουμε στη διαγραφή. Στις περιπτώσεις που είμαστε 110% βέβαιοι γι’ αυτό που πρόκειται ν’ ακολουθήσει, αρκεί να προσθέτουμε την παράμετρο --force και το doctl δεν θα ζητά επιβεβαίωση.

Packer, DigitalOcean snapshots και Ansible
Στο αναλυτικό μας άρθρο περί του Packer είδαμε ότι για το εν λόγω εργαλείο διατίθεται ένα πλήθος builders. Στο εκτενές παράδειγμα που παραθέσαμε ασχοληθήκαμε λεπτομερώς με τους builders για VMware, VirtualBox και QEMU machine images. Αναφέραμε επίσης ότι το Packer είναι ικανό ν’ αναπτύσσει images και στο cloud — χάρη στους κατάλληλους builders φυσικά. Ένας εξ αυτών προορίζεται για deployment στο cloud της DigitalOcean. Αναλυτικότερα, μέσω του σχετικού builder ξεκινάμε με κάποιο από τα images που ήδη παρέχει η DigitalOcean (δεν ξεκινάμε από μηδενική βάση, δηλαδή), εφαρμόζουμε το επιθυμητό provisioning (ενημέρωση/εγκατάσταση λογισμικού, ρυθμίσεις για υπηρεσίες κι εφαρμογές κ.ο.κ.) και μετά φτιάχνουμε ένα snapshot. Αυτό το snapshot μπορούμε να το χρησιμοποιούμε ως πρότυπο για νέα droplets (εικονικές μηχανές στο cloud της DigitalOcean). Ας δούμε ένα συγκεκριμένο παράδειγμα: τη δημιουργία snapshot στο cloud της DigitalOcean, με Ubuntu 18.04 LTS Server και τον nginx web server ρυθμισμένο κι έτοιμο. Για το provisioning του snapshot (ενημέρωση λειτουργικού κι εφαρμογών, εγκατάσταση και ρύθμιση του nginx) θα στραφούμε στο Ansible, ώστε να αποκτήσουμε μια πρώτη εικόνα για το πώς μοιάζει το σύγχρονο configuration management.

Δεν θα σας ταλαιπωρήσουμε φτιάχνοντας το Packer template από την αρχή. Αντίθετα, έχουμε ήδη ετοιμάσει ένα πλήρες παράδειγμα με όλα τα σχετικά αρχεία (Packer template, Ansible Playbook, configuration files κ.ο.κ.). Μπορείτε –και πρέπει– να τα κατεβάσετε τώρα, κλωνοποιώντας το αντίστοιχο repository στο GitHub:

mkdir github
cd github
git clone https://github.com/colder-is-better/packer-do-ansible.git
cd packer-do-ansible

Πριν κάνουμε οτιδήποτε ανοίγουμε το αρχείο template.json κι αντικαθιστούμε το PUT_YOUR_DO_API_TOKEN_HERE (βλ. αντικείμενο variables) με ένα από τα DigitalOcean API tokens που διαθέτουμε (το token πρέπει να έχει το Write Scope ενεργοποιημένο). Όπως μπορείτε να διαπιστώσετε, το συγκεκριμένο template του Packer είναι πολύ πιο απλό σε σχέση με εκείνο που φτιάξαμε στο άρθρο περί Packer. Ρίξτε μια ματιά, αποθηκεύστε την αλλαγή (DO API token!) κι εγκαταλείψτε τον editor.

Πριν ξεκινήσουμε, οφείλουμε να έχουμε το Ansible εγκατεστημένο. Μια αναλυτική περιγραφή θα ξέφευγε από τους σκοπούς του παρόντος — ούτως ή άλλως στο Ansible θα επανέλθουμε σε επόμενα άρθρα. Τώρα, για τη δημιουργία του image στο cloud της DigitalOcean αρκεί να πληκτρολογήσουμε το ακόλουθο:

packer build template.json

Από τη στιγμή που το νέο μας snapshot βασίζεται σε image που ήδη υπάρχει στο cloud της DigitalOcean, η δημιουργία του ολοκληρώνεται σε ελάχιστο χρόνο.

Το snapshot που φτιάχνουμε στο cloud της DigitalOcean με τη βοήθεια του Packer βασίζεται σε υπάρχον Ubuntu 18.04 LTS Server image, συνεπώς η όλη διαδικασία ολοκληρώνεται πολύ γρήγορα.

Το snapshot που φτιάχνουμε στο cloud της DigitalOcean με τη βοήθεια του Packer βασίζεται σε υπάρχον Ubuntu 18.04 LTS Server image, συνεπώς η όλη διαδικασία ολοκληρώνεται πολύ γρήγορα.

Συγκριτικά περισσότερο χρόνο διαρκεί το provisioning, δηλαδή η προετοιμασία ή αν θέλετε η προσαρμογή, του νέου image. Οι προσεκτικότεροι εξ υμών θα παρατηρήσατε ότι στο template.json, και συγκεκριμένα στο array με όνομα provisioners, υπάρχουν δύο αντικείμενα — μ’ άλλα λόγια ορίζονται δύο provisioners. Αυτοί εκτελούνται με τη σειρά που εμφανίζονται, από πάνω προς τα κάτω. Ο πρώτος είναι τύπου shell και στο σύστημα-στόχο εκτελεί μία μόνον απλή εντολή: ln -s /usr/bin/python3 /usr/bin/python. Χωρίς αυτό το symbolic link το Ansible δεν θα μπορέσει να εκτελέσει τα plays που περιγράφονται στο playbook που του υποδεικνύουμε. Ο δεύτερος provisioner είναι τύπου Ansible και του δίνουμε το αρχείο provision.yaml, το οποίο είναι το playbook που πρέπει να εκτελέσει. Εντελώς επιγραμματικά λέμε ότι τα playbooks του Ansible αποτελούν συλλογές ενός ή περισσοτέρων tasks ή αλλιώς plays, με το κάθε play να είναι μια εργασία που πρέπει να εκτελεστεί στο μηχάνημα-στόχο ή γενικά στα μηχανήματα-στόχους που διαχειριζόμαστε.

Μετά τη δημιουργία του snapshot έρχεται η σειρά των provisioners. Στο παράδειγμα έχουμε δύο. Ο πρώτος είναι ένας απλός, τύπου shell, ο οποίος αποτελείται από μία μόνο εντολή για τη δημιουργία ενός symbolic link. Ο δεύτερος provisioner είναι τύπου Ansible κι εφαρμόζει πιστά τις οδηγίες ενός playbook, προκειμένου να ενημερωθεί το λειτουργικό σύστημα και να ρυθμιστεί κατάλληλα ο nginx web server. Σημειώστε ότι χωρίς το symbolic link που δημιουργεί ο πρώτος provisioner, ο δεύτερος δεν θα μπορούσε να ξεκινήσει.

Μετά τη δημιουργία του snapshot έρχεται η σειρά των provisioners. Στο παράδειγμα έχουμε δύο. Ο πρώτος είναι ένας απλός, τύπου shell, ο οποίος αποτελείται από μία μόνο εντολή για τη δημιουργία ενός symbolic link. Ο δεύτερος provisioner είναι τύπου Ansible κι εφαρμόζει πιστά τις οδηγίες ενός playbook, προκειμένου να ενημερωθεί το λειτουργικό σύστημα και να ρυθμιστεί κατάλληλα ο nginx web server. Σημειώστε ότι χωρίς το symbolic link που δημιουργεί ο πρώτος provisioner, ο δεύτερος δεν θα μπορούσε να ξεκινήσει.

Εξετάζοντας το περιεχόμενο του playbook που έχουμε φτιάξει για το Ansible, ακόμη κι αν δεν γνωρίζουμε πολλά για το εν λόγω configuration management system εύκολα διαπιστώνουμε ότι τα επιμέρους plays φροντίζουν για τις ακόλουθες εργασίες: ανέβασμα των δικών μας ρυθμίσεων περί locales, φρεσκάρισμα των repositories του λειτουργικού (αρκεί να έχει περάσει πάνω από μία ώρα πριν από πιο πρόσφατο φρεσκάρισμα), έλεγχος για την παρουσία του εργαλείου aptitude, εφαρμογή των όποιων διαθέσιμων updates, εγκατάσταση του nginx web server και βασική του ρύθμιση, ανέβασμα server block για το site που θέλουμε να σερβίρει ο nginx, ανέβασμα απλής σελίδας ώστε να ελέγχουμε αν όντως το site μας σερβίρεται από τον nginx, επανεκκίνηση της αντίστοιχης υπηρεσίας ώστε να ληφθούν υπόψη οι επεμβάσεις μας.

Το Ansible εκτελεί τα tasks (plays) που παρατίθενται στο playbook που του έχουμε δώσει, χωρίς να επιστρέφει πολλά πολλά στην έξοδό του. Γενικά, πάντως, όταν κάποιο play για κάποιον λόγο αποτυγχάνει τότε παίρνουμε σχετικό μήνυμα λάθους.

Το Ansible εκτελεί τα tasks (plays) που παρατίθενται στο playbook που του έχουμε δώσει, χωρίς να επιστρέφει πολλά πολλά στην έξοδό του. Γενικά, πάντως, όταν κάποιο play για κάποιον λόγο αποτυγχάνει τότε παίρνουμε σχετικό μήνυμα λάθους.

Όπως φαίνεται και στην ενότητα PLAY RECAP, όλα τα tasks (plays) που δοκίμασε το Ansible εκτελέστηκαν επιτυχώς (δείτε αυτό το failed, που είναι μηδέν). Άλλος provisioner δεν υπήρχε για τον DigitalOcean builder του Packer, οπότε λίγα δευτερόλεπτα αργότερα πήραμε το ένα και μοναδικό artifact του build: ένα νέο snapshot στον λογαριασμό μας στη DigitalOcean, με Ubuntu 18.04 Server και τον nginx ρυθμισμένο βάσει των προδιαγραφών μας.

Όπως φαίνεται και στην ενότητα PLAY RECAP, όλα τα tasks (plays) που δοκίμασε το Ansible εκτελέστηκαν επιτυχώς (δείτε αυτό το failed, που είναι μηδέν). Άλλος provisioner δεν υπήρχε για τον DigitalOcean builder του Packer, οπότε λίγα δευτερόλεπτα αργότερα πήραμε το ένα και μοναδικό artifact του build: ένα νέο snapshot στον λογαριασμό μας στη DigitalOcean, με Ubuntu 18.04 Server και τον nginx ρυθμισμένο βάσει των προδιαγραφών μας.

Μετά τους provisioners ο Packer builder θα ετοιμάσει το snapshot image. Μπορούμε να το δούμε, μαζί με άλλα snapshots που ενδεχομένως έχουμε φτιάξει, από το web dashboard της DigitalOcean. Εναλλακτικά, μένουμε στο τερματικό μας και γράφουμε:

doctl compute image list-user

Το ένα και μοναδικό snapshot που διαθέτουμε αυτή τη στιγμή, στο λογαριασμό μας στη DigitalOcean: Είναι αυτό που μόλις δημιουργήσαμε μέσω του αντίστοιχου Packer builder, και ρυθμίσαμε με τη βοήθεια του Ansible.

Το ένα και μοναδικό snapshot που διαθέτουμε αυτή τη στιγμή, στο λογαριασμό μας στη DigitalOcean: Είναι αυτό που μόλις δημιουργήσαμε μέσω του αντίστοιχου Packer builder, και ρυθμίσαμε με τη βοήθεια του Ansible.

Στο παράδειγμά μας βλέπουμε ότι ο builder έδωσε στο snapshot ένα περιγραφικό αλλά μάλλον άβολα μεγάλο όνομα: delta-by-packer-1536215876. Αυτό πάντως που αξίζει να σημειώσουμε είναι το ID του (37947944, πάντα στο πλαίσιο του παραδείγματός μας). Έτσι, μπορούμε τώρα να φτιάξουμε ένα droplet με βάση το ωραιότατο snapshot μας:

doctl compute droplet create delta \
--image 37947944 --region fra1 --size s-2vcpu-2gb \
--ssh-keys 5e:f2:20:48:8e:b6:4c:b1:bf:b1:6c:2b:3b:23:f7:f7

Δημιουργία νέου droplet, κατ' εικόνα και καθ' ομοίωσιν του snapshot που φτιάξαμε πριν από περίπου πενήντα τρισεκατομμύρια πικοδευτερόλεπτα (προσέξτε το ID του snapshot).

Δημιουργία νέου droplet, κατ’ εικόνα και καθ’ ομοίωσιν του snapshot που φτιάξαμε πριν από περίπου πενήντα τρισεκατομμύρια πικοδευτερόλεπτα (προσέξτε το ID του snapshot).

Προκειμένου να βεβαιωθούμε ότι το νέο droplet δημιουργήθηκε επιτυχώς, ζητάμε τη λίστα με όλα τα droplets του λογαριασμού μας:

doctl compute droplet list \
--format "ID,Name,PublicIPv4,Memory,VCPUs,Disk,Region"

Πλέον, το νέο droplet αποτελεί μέλος του μη-κενού αριθμήσιμου συνόλου των droplets του λογαριασμού μας στη Digital την Ocean.

Πλέον, το νέο droplet αποτελεί μέλος του μη-κενού αριθμήσιμου συνόλου των droplets του λογαριασμού μας στη Digital την Ocean.

Δώστε προσοχή στο δημόσιο IPv4 του νέου droplet, με όνομα delta: για εμάς είναι το 165.227.148.192. Το αντιγράφουμε στη μπάρα διευθύνσεων ενός web browser, ώστε να ελέγξουμε α) αν το νέο μηχάνημα είναι προσβάσιμο μέσω Internet, και β) αν ο nginx web server αποκρίνεται κατά πώς προβλέπεται.

Από τον web browser της προτίμησής μας και χωρίς να ρυθμίσουμε DNS για το νέο droplet, επισκεπτόμαστε το site που σερβίρει ο nginx με βάση το IP. Βλέπουμε μια λευκή σελίδα με το μήνυμα που είχαμε βάλει στην προκαθορισμένη σελίδα του site, οπότε όλα πήγαν καλά!

Από τον web browser της προτίμησής μας και χωρίς να ρυθμίσουμε DNS για το νέο droplet, επισκεπτόμαστε το site που σερβίρει ο nginx με βάση το IP. Βλέπουμε μια λευκή σελίδα με το μήνυμα που είχαμε βάλει στην προκαθορισμένη σελίδα του site, οπότε όλα πήγαν καλά!

Το playbook για την προετοιμασία του snapshot (αρχείο provision.yml) μπορούμε να το τρέχουμε ανά πάσα στιγμή και για το droplet που δημιουργήσαμε με βάση το snapshot. Αναρωτιέστε τι θα γίνει αν το τρέξουμε, από τη στιγμή που το έχουμε ήδη τρέξει μία φορά κι ο nginx server είναι τώρα ρυθμισμένος; Πάρα πολύ καλώς κάνετε κι αναρωτιέστε. Χάρη στην ιδιότητα του idempotence που έχουν τα καλογραμμένα tasks του Ansible, θα γίνει μόνο ό,τι έχει νόημα να γίνει. Για το playbook μας, αυτό σημαίνει ότι δεν θ’ ανέβουν στον server αρχεία που έχουν ήδη ανέβει, εκτός κι αν έχουν αλλάξει οι τοπικές τους εκδοχές. Σημαίνει επίσης ότι δεν θα ξεκινήσει και πάλι ο nginx, εκτός αν για κάποιον λόγο έχει σταματήσει. Επίσης: Η υπηρεσία του nginx δεν θα ενεργοποιηθεί ξανά, εκτός αν για κάποιο λόγο έχει απενεργοποιηθεί. (Για τις διαφορές μεταξύ ενεργών-ενεργοποιημένων κι ανενεργών-απενεργοποιημένων υπηρεσιών στον κόσμο του Systemd, διαβάστε το σχετικό μας άρθρο.) Τα δε repositories του Ubuntu δεν θα φρεσκαριστούν, εκτός κι αν έχει περάσει πάνω από μία ώρα από την τελευταία φορά που φρεσκαρίστηκαν. Τέλος, ενημερώσεις πακέτων δεν θα γίνουν, εκτός βέβαια κι αν έχουν κυκλοφορήσει νεότερες εκδόσεις. Καταλαβαίνουμε, λοιπόν, ότι το να τρέχουμε πότε πότε ένα Ansible playbook δεν είναι καθόλου κακή ιδέα. Το αντίθετο: κρατά τον server ενημερωμένο κι επιπρόσθετα τον “φέρνει στα ίσα του”, ας μας επιτραπεί η έκφραση, διορθώνοντας τις όποιες παρενέργειες του λεγόμενου configuration drift.

Πώς λοιπόν ακριβώς τρέχουμε ξανά το playbook, αυτή τη φορά για το droplet μας; Στο πλαίσιο του παραδείγματός μας, αρκεί ν’ ανοίξουμε το αρχείο hosts και ν’ αντικαταστήσουμε το my.droplet.ip.address με τη διεύθυνση IP του server (π.χ., με τη διεύθυνση 165.227.148.192). Αποθηκεύουμε την αλλαγή και στο τερματικό πληκτρολογούμε:

ansible-playbook -i hosts provision.yml

Στο screenshot που ακολουθεί απεικονίζεται ένα πιθανό αποτέλεσμα της παραπάνω εντολής.

Η ιδιότητα του idempotence στην πράξη: Τρέξαμε το Ansible playbook για το νέο droplet και μόνο δύο από τα δώδεκα plays εκτελέστηκαν: το ένα αφορούσε στο φρεσκάρισμα των repositories και το άλλο στην αναβάθμιση πακέτων για τα οποία υπήρχαν νέες εκδόσεις.

Η ιδιότητα του idempotence στην πράξη: Τρέξαμε το Ansible playbook για το νέο droplet και μόνο δύο από τα δώδεκα plays εκτελέστηκαν: το ένα αφορούσε στο φρεσκάρισμα των repositories και το άλλο στην αναβάθμιση πακέτων για τα οποία υπήρχαν νέες εκδόσεις.

Έχουμε πολλά και ενδιαφέροντα να συζητήσουμε για το configuration management γενικότερα — και για το Ansible ειδικότερα. Όμως όλα αυτά θα συμβούν σε επόμενα άρθρα. Προς το παρόν σας αφήνουμε, υπενθυμίζοντας ότι τα εφήμερα droplets δεν πρέπει να τα ξεχνάμε. Αντίθετα, όταν δεν τα χρειαζόμαστε οφείλουμε να τα διαγράφουμε. Για τη διαγραφή του droplet ονόματι delta, γράφουμε: doctl compute droplet delete 108930170 (αντικαταστήστε με το ID του δικού σας droplet). Τέλος, όταν κάποια στιγμή αποφασίσουμε ότι δεν χρειαζόμαστε άλλο ένα συγκεκριμένο snapshot, το διαγράφουμε κι αυτό με ένα doctl compute droplet delete 37947944 (αντικαταστήστε με το ID του δικού σας snapshot).

Leave a Reply

You must be logged in to post a comment.

Σύνδεση

Αρχείο δημοσιεύσεων