Φαντάσου δύο ομάδες προγραμματιστών.
Η πρώτη ετοιμάζει μια νέα έκδοση της εφαρμογής.
Ο προγραμματιστής ολοκληρώνει την εργασία. Κάποιος ελέγχει τον κώδικα. Μετά πρέπει να τρέξουν οι δοκιμές. Κάποιος ετοιμάζει το πακέτο. Κάποιος άλλος συνδέεται στον διακομιστή. Στη συνέχεια πρέπει να γίνουν μερικές χειροκίνητες ενέργειες, να ελεγχθεί η ρύθμιση και να παρακολουθηθεί το σύστημα μετά την ανάπτυξη. Αν όλα πάνε καλά, η νέα έκδοση γίνεται διαθέσιμη.
Η δεύτερη ομάδα δουλεύει διαφορετικά.
Ο κώδικας καταλήγει στο αποθετήριο. Αυτόματα εκτελούνται δοκιμές, ανάλυση ποιότητας και έλεγχοι ασφαλείας. Το σύστημα χτίζει την έκδοση της εφαρμογής, την αναπτύσσει σε περιβάλλον δοκιμών, εκτελεί επόμενους ελέγχους και, αφού πληρωθούν ορισμένες προϋποθέσεις, μπορεί να τη διαθέσει σε παραγωγή. Αν κάτι πάει στραβά, η ανάπτυξη σταματά ή το σύστημα μπορεί να επιστρέψει στην προηγούμενη έκδοση.
Και οι δύο ομάδες δημιουργούν λογισμικό.
Αλλά μόνο η μία έχει χτίσει μια επαναλήψιμη διαδικασία παράδοσης λογισμικού.
Και ακριβώς αυτό είναι το CI/CD.
"Λειτουργεί στην παραγωγή" δεν σημαίνει ακόμα ώριμη διαδικασία
Πολλές εταιρείες μετρούν την επιτυχία με έναν πολύ απλό δείκτη: η εφαρμογή λειτουργεί.
Αυτό φυσικά είναι η βασική προϋπόθεση.
Αλλά όσο το σύστημα μεγαλώνει, προκύπτουν κι άλλα ερωτήματα:
- Πόσο γρήγορα μπορούμε να αναπτύξουμε μια διόρθωση;
- Πόσο συχνά μπορούμε να δημοσιεύουμε νέα χαρακτηριστικά;
- Πόσες χειροκίνητες ενέργειες εκτελούμε σε κάθε ανάπτυξη;
- Μπορεί κάθε προγραμματιστής να εκτελεί τη διαδικασία ανάπτυξης με τους ίδιους κανόνες;
- Ξέρουμε ποια έκδοση λειτουργεί αυτή τη στιγμή;
- Μπορούμε να επιστρέψουμε στην προηγούμενη έκδοση;
- Μετά την ανάπτυξη ελέγχουμε αυτόματα αν το σύστημα λειτουργεί σωστά;
- Έχουμε παρακολούθηση;
- Ξέρουμε ότι η ανάπτυξη προκάλεσε πρόβλημα πριν το αναφέρει ο πελάτης;
Αυτά είναι ερωτήματα σχετικά με το software delivery, και όχι μόνο με τον ίδιο τον προγραμματισμό.
CI και CD - δύο στοιχεία μιας ενιαίας διαδικασίας
Το CI, δηλαδή Continuous Integration, σημαίνει συνεχή ενοποίηση των αλλαγών.
Στην πράξη, αυτό σημαίνει ότι οι αλλαγές καταλήγουν συχνά στο κοινό αποθετήριο και ελέγχονται αυτόματα.
Ένα τυπικό pipeline μπορεί να εκτελεί, μεταξύ άλλων:
-
μεταγλώττιση ή χτίσιμο της εφαρμογής,
-
unit tests,
-
integration tests,
-
linting,
-
στατική ανάλυση κώδικα,
-
σάρωση εξαρτήσεων,
-
ελέγχους ασφαλείας,
-
δημιουργία deployable artifacts.
Έτσι, το πρόβλημα μπορεί να εντοπιστεί πριν ο κώδικας φτάσει στην παραγωγή.
Το CD, δηλαδή Continuous Delivery ή Continuous Deployment, αφορά το επόμενο στάδιο - την παράδοση των αλλαγών.
Ανάλογα με το επιλεγμένο μοντέλο, το σύστημα μπορεί να προετοιμάσει μια έτοιμη έκδοση για ανάπτυξη ή να την αναπτύξει αυτόματα αφού περάσει από συγκεκριμένους ελέγχους.
Αυτή είναι μια σημαντική διάκριση.
Το Continuous Delivery δεν σημαίνει απαραίτητα αυτόματη ανάπτυξη κάθε αλλαγής στην παραγωγή.
Μπορεί απλώς να σημαίνει ότι κάθε έκδοση προετοιμάζεται με επαναλήψιμο τρόπο για ανάπτυξη.
Γιατί οι χειροκίνητες αναπτύξεις γίνονται πρόβλημα;
Η χειροκίνητη ανάπτυξη δεν είναι απαραίτητα κακή.
Σε ένα μικρό έργο μπορεί να είναι απολύτως επαρκής.
Το πρόβλημα ξεκινά όταν η διαδικασία μεγαλώνει μαζί με την εφαρμογή.
Στην αρχή έχουμε ένα άτομο που ξέρει πώς να αναπτύξει το σύστημα. Ύστερα προστίθεται ένας δεύτερος διακομιστής. Μετά το περιβάλλον δοκιμών. Στη συνέχεια η βάση δεδομένων, η cache, οι ουρές, το storage, μερικές υπηρεσίες και εξωτερικά API. Σε αυτά προστίθενται διαφορετικές ρυθμίσεις για development, δοκιμές και παραγωγή.
Μετά από λίγα χρόνια η διαδικασία μπορεί να μοιάζει κάπως έτσι:
"Πρώτα τρέξε το X, μετά άλλαξε την παράμετρο Y, ύστερα κάνε επανεκκίνηση της υπηρεσίας Z, αλλά πριν από αυτό πάρε ένα αντίγραφο της βάσης. Και αν εμφανιστεί σφάλμα, κάλεσε το άτομο που το ανέπτυξε την τελευταία φορά."
Αυτό δεν είναι πια διαδικασία. Είναι γνώση κρυμμένη μέσα στο μυαλό ενός ανθρώπου. Και ακριβώς τότε το ρίσκο αυξάνεται.
Ο αυτοματισμός δεν είναι μόνο για την άνεση των προγραμματιστών
Συχνά το CI/CD παρουσιάζεται ως εργαλείο που αυξάνει την άνεση των developers. Αυτό είναι αλήθεια, αλλά είναι μόνο ένα μέρος της εικόνας.
Ο αυτοματισμός του delivery αυξάνει κυρίως την επαναληψιμότητα της διαδικασίας.
Αν την ανάπτυξη την εκτελεί άνθρωπος, υπάρχει πιθανότητα κάθε φορά να κάνει κάτι λίγο διαφορετικά.
Αν το κάνει το pipeline, μπορεί να οριστεί η ακριβής ακολουθία βημάτων.
Η ίδια έκδοση.
Οι ίδιες δοκιμές.
Οι ίδιοι έλεγχοι.
Οι ίδιοι κανόνες.
Αυτό είναι ιδιαίτερα σημαντικό σε έργα που αναπτύσσονται από πολλά άτομα ή πολλές ομάδες.
Οι δοκιμές πριν από την ανάπτυξη είναι πιο σημαντικές από την ταχύτητα της ανάπτυξης
Ο αυτοματισμός χωρίς δοκιμές μπορεί απλώς να κάνει τα λάθη να εμφανίζονται πιο γρήγορα.
Γι' αυτό ένα σωστά σχεδιασμένο pipeline δεν θα πρέπει να είναι μόνο ένας μηχανισμός: "κώδικας → παραγωγή".
Θα πρέπει να είναι ένα σύστημα ελέγχου ποιότητας.
Ανάλογα με το έργο, μπορεί να περιλαμβάνει:
- Unit tests - ελέγχουν μεμονωμένα στοιχεία της λογικής.
- Integration tests - ελέγχουν τη συνεργασία των components.
- End-to-end tests - προσομοιώνουν πραγματικά σενάρια χρήστη.
- Tests ασφαλείας - ελέγχουν μεταξύ άλλων εξαρτήσεις και γνωστά τρωτά σημεία.
- Tests απόδοσης - απαραίτητα εκεί όπου είναι σημαντικός ο χειρισμός συγκεκριμένου φορτίου.
Δεν χρειάζεται κάθε εφαρμογή όλα αυτά τα επίπεδα στον ίδιο βαθμό.
Και αυτό είναι σημαντικό.
Το CI/CD δεν αφορά την προσθήκη όσο το δυνατόν περισσότερων εργαλείων στο pipeline.
Αφορά την επιλογή ελέγχων που ταιριάζουν στο ρίσκο του συγκεκριμένου συστήματος.
Τι συμβαίνει όταν ένα test δεν περάσει;
Αυτό είναι ένα από τα πιο σημαντικά ερωτήματα σε όλη τη διαδικασία.
Ένα ώριμο pipeline πρέπει να έχει ξεκάθαρους κανόνες.
Αν ένα κρίσιμο test αποτύχει, η έκδοση δεν θα πρέπει να θεωρείται έτοιμη για ανάπτυξη.
Αν ένας έλεγχος ασφαλείας εντοπίσει συγκεκριμένο επίπεδο κινδύνου, το pipeline μπορεί να σταματήσει τη διαδικασία.
Αν το build αποτύχει, δεν υπάρχει τίποτα για ανάπτυξη.
Ακούγεται απλό. Αλλά ακριβώς αυτά τα αυτόματα "gates" είναι που κάνουν την ποιότητα να μην εξαρτάται μόνο από τη μνήμη και την ακρίβεια του ανθρώπου.
Κι αν η ανάπτυξη παρ' όλα αυτά αποτύχει;
Ακόμα και η καλύτερη διαδικασία δεν εξαλείφει όλα τα λάθη. Γι' αυτό το δεύτερο στοιχείο του ώριμου delivery είναι η δυνατότητα ελεγχόμενης επιστροφής της αλλαγής.
Το rollback μπορεί να σημαίνει επιστροφή στο προηγούμενο artifact, στο image του container ή στην έκδοση της εφαρμογής. Αλλά εδώ προκύπτει ένα σημαντικό πρόβλημα. Το rollback του κώδικα δεν σημαίνει πάντα rollback των δεδομένων.
Αν η νέα έκδοση άλλαξε τη δομή της βάσης δεδομένων, η κατάσταση γίνεται πιο περίπλοκη.
Γι’ αυτό οι μεταναστεύσεις βάσεων δεδομένων θα πρέπει να σχεδιάζονται έτσι ώστε η όλη διαδικασία να είναι όσο το δυνατόν πιο ασφαλής και αναστρέψιμη ή, τουλάχιστον, συμβατή με την προηγούμενη έκδοση της εφαρμογής.
Αυτό είναι ένα από τα παραδείγματα που δείχνουν ότι το επαγγελματικό CI/CD είναι αρχιτεκτονικό ζήτημα και όχι απλώς διαμόρφωση ενός εργαλείου.
Blue-green, canary και άλλες στρατηγικές ανάπτυξης
Σε πιο απαιτητικά συστήματα δεν χρειάζεται να μεταφέρονται αμέσως όλοι οι χρήστες στη νέα έκδοση. Μπορούν να εφαρμοστούν διάφορες στρατηγικές deployment.
Blue-green deployment
Λειτουργούν δύο εκδόσεις του περιβάλλοντος.
Η μία εξυπηρετεί την κίνηση, η άλλη προετοιμάζεται για να την αναλάβει.
Μετά από θετική επαλήθευση ακολουθεί η εναλλαγή.
Το πλεονέκτημα είναι η δυνατότητα γρήγορης επιστροφής στο προηγούμενο περιβάλλον.
Το μειονέκτημα μπορεί να είναι η μεγαλύτερη κατανάλωση υποδομής.
Canary deployment
Η νέα έκδοση φτάνει πρώτα σε ένα μικρό μέρος των χρηστών ή της κίνησης.
Αν η παρακολούθηση δεν δείξει προβλήματα, το εύρος της ανάπτυξης μπορεί να αυξάνεται σταδιακά.
Αυτό περιορίζει το δυνητικό εύρος του σφάλματος.
Απαιτεί όμως κατάλληλη υποδομή, παρακολούθηση και τρόπο διαχείρισης της κίνησης.
Feature flags
Η λειτουργία μπορεί να αναπτυχθεί στο σύστημα, αλλά να παραμένει απενεργοποιημένη για τους χρήστες.
Χάρη σε αυτό, η ανάπτυξη του κώδικα και η ενεργοποίηση της λειτουργικότητας γίνονται δύο ξεχωριστές διαδικασίες.
Αυτό δίνει μεγαλύτερο έλεγχο, ιδιαίτερα σε μεγάλες αλλαγές.
Δεν σημαίνει όμως ότι τα feature flags είναι λύση για κάθε έργο. Η υπερβολή τους μπορεί επίσης να αυξήσει την πολυπλοκότητα του συστήματος.
Παρακολούθηση μετά την ανάπτυξη
Μπορεί να περάσουν όλα τα tests. Μπορεί να υπάρχει εξαιρετικό pipeline. Μπορεί να αναπτυχθεί η νέα έκδοση χωρίς κανένα σφάλμα. Και λίγα λεπτά αργότερα η εφαρμογή μπορεί να αρχίσει να συμπεριφέρεται διαφορετικά υπό πραγματικό φορτίο.
Γι’ αυτό η διαδικασία δεν πρέπει να τελειώνει στο deployment. Χρειάζεται observability, δηλαδή η δυνατότητα να καταλαβαίνουμε τι συμβαίνει μέσα στο λειτουργικό σύστημα.
Ανάλογα με την αρχιτεκτονική περιλαμβάνει μεταξύ άλλων:
-
logs,
-
metrics,
-
tracing,
-
παρακολούθηση υποδομής,
-
παρακολούθηση εφαρμογής,
-
alerts,
-
πληροφορίες για σφάλματα,
-
επιχειρηματικούς δείκτες.
Δεν πρόκειται να συλλέγουμε τα πάντα. Πρόκειται να μπορούμε να απαντάμε σε σημαντικά ερωτήματα με βάση τα δεδομένα.
Η εφαρμογή λειτουργεί;
Λειτουργεί πιο αργά από πριν;
Αυξήθηκε ο αριθμός των σφαλμάτων;
Ποια υπηρεσία προκαλεί το πρόβλημα;
Το πρόβλημα αφορά όλους τους χρήστες ή μόνο ένα μέρος;
100 αναπτύξεις την ημέρα δεν είναι πάντα ο στόχος
Ο τίτλος αυτού του άρθρου μιλά για 100 αναπτύξεις την ημέρα, αλλά δεν πρόκειται να τεθεί αυτός ο αριθμός ως στόχος.
Σε ένα εσωτερικό σύστημα που ενημερώνεται μία φορά τον μήνα δεν έχει νόημα να στοχεύουμε τεχνητά σε εκατοντάδες deployments. Σε ένα σύστημα που αναπτύσσεται πολύ έντονα μια τέτοια συχνότητα μπορεί όμως να είναι τεχνικά εφικτή.
Το κρίσιμο είναι η ικανότητα ασφαλούς παράδοσης αλλαγών, όχι ο ίδιος ο αριθμός των αναπτύξεων. Αυτή είναι μια θεμελιώδης διαφορά.
Η ωριμότητα της διαδικασίας μετριέται όχι από το πόσο συχνά κάνουμε deploy, αλλά από το πόσο προβλέψιμα και ασφαλώς μπορούμε να το κάνουμε.
Πότε το CI/CD μπορεί να είναι υπερβολή ως προς τη μορφή σε σχέση με το περιεχόμενο;
Δεν χρειάζεται κάθε εφαρμογή πολύπλοκη υποδομή deployment.
Αν έχουμε μια μικρή εφαρμογή, μικρή ομάδα και λίγες αναπτύξεις τον χρόνο, ένα εκτεταμένο pipeline μπορεί να κοστίζει περισσότερο από τα προβλήματα που λύνει.
Το ίδιο ισχύει και σε πολύ ειδικά συστήματα, όπου το deployment απαιτεί χειροκίνητο έλεγχο για λόγους ασφάλειας, κανονισμών ή της φύσης της υποδομής.
Γι’ αυτό η αρχιτεκτονική του delivery πρέπει να προκύπτει από τις ανάγκες του συστήματος. Όχι από τη μόδα.
Πότε η αυτοματοποίηση των deployments δίνει ιδιαίτερα πολλά;
Αξίζει να τη σκεφτούμε ιδιαίτερα όταν:
-
το σύστημα αναπτύσσεται τακτικά,
-
πάνω στον κώδικα εργάζονται αρκετά άτομα,
-
υπάρχει περισσότερα από ένα περιβάλλοντα,
-
οι αναπτύξεις είναι συχνές,
-
οι χειροκίνητες αναπτύξεις προκαλούν σφάλματα,
-
το σύστημα έχει κρίσιμη επιχειρηματική σημασία,
-
χρειαζόμαστε γρήγορο rollback,
-
η εφαρμογή διαθέτει πολλά στοιχεία,
-
απαιτούνται audits ή ίχνος αλλαγών,
-
ο χρόνος παράδοσης της λειτουργίας έχει επιχειρηματική σημασία.
Σε τέτοιες περιπτώσεις ένα καλά σχεδιασμένο pipeline μπορεί να είναι ένα από τα σημαντικότερα στοιχεία της διαδικασίας παραγωγής λογισμικού.
Το CI/CD δεν διορθώνει κακή αρχιτεκτονική
Αυτό επίσης αξίζει να τονιστεί.
Μπορεί να δημιουργηθεί ένα εξαιρετικό pipeline για μια κακή εφαρμογή.
Να δοκιμάζεται αυτόματα κακός κώδικας.
Να γίνεται αυτόματη ανάπτυξη κακής αρχιτεκτονικής.
Να κλιμακώνεται αυτόματα ένα κακώς σχεδιασμένο σύστημα.
Η αυτοματοποίηση λοιπόν δεν αντικαθιστά την αρχιτεκτονική, τα tests ούτε τις ικανότητες της ομάδας.
Ενισχύει την υπάρχουσα διαδικασία.
Αν η διαδικασία είναι καλή, βοηθά να κλιμακωθεί.
Αν η διαδικασία είναι κακή, μπορεί απλώς να εκτελεί πιο γρήγορα κακά πράγματα.
Πώς μοιάζει μια ώριμη διαδικασία;
Δεν υπάρχει ένα μοναδικό καθολικό pipeline.
Αλλά μια ώριμη διαδικασία θα πρέπει να έχει μερικά βασικά χαρακτηριστικά.
Επαναληψιμότητα - το deployment εκτελείται σύμφωνα με καθορισμένα βήματα.
Αυτοματοποίηση - οι μηχανές εκτελούν όσο το δυνατόν μεγαλύτερο μέρος της επαναλαμβανόμενης εργασίας.
Δοκιμασιμότητα - οι αλλαγές επαληθεύονται αυτόματα.
Ασφάλεια - η διαδικασία περιλαμβάνει κατάλληλους ελέγχους ασφαλείας.
Παρατηρησιμότητα - μετά το deployment ξέρουμε τι συμβαίνει με το σύστημα.
Αναστρεψιμότητα - υπάρχει σχεδιασμένος τρόπος αντίδρασης σε αποτυχημένη αλλαγή.
Ιχνηλάτηση αλλαγών - ξέρουμε ποια έκδοση αναπτύχθηκε και από τι προέκυψε.
Έλεγχο πρόσβασης - δεν μπορεί ο καθένας να αναπτύσσει ό,τι θέλει στην παραγωγή.
Από τέτοια στοιχεία δημιουργείται η επαγγελματική διαδικασία software delivery.
Η σημαντικότερη αλλαγή ξεκινά από μια διαφορετική ερώτηση
Οι εταιρείες συχνά ρωτούν: "Πόσο γρήγορα μπορούμε να δημιουργήσουμε αυτή τη λειτουργία;"
Αξίζει να προστεθεί και μια δεύτερη ερώτηση: "Πόσο γρήγορα και ασφαλώς θα μπορούμε να παραδίδουμε τις επόμενες 50 λειτουργίες;"
Γιατί μια μεμονωμένη ανάπτυξη μπορεί να γίνει χειροκίνητα. Μπορείς ακόμη και να αναπτύσσεις χειροκίνητα μια εφαρμογή για μερικά χρόνια. Αλλά όσο μεγαλώνει το προϊόν, η ομάδα, ο αριθμός των χρηστών και ο αριθμός των αλλαγών, αυξάνεται επίσης και το κόστος μιας τέτοιας προσέγγισης.
Γι’ αυτό το CI/CD, τα αυτόματα tests, η παρακολούθηση και οι ελεγχόμενες αναπτύξεις δεν είναι λύσεις μόνο για μεγάλες εταιρείες.
Είναι στοιχεία της υποδομής της διαδικασίας που επιτρέπει να αναπτύσσουμε λογισμικό χωρίς να προσθέτουμε περιττό ρίσκο σε κάθε επόμενη αλλαγή.
Και τελικά ακριβώς γι’ αυτό πρόκειται.
Όχι για 100 αναπτύξεις την ημέρα.
Όχι για μοντέρνα εργαλεία.
Όχι για το πιο σύνθετο pipeline.
Αλλά για τη δυνατότητα να λες:
"Έχουμε μια αλλαγή. Την ελέγξαμε. Ξέρουμε τι θα αναπτύξουμε. Ξέρουμε πώς θα την παρακολουθήσουμε. Και ξέρουμε τι θα κάνουμε αν κάτι πάει στραβά."



