Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

Το άρθρο εξετάζει τα προβλήματα καθαρισμού εικόνων που συσσωρεύονται σε μητρώα κοντέινερ (Docker Registry και τα ανάλογα του) στην πραγματικότητα των σύγχρονων αγωγών CI/CD για εγγενείς εφαρμογές cloud που παραδίδονται στο Kubernetes. Δίνονται τα κύρια κριτήρια για τη συνάφεια των εικόνων και τις δυσκολίες που προκύπτουν στην αυτοματοποίηση του καθαρισμού, στην εξοικονόμηση χώρου και στην κάλυψη των αναγκών των ομάδων. Τέλος, χρησιμοποιώντας το παράδειγμα ενός συγκεκριμένου έργου ανοιχτού κώδικα, θα σας πούμε πώς μπορούν να ξεπεραστούν αυτές οι δυσκολίες.

Εισαγωγή

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

  1. Χρησιμοποιήστε έναν σταθερό αριθμό ετικετών για εικόνες.
  2. καθαρίστε τις εικόνες με κάποιο τρόπο.


Ο πρώτος περιορισμός είναι μερικές φορές αποδεκτός για μικρές ομάδες. Εάν οι προγραμματιστές έχουν αρκετές μόνιμες ετικέτες (latest, main, test, boris κ.λπ.), το μητρώο δεν θα διογκωθεί σε μέγεθος και για μεγάλο χρονικό διάστημα δεν θα χρειαστεί να σκεφτείτε καθόλου να το καθαρίσετε. Άλλωστε όλες οι άσχετες εικόνες σβήνονται και απλά δεν μένει δουλειά για καθάρισμα (όλα τα κάνει ένας κανονικός απορριμματιστής).

Ωστόσο, αυτή η προσέγγιση περιορίζει σε μεγάλο βαθμό την ανάπτυξη και σπάνια εφαρμόζεται σε σύγχρονα έργα CI/CD. Αναπόσπαστο μέρος της εξέλιξης ήταν αυτοματοποίηση, που σας επιτρέπει να δοκιμάζετε, να αναπτύσσετε και να παρέχετε νέες λειτουργίες στους χρήστες πολύ πιο γρήγορα. Για παράδειγμα, σε όλα τα έργα μας, δημιουργείται αυτόματα ένας αγωγός CI με κάθε δέσμευση. Σε αυτό, η εικόνα συναρμολογείται, δοκιμάζεται, προωθείται σε διάφορα κυκλώματα Kubernetes για τον εντοπισμό σφαλμάτων και τους υπόλοιπους ελέγχους, και αν όλα πάνε καλά, οι αλλαγές φτάνουν στον τελικό χρήστη. Και αυτό δεν είναι πλέον επιστήμη πυραύλων, αλλά καθημερινό φαινόμενο για πολλούς - πιθανότατα για εσάς, αφού διαβάζετε αυτό το άρθρο.

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

Αλλά πώς μπορείτε να προσδιορίσετε αν μια εικόνα είναι σχετική;

Κριτήρια για τη συνάφεια της εικόνας

Στη συντριπτική πλειοψηφία των περιπτώσεων, τα κύρια κριτήρια θα είναι:

1. Η πρώτη (η πιο προφανής και η πιο επικριτική από όλες) είναι οι εικόνες που χρησιμοποιείται επί του παρόντος στο Kubernetes. Η κατάργηση αυτών των εικόνων μπορεί να οδηγήσει σε σημαντικό κόστος διακοπής της παραγωγής (για παράδειγμα, οι εικόνες μπορεί να απαιτούνται για αναπαραγωγή) ή να ακυρώσει τις προσπάθειες της ομάδας εντοπισμού σφαλμάτων σε οποιονδήποτε από τους βρόχους. (Για αυτό το λόγο φτιάξαμε ακόμη και μια ειδική Εξαγωγείς Προμηθέας, το οποίο παρακολουθεί την απουσία τέτοιων εικόνων σε οποιοδήποτε σύμπλεγμα Kubernetes.)

2. Δεύτερο (λιγότερο προφανές, αλλά και πολύ σημαντικό και σχετίζεται πάλι με την εκμετάλλευση) - εικόνες που απαιτείται για επαναφορά σε περίπτωση εντοπισμού σοβαρών προβλημάτων στην τρέχουσα έκδοση. Για παράδειγμα, στην περίπτωση του Helm, αυτές είναι εικόνες που χρησιμοποιούνται σε αποθηκευμένες εκδόσεις της έκδοσης. (Παρεμπιπτόντως, από προεπιλογή στο Helm το όριο είναι 256 αναθεωρήσεις, αλλά είναι απίθανο κάποιος να χρειαστεί πραγματικά να αποθηκεύσει ένα τέτοιο μεγάλος αριθμός εκδόσεων;..) Άλλωστε, ειδικότερα, αποθηκεύουμε εκδόσεις για να μπορούμε να τις χρησιμοποιήσουμε αργότερα, δηλ. «επιστρέφετε» σε αυτούς εάν είναι απαραίτητο.

3. Τρίτο - ανάγκες προγραμματιστή: Όλες οι εικόνες που σχετίζονται με την τρέχουσα δουλειά τους. Για παράδειγμα, εάν εξετάζουμε ένα PR, τότε είναι λογικό να αφήσουμε μια εικόνα που αντιστοιχεί στην τελευταία δέσμευση και, ας πούμε, στην προηγούμενη δέσμευση: με αυτόν τον τρόπο ο προγραμματιστής μπορεί να επιστρέψει γρήγορα σε οποιαδήποτε εργασία και να εργαστεί με τις τελευταίες αλλαγές.

4. Τέταρτον - εικόνες που αντιστοιχούν στις εκδόσεις της εφαρμογής μας, δηλ. είναι το τελικό προϊόν: v1.0.0, 20.04.01/XNUMX/XNUMX, sierra, κ.λπ.

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

Επιλεξιμότητα και υπάρχουσες λύσεις

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

* Εξαρτάται από συγκεκριμένες υλοποιήσεις μητρώου κοντέινερ. Εξετάσαμε τις δυνατότητες των ακόλουθων λύσεων: Azure CR, Docker Hub, ECR, GCR, GitHub Packages, GitLab Container Registry, Harbor Registry, JFrog Artifactory, Quay.io - από τον Σεπτέμβριο του 2020.

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

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

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

Απεικόνιση της ροής εργασίας στο Git

Ας υποθέσουμε ότι εργάζεστε κάτι σαν αυτό στο Git:

Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

Το εικονίδιο με μια κεφαλή στο διάγραμμα υποδεικνύει εικόνες κοντέινερ που αναπτύσσονται αυτήν τη στιγμή στο Kubernetes για οποιονδήποτε χρήστη (τελικούς χρήστες, δοκιμαστές, διαχειριστές κ.λπ.) ή χρησιμοποιούνται από προγραμματιστές για εντοπισμό σφαλμάτων και παρόμοιους σκοπούς.

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

Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

Προφανώς, ένα τέτοιο σενάριο δεν θα κάνει κανέναν χαρούμενο.

Τι θα αλλάξει εάν οι πολιτικές επιτρέπουν τη μη διαγραφή εικόνων; σύμφωνα με ένα δεδομένο χρονικό διάστημα / αριθμό τελευταίων δεσμεύσεων?

Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

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

Για να συνοψίσουμε την τρέχουσα κατάσταση της αγοράς: οι λειτουργίες που είναι διαθέσιμες στα μητρώα εμπορευματοκιβωτίων δεν προσφέρουν αρκετή ευελιξία κατά τον καθαρισμό και ο κύριος λόγος για αυτό είναι δεν υπάρχει τρόπος αλληλεπίδρασης με τον έξω κόσμο. Αποδεικνύεται ότι οι ομάδες που απαιτούν τέτοια ευελιξία αναγκάζονται να εφαρμόσουν ανεξάρτητα τη διαγραφή εικόνας "από έξω", χρησιμοποιώντας το Docker Registry API (ή το εγγενές API της αντίστοιχης υλοποίησης).

Ωστόσο, αναζητούσαμε μια καθολική λύση που θα αυτοματοποιούσε τον καθαρισμό εικόνων για διαφορετικές ομάδες που χρησιμοποιούν διαφορετικά μητρώα...

Η πορεία μας προς τον καθολικό καθαρισμό εικόνας

Από πού προέρχεται αυτή η ανάγκη; Το γεγονός είναι ότι δεν είμαστε μια ξεχωριστή ομάδα προγραμματιστών, αλλά μια ομάδα που εξυπηρετεί πολλούς από αυτούς ταυτόχρονα, βοηθώντας στην ολοκληρωμένη επίλυση προβλημάτων CI/CD. Και το κύριο τεχνικό εργαλείο για αυτό είναι το βοηθητικό πρόγραμμα Open Source werf. Η ιδιαιτερότητά του είναι ότι δεν εκτελεί μία μόνο λειτουργία, αλλά συνοδεύει τις διαδικασίες συνεχούς παράδοσης σε όλα τα στάδια: από τη συναρμολόγηση έως την ανάπτυξη.

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

* Αν και τα ίδια τα μητρώα μπορεί να είναι διαφορετικά (Docker Registry, GitLab Container Registry, Harbor, κ.λπ.), οι χρήστες τους αντιμετωπίζουν τα ίδια προβλήματα. Η καθολική λύση στην περίπτωσή μας δεν εξαρτάται από την εφαρμογή του μητρώου, γιατί τρέχει εκτός των ίδιων των μητρώων και προσφέρει την ίδια συμπεριφορά για όλους.

Αν και χρησιμοποιούμε το werf ως παράδειγμα υλοποίησης, ελπίζουμε ότι οι προσεγγίσεις που θα χρησιμοποιηθούν θα είναι χρήσιμες σε άλλες ομάδες που αντιμετωπίζουν παρόμοιες δυσκολίες.

Έτσι ασχοληθήκαμε εξωτερικός εφαρμογή ενός μηχανισμού για τον καθαρισμό εικόνων - αντί για εκείνες τις δυνατότητες που είναι ήδη ενσωματωμένες σε μητρώα για κοντέινερ. Το πρώτο βήμα ήταν η χρήση του Docker Registry API για τη δημιουργία των ίδιων αρχέγονων πολιτικών για τον αριθμό των ετικετών και τον χρόνο δημιουργίας τους (που αναφέρθηκαν παραπάνω). Προστέθηκε σε αυτά επιτρέψτε τη λίστα με βάση τις εικόνες που χρησιμοποιούνται στην αναπτυγμένη υποδομή, δηλ. Kubernetes. Για το τελευταίο, αρκούσε η χρήση του Kubernetes API για επανάληψη σε όλους τους αναπτυγμένους πόρους και λήψη μιας λίστας τιμών image.

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

Σχέδια τοποθέτησης ετικετών

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

Αυτή η προσέγγιση κατέληξε σε ένα σύνολο πολιτικών που επέτρεψαν στο Git να χρησιμοποιηθεί ως η μοναδική πηγή αλήθειας:

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

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

Νέος αλγόριθμος

Γιατί; Με την προσθήκη ετικετών βάσει περιεχομένου, κάθε ετικέτα μπορεί να ικανοποιήσει πολλαπλές δεσμεύσεις στο Git. Όταν καθαρίζετε εικόνες, δεν μπορείτε πλέον να υποθέσετε μόνο από το commit όπου προστέθηκε η νέα ετικέτα στο μητρώο.

Για τον νέο αλγόριθμο καθαρισμού, αποφασίστηκε να απομακρυνθούμε από τα σχήματα προσθήκης ετικετών και να δημιουργήσουμε διαδικασία μετα-εικόνας, καθένα από τα οποία αποθηκεύει ένα σωρό από:

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

Προβλέφθηκε δηλαδή σύνδεση δημοσιευμένων ετικετών με δεσμεύσεις στο Git.

Τελική διαμόρφωση και γενικός αλγόριθμος

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

  • πολλές αναφορές, δηλ. Ετικέτες Git ή κλάδοι Git που χρησιμοποιούνται κατά τη σάρωση.
  • και το όριο των εικόνων που αναζητήθηκαν για κάθε αναφορά από το σύνολο.

Για παράδειγμα, η προεπιλεγμένη διαμόρφωση πολιτικής άρχισε να μοιάζει με αυτό:

cleanup:
  keepPolicies:
  - references:
      tag: /.*/
      limit:
        last: 10
  - references:
      branch: /.*/
      limit:
        last: 10
        in: 168h
        operator: And
    imagesPerReference:
      last: 2
      in: 168h
      operator: And
  - references:  
      branch: /^(main|staging|production)$/
    imagesPerReference:
      last: 10

Αυτή η διαμόρφωση περιέχει τρεις πολιτικές που συμμορφώνονται με τους ακόλουθους κανόνες:

  1. Αποθηκεύστε την εικόνα για τις τελευταίες 10 ετικέτες Git (ανά ημερομηνία δημιουργίας ετικέτας).
  2. Αποθηκεύστε όχι περισσότερες από 2 εικόνες που δημοσιεύτηκαν την τελευταία εβδομάδα για όχι περισσότερες από 10 νήματα με δραστηριότητα την τελευταία εβδομάδα.
  3. Αποθηκεύστε 10 εικόνες για κλάδους main, staging и production.

Ο τελικός αλγόριθμος συνοψίζεται στα ακόλουθα βήματα:

  • Ανάκτηση δηλώσεων από το μητρώο κοντέινερ.
  • Εξαιρούνται οι εικόνες που χρησιμοποιούνται στο Kubernetes, επειδή Τους έχουμε ήδη προεπιλέξει ψηφίζοντας το K8s API.
  • Σάρωση ιστορικού Git και εξαίρεση εικόνων με βάση καθορισμένες πολιτικές.
  • Αφαίρεση των υπόλοιπων εικόνων.

Επιστρέφοντας στην παράστασή μας, αυτό συμβαίνει με το werf:

Το πρόβλημα του «έξυπνου» καθαρισμού εικόνων κοντέινερ και η επίλυσή του στο werf

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

Συμπέρασμα

  • Αργά ή γρήγορα, οι περισσότερες ομάδες αντιμετωπίζουν το πρόβλημα της υπερχείλισης μητρώου.
  • Κατά την αναζήτηση λύσεων, είναι πρώτα απαραίτητο να καθοριστούν τα κριτήρια για τη συνάφεια της εικόνας.
  • Τα εργαλεία που προσφέρονται από δημοφιλείς υπηρεσίες μητρώου κοντέινερ σάς επιτρέπουν να οργανώσετε μια πολύ απλή εκκαθάριση που δεν λαμβάνει υπόψη τον «έξω κόσμο»: τις εικόνες που χρησιμοποιούνται στο Kubernetes και τις ιδιαιτερότητες των ροών εργασίας της ομάδας.
  • Ένας ευέλικτος και αποτελεσματικός αλγόριθμος πρέπει να έχει κατανόηση των διαδικασιών CI/CD και να λειτουργεί όχι μόνο με δεδομένα εικόνας Docker.

PS

Διαβάστε επίσης στο blog μας:

Πηγή: www.habr.com

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