Δυναμική συναρμολόγηση και ανάπτυξη εικόνων Docker με werf χρησιμοποιώντας το παράδειγμα μιας τοποθεσίας τεκμηρίωσης με έκδοση

Έχουμε ήδη μιλήσει για το εργαλείο GitOps μας περισσότερες από μία φορές. werf, και αυτή τη φορά θα θέλαμε να μοιραστούμε την εμπειρία μας στη συναρμολόγηση του ιστότοπου με την τεκμηρίωση του ίδιου του έργου - werf.io (η ρωσική του έκδοση είναι en.werf.io). Αυτή είναι μια συνηθισμένη στατική τοποθεσία, αλλά η συναρμολόγησή της είναι ενδιαφέρουσα καθώς είναι κατασκευασμένη χρησιμοποιώντας έναν δυναμικό αριθμό τεχνουργημάτων.

Δυναμική συναρμολόγηση και ανάπτυξη εικόνων Docker με werf χρησιμοποιώντας το παράδειγμα μιας τοποθεσίας τεκμηρίωσης με έκδοση

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

Εισαγωγή: πώς λειτουργεί ο ιστότοπος

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

  • Οι νέες λειτουργίες werf δεν πρέπει να κυκλοφορούν χωρίς ενημέρωση της τεκμηρίωσης και, αντιστρόφως, τυχόν αλλαγές στην τεκμηρίωση συνεπάγονται την κυκλοφορία μιας νέας έκδοσης του werf.
  • Το έργο έχει μια αρκετά εντατική ανάπτυξη: νέες εκδόσεις μπορούν να κυκλοφορούν πολλές φορές την ημέρα.
  • Οποιεσδήποτε μη αυτόματες λειτουργίες για την ανάπτυξη μιας τοποθεσίας με νέα έκδοση τεκμηρίωσης είναι τουλάχιστον κουραστικές.
  • Το έργο υιοθετεί μια σημασιολογική προσέγγιση εκδόσεις, με 5 κανάλια σταθερότητας. Η διαδικασία απελευθέρωσης περιλαμβάνει τη διαδοχική διέλευση των εκδόσεων μέσω καναλιών με σειρά αυξανόμενης σταθερότητας: από άλφα σε στερεό βράχο.
  • Ο ιστότοπος έχει μια έκδοση στη ρωσική γλώσσα, η οποία "ζει και αναπτύσσεται" (δηλαδή, το περιεχόμενο της οποίας ενημερώνεται) παράλληλα με την κύρια (δηλαδή, στην αγγλική) έκδοση.

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

Στο μενού επιλογής έκδοσης στον ιστότοπο, οι πιο πρόσφατες εκδόσεις του werf είναι διαθέσιμες σε κάθε κανάλι. Από προεπιλογή, κατά διεύθυνση werf.io/documentation ανοίγει η έκδοση του πιο σταθερού καναλιού για την τελευταία έκδοση - ευρετηριάζεται επίσης από τις μηχανές αναζήτησης. Η τεκμηρίωση για το κανάλι είναι διαθέσιμη σε ξεχωριστές διευθύνσεις (για παράδειγμα, werf.io/v1.0-beta/documentation για έκδοση beta 1.0).

Συνολικά, ο ιστότοπος διαθέτει τις ακόλουθες εκδόσεις:

  1. root (ανοίγει από προεπιλογή),
  2. για κάθε ενεργό κανάλι ενημέρωσης κάθε κυκλοφορίας (για παράδειγμα, werf.io/v1.0-beta).

Για να δημιουργήσετε μια συγκεκριμένη έκδοση ενός ιστότοπου, γενικά, αρκεί να το μεταγλωττίσετε χρησιμοποιώντας Jekyllτρέχοντας στον κατάλογο /docs αντίστοιχη εντολή στο αποθετήριο werf (jekyll build), αφού μεταβείτε στην ετικέτα Git της απαιτούμενης έκδοσης.

Μένει μόνο να προσθέσουμε ότι:

  • το ίδιο το βοηθητικό πρόγραμμα (werf) χρησιμοποιείται για συναρμολόγηση.
  • Οι διεργασίες CI/CD δημιουργούνται με βάση το GitLab CI.
  • και όλα αυτά, φυσικά, τρέχουν στο Kubernetes.

εργασίες

Τώρα ας διατυπώσουμε εργασίες που λαμβάνουν υπόψη όλες τις περιγραφόμενες ιδιαιτερότητες:

  1. Μετά την αλλαγή της έκδοσης werf σε οποιοδήποτε κανάλι ενημέρωσης η τεκμηρίωση στον ιστότοπο θα πρέπει να ενημερώνεται αυτόματα.
  2. Για ανάπτυξη χρειάζεται να μπορείς μερικές φορές προβολή εκδόσεων προεπισκόπησης του ιστότοπου.

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

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

Αποδεικνύεται ότι η συναρμολόγηση εξαρτάται από την αλλαγή των εξωτερικών δεδομένων.

Реализация

Επιλογή Προσέγγισης

Εναλλακτικά, μπορείτε να εκτελέσετε κάθε απαιτούμενη έκδοση ως ξεχωριστό pod στο Kubernetes. Αυτή η επιλογή συνεπάγεται μεγαλύτερο αριθμό αντικειμένων στο σύμπλεγμα, τα οποία θα αυξάνονται με την αύξηση του αριθμού των σταθερών απελευθερώσεων werf. Και αυτό, με τη σειρά του, συνεπάγεται πιο περίπλοκη συντήρηση: κάθε έκδοση έχει τον δικό της διακομιστή HTTP και με μικρό φορτίο. Φυσικά, αυτό συνεπάγεται και μεγαλύτερο κόστος πόρων.

Εμείς πήραμε τον ίδιο δρόμο συναρμολόγηση όλων των απαραίτητων εκδόσεων σε μία εικόνα. Τα μεταγλωττισμένα στατικά όλων των εκδόσεων του ιστότοπου βρίσκονται σε ένα κοντέινερ με NGINX και η κυκλοφορία στην αντίστοιχη Ανάπτυξη πραγματοποιείται μέσω του NGINX Ingress. Μια απλή δομή - μια εφαρμογή χωρίς κράτος - σας επιτρέπει να κλιμακώνετε εύκολα την Ανάπτυξη (ανάλογα με το φορτίο) χρησιμοποιώντας το ίδιο το Kubernetes.

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

werf vs git κλώνος και τεχνουργήματα

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

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

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

Γράφουμε werf.yaml

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

Το werf σας επιτρέπει να χρησιμοποιήσετε Πρότυπα μετάβασης στο αρχείο ρυθμίσεών σας (werf.yaml), και αυτό το καθιστά δυνατό δημιουργία ρυθμίσεων εν κινήσει ανάλογα με τα εξωτερικά δεδομένα (τι χρειάζεστε!). Τα εξωτερικά δεδομένα στην περίπτωσή μας είναι πληροφορίες σχετικά με εκδόσεις και εκδόσεις, βάσει των οποίων συλλέγουμε τον απαιτούμενο αριθμό τεχνουργημάτων και ως αποτέλεσμα λαμβάνουμε δύο εικόνες: werf-doc и werf-dev να τρέχει σε διαφορετικά κυκλώματα.

Τα εξωτερικά δεδομένα διαβιβάζονται μέσω μεταβλητών περιβάλλοντος. Ιδού η σύνθεσή τους:

  • RELEASES — μια γραμμή με μια λίστα εκδόσεων και την αντίστοιχη τρέχουσα έκδοση του werf, με τη μορφή μιας λίστας τιμών διαχωρισμένου χώρου στη μορφή <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. Ένα παράδειγμα: 1.0%v1.0.4-beta.20
  • CHANNELS — μια γραμμή με μια λίστα καναλιών και την αντίστοιχη τρέχουσα έκδοση του werf, με τη μορφή λίστας τιμών διαχωρισμένου χώρου στη μορφή <КАНАЛ>%<НОМЕР_ВЕРСИИ>. Ένα παράδειγμα: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — η έκδοση έκδοσης werf να εμφανίζεται από προεπιλογή στον ιστότοπο (δεν είναι πάντα απαραίτητο να εμφανίζεται η τεκμηρίωση με τον υψηλότερο αριθμό έκδοσης). Παράδειγμα: v1.0.4-beta.20
  • REVIEW_SHA — κατακερματισμός της δέσμευσης αναθεώρησης από την οποία πρέπει να δημιουργήσετε την έκδοση για τον βρόχο δοκιμής.

Αυτές οι μεταβλητές θα συμπληρωθούν στη διοχέτευση GitLab CI και πώς ακριβώς γράφεται παρακάτω.

Πρώτα απ 'όλα, για ευκολία, ορίζουμε σε werf.yaml Μεταβλητές προτύπου Go, εκχωρώντας τους τιμές από μεταβλητές περιβάλλοντος:

{{ $_ := set . "WerfVersions" (cat (env "CHANNELS") (env "RELEASES") | splitList " ") }}
{{ $Root := . }}
{{ $_ := set . "WerfRootVersion" (env "ROOT_VERSION") }}
{{ $_ := set . "WerfReviewCommit" (env "REVIEW_SHA") }}

Η περιγραφή του artifact για τη μεταγλώττιση της στατικής έκδοσης του ιστότοπου είναι γενικά η ίδια για όλες τις περιπτώσεις που χρειαζόμαστε (συμπεριλαμβανομένης της δημιουργίας της έκδοσης root, καθώς και της έκδοσης για το κύκλωμα dev). Επομένως, θα το μετακινήσουμε σε ξεχωριστό μπλοκ χρησιμοποιώντας τη συνάρτηση define - για επακόλουθη επαναχρησιμοποίηση include. Θα περάσουμε τα ακόλουθα ορίσματα στο πρότυπο:

  • Version — δημιουργημένη έκδοση (όνομα ετικέτας).
  • Channel — το όνομα του καναλιού ενημέρωσης για το οποίο δημιουργείται το τεχνούργημα·
  • Commit — δέσμευση κατακερματισμού, εάν το τεχνούργημα δημιουργείται για δέσμευση αναθεώρησης·
  • συμφραζόμενα.

Περιγραφή προτύπου τεχνουργήματος

{{- define "doc_artifact" -}}
{{- $Root := index . "Root" -}}
artifact: doc-{{ .Channel }}
from: jekyll/builder:3
mount:
- from: build_dir
  to: /usr/local/bundle
ansible:
  install:
  - shell: |
      export PATH=/usr/jekyll/bin/:$PATH
  - name: "Install Dependencies"
    shell: bundle install
    args:
      executable: /bin/bash
      chdir: /app/docs
  beforeSetup:
{{- if .Commit }}
  - shell: echo "Review SHA - {{ .Commit }}."
{{- end }}
{{- if eq .Channel "root" }}
  - name: "releases.yml HASH: {{ $Root.Files.Get "releases.yml" | sha256sum }}"
    copy:
      content: |
{{ $Root.Files.Get "releases.yml" | indent 8 }}
      dest:  /app/docs/_data/releases.yml
{{- else }}
  - file:
      path: /app/docs/_data/releases.yml
      state: touch
{{- end }}
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/
    - /app/ru_site/
  - file:
      dest: /app/docs/pages_ru/cli
      state: link
      src: /app/docs/pages/cli
  - shell: |
      echo -e "werfVersion: {{ .Version }}nwerfChannel: {{ .Channel }}" > /tmp/_config_additional.yml
      export PATH=/usr/jekyll/bin/:$PATH
{{- if and (ne .Version "review") (ne .Channel "root") }}
{{- $_ := set . "BaseURL" ( printf "v%s" .Channel ) }}
{{- else if ne .Channel "root" }}
{{- $_ := set . "BaseURL" .Channel }}
{{- end }}
      jekyll build -s /app/docs  -d /app/_main_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/tmp/_config_additional.yml
      jekyll build -s /app/docs  -d /app/_ru_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/app/docs/_config_ru.yml,/tmp/_config_additional.yml
    args:
      executable: /bin/bash
      chdir: /app/docs
git:
- url: https://github.com/flant/werf.git
  to: /app/
  owner: jekyll
  group: jekyll
{{- if .Commit }}
  commit: {{ .Commit }}
{{- else }}
  tag: {{ .Version }}
{{- end }}
  stageDependencies:
    install: ['docs/Gemfile','docs/Gemfile.lock']
    beforeSetup: '**/*'
  includePaths: 'docs'
  excludePaths: '**/*.sh'
{{- end }}

Το όνομα του αντικειμένου πρέπει να είναι μοναδικό. Μπορούμε να το πετύχουμε αυτό, για παράδειγμα, προσθέτοντας το όνομα του καναλιού (την τιμή της μεταβλητής .Channel) ως επίθημα στο όνομα του αντικειμένου: artifact: doc-{{ .Channel }}. Αλλά πρέπει να καταλάβετε ότι κατά την εισαγωγή από αντικείμενα, θα πρέπει να αναφερθείτε στα ίδια ονόματα.

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

Μπορεί επίσης να έχετε παρατηρήσει τη χρήση του αρχείου releases.yml είναι ένα αρχείο YAML με δεδομένα έκδοσης που ζητούνται από Github.com (ένα τεχνούργημα που λαμβάνεται κατά την εκτέλεση ενός αγωγού). Χρειάζεται κατά τη σύνταξη του ιστότοπου, αλλά στο πλαίσιο του άρθρου μας ενδιαφέρει γιατί εξαρτάται από την κατάστασή του επανασυναρμολόγηση μόνο ενός αντικειμένου — ένα τεχνούργημα της βασικής έκδοσης του ιστότοπου (δεν χρειάζεται σε άλλα αντικείμενα).

Αυτό υλοποιείται χρησιμοποιώντας τη δήλωση υπό όρους if Πηγαίνετε πρότυπα και σχέδια {{ $Root.Files.Get "releases.yml" | sha256sum }} στη σκηνή στάδια. Λειτουργεί ως εξής: όταν δημιουργείτε ένα τεχνούργημα για την έκδοση root (μεταβλητή .Channel είναι ίσο με root) κατακερματισμός αρχείου releases.yml επηρεάζει την υπογραφή ολόκληρου του σταδίου, καθώς αποτελεί μέρος του ονόματος της εργασίας Ansible (παράμετρος name). Έτσι, κατά την αλλαγή περιεχόμενο αρχείο releases.yml το αντίστοιχο τεχνούργημα θα επανασυναρμολογηθεί.

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

Για να χρησιμοποιήσουμε το πρότυπο artifact για να δημιουργήσουμε μια περιγραφή του τεχνουργήματος των μεταφερόμενων εκδόσεων καναλιών και εκδόσεων, οργανώνουμε έναν βρόχο στη μεταβλητή .WerfVersions в werf.yaml:

{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }}
---
{{ end -}}

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

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

{{ dict "Version" .WerfRootVersion "Channel" "root" "Root" $Root  | include "doc_artifact" }}
---
{{- if .WerfReviewCommit }}
{{ dict "Version" "review" "Channel" "review" "Commit" .WerfReviewCommit "Root" $Root  | include "doc_artifact" }}
{{- end }}

Λάβετε υπόψη ότι το τεχνούργημα για την δέσμευση αναθεώρησης θα δημιουργηθεί μόνο εάν έχει οριστεί η μεταβλητή .WerfReviewCommit.

Τα αντικείμενα είναι έτοιμα - ήρθε η ώρα να ξεκινήσετε την εισαγωγή!

Η τελική εικόνα, σχεδιασμένη για εκτέλεση στο Kubernetes, είναι ένα κανονικό NGINX με ένα αρχείο διαμόρφωσης διακομιστή που έχει προστεθεί nginx.conf και στατική από τεχνουργήματα. Εκτός από το τεχνούργημα της ριζικής έκδοσης του ιστότοπου, πρέπει να επαναλάβουμε τον βρόχο στη μεταβλητή .WerfVersions για εισαγωγή τεχνουργημάτων των εκδόσεων καναλιού και έκδοσης + ακολουθήστε τον κανόνα ονομασίας τεχνουργημάτων που υιοθετήσαμε νωρίτερα. Εφόσον κάθε τεχνούργημα αποθηκεύει εκδόσεις του ιστότοπου για δύο γλώσσες, τις εισάγουμε στις θέσεις που παρέχονται από τη διαμόρφωση.

Περιγραφή της τελικής εικόνας werf-doc

image: werf-doc
from: nginx:stable-alpine
ansible:
  setup:
  - name: "Setup /etc/nginx/nginx.conf"
    copy:
      content: |
{{ .Files.Get ".werf/nginx.conf" | indent 8 }}
      dest: /etc/nginx/nginx.conf
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/assets
    - /app/ru_site/assets
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_main_site
  to: /app/main_site/v{{ $Channel }}
  before: setup
{{ end -}}
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_ru_site
  to: /app/ru_site/v{{ $Channel }}
  before: setup
{{ end -}}

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

image: werf-dev
...
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{- if .WerfReviewCommit  }}
- artifact: doc-review
  add: /app/_main_site
  to: /app/main_site/review
  before: setup
- artifact: doc-review
  add: /app/_ru_site
  to: /app/ru_site/review
  before: setup
{{- end }}

Όπως σημειώθηκε παραπάνω, το τεχνούργημα για την δέσμευση αναθεώρησης θα δημιουργηθεί μόνο όταν εκτελεστεί η μεταβλητή περιβάλλοντος που έχει εκτελεστεί REVIEW_SHA. Θα ήταν δυνατό να μην δημιουργηθεί καθόλου η εικόνα werf-dev εάν δεν υπάρχει μεταβλητή περιβάλλοντος REVIEW_SHA, αλλά για να καθαρισμός βάσει πολιτικών Οι εικόνες Docker στο werf δούλεψαν για την εικόνα werf-dev, θα την αφήσουμε να κατασκευαστεί μόνο με το τεχνούργημα της έκδοσης root (είναι ήδη κατασκευασμένο ούτως ή άλλως), για να απλοποιήσουμε τη δομή του αγωγού.

Η συναρμολόγηση είναι έτοιμη! Ας προχωρήσουμε στο CI/CD και στις σημαντικές αποχρώσεις.

Pipeline στο GitLab CI και χαρακτηριστικά δυναμικής κατασκευής

Κατά την εκτέλεση του build πρέπει να ορίσουμε τις μεταβλητές περιβάλλοντος που χρησιμοποιούνται werf.yaml. Αυτό δεν ισχύει για τη μεταβλητή REVIEW_SHA, την οποία θα ορίσουμε όταν καλούμε τη διοχέτευση από το άγκιστρο GitHub.

Θα δημιουργήσουμε τα απαραίτητα εξωτερικά δεδομένα σε ένα σενάριο Bash generate_artifacts, το οποίο θα δημιουργήσει δύο τεχνουργήματα αγωγών GitLab:

  • αρχείου releases.yml με δεδομένα έκδοσης,
  • αρχείου common_envs.sh, που περιέχει τις μεταβλητές περιβάλλοντος προς εξαγωγή.

Περιεχόμενα αρχείου generate_artifacts θα βρείτε στο δικό μας αποθετήρια με παραδείγματα. Η ίδια η λήψη των δεδομένων δεν είναι το θέμα του άρθρου, αλλά το αρχείο common_envs.sh είναι σημαντικό για εμάς, γιατί η δουλειά του werf εξαρτάται από αυτό. Ένα παράδειγμα του περιεχομένου του:

export RELEASES='1.0%v1.0.6-4'
export CHANNELS='1.0-alpha%v1.0.7-1 1.0-beta%v1.0.7-1 1.0-ea%v1.0.6-4 1.0-stable%v1.0.6-4 1.0-rock-solid%v1.0.6-4'
export ROOT_VERSION='v1.0.6-4'

Μπορείτε να χρησιμοποιήσετε την έξοδο μιας τέτοιας δέσμης ενεργειών, για παράδειγμα, χρησιμοποιώντας τη συνάρτηση Bash source.

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

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

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

Εμείς θα λήψη και καταγραφή εξωτερικών δεδομένων στο πρώτο στάδιο του αγωγού στο GitLab (Προκατασκευή) και μεταδώστε τα περαιτέρω στη φόρμα Artifact GitLab CI. Αυτό θα σας επιτρέψει να εκτελέσετε και να επανεκκινήσετε εργασίες διοχέτευσης (κατασκευή, ανάπτυξη, καθαρισμός) με την ίδια διαμόρφωση στο werf.yaml.

Περιεχόμενα της σκηνής Προκατασκευή αρχείο .gitlab-ci.yml:

Prebuild:
  stage: prebuild
  script:
    - bash ./generate_artifacts 1> common_envs.sh
    - cat ./common_envs.sh
  artifacts:
    paths:
      - releases.yml
      - common_envs.sh
    expire_in: 2 week

Έχοντας καταγράψει τα εξωτερικά δεδομένα στο τεχνούργημα, μπορείτε να δημιουργήσετε και να αναπτύξετε χρησιμοποιώντας τα τυπικά στάδια διοχέτευσης GitLab CI: Build και Deploy. Ξεκινάμε τον ίδιο τον αγωγό χρησιμοποιώντας άγκιστρα από το αποθετήριο werf GitHub (δηλαδή, όταν υπάρχουν αλλαγές στο αποθετήριο GitHub). Τα δεδομένα για αυτά βρίσκονται στις ιδιότητες του έργου GitLab στην ενότητα CI/CD Settings -> Pipeline triggersκαι, στη συνέχεια, δημιουργήστε το αντίστοιχο Webhook στο GitHub (Ρυθμίσεις -> Webhooks).

Το στάδιο κατασκευής θα μοιάζει με αυτό:

Build:
  stage: build
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf build-and-publish --stages-storage :local
  except:
    refs:
      - schedules
  dependencies:
    - Prebuild

Το GitLab θα προσθέσει δύο τεχνουργήματα από το στάδιο στο στάδιο κατασκευής Προκατασκευή, επομένως εξάγουμε μεταβλητές με έτοιμα δεδομένα εισόδου χρησιμοποιώντας την κατασκευή source common_envs.sh. Ξεκινάμε το στάδιο της κατασκευής σε όλες τις περιπτώσεις, εκτός από την εκκίνηση του αγωγού σύμφωνα με χρονοδιάγραμμα. Σύμφωνα με το χρονοδιάγραμμα, θα τρέξουμε έναν αγωγό για καθαρισμό - σε αυτή την περίπτωση δεν χρειάζεται να γίνει συναρμολόγηση.

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

.base_deploy: &base_deploy
  stage: deploy
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf deploy --stages-storage :local
  dependencies:
    - Prebuild
  except:
    refs:
      - schedules

Deploy to Production:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: prod
  environment:
    name: production
    url: werf.io
  only:
    refs:
      - master
  except:
    variables:
      - $REVIEW_SHA
    refs:
      - schedules

Deploy to Test:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: dev
  environment:
    name: test
    url: werf.test.flant.com
  except:
    refs:
      - schedules
  only:
    variables:
      - $REVIEW_SHA

Οι εργασίες ουσιαστικά διαφέρουν μόνο στον καθορισμό του περιβάλλοντος συμπλέγματος στο οποίο η werf θα πρέπει να εκτελέσει την ανάπτυξη (WERF_KUBE_CONTEXT), και ορίζοντας τις μεταβλητές περιβάλλοντος βρόχου (environment.name и environment.url), τα οποία στη συνέχεια χρησιμοποιούνται σε πρότυπα γραφημάτων Helm. Δεν θα παρέχουμε τα περιεχόμενα των προτύπων, επειδή... Δεν υπάρχει τίποτα ενδιαφέρον εκεί για το εν λόγω θέμα, αλλά μπορείτε να το βρείτε αποθετήρια για το άρθρο.

Τελική αφή

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

Για την υλοποίηση θα χρειαστείτε:

  • Προσθέστε ένα βήμα καθαρισμού σε .gitlab-ci.yml;
  • Προσθέστε την περιοδική εκτέλεση μιας εργασίας καθαρισμού.
  • Ρυθμίστε μια μεταβλητή περιβάλλοντος με ένα διακριτικό πρόσβασης εγγραφής.

Προσθήκη σταδίου καθαρισμού σε .gitlab-ci.yml:

Cleanup:
  stage: cleanup
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO}
    - werf cleanup --stages-storage :local
  only:
    refs:
      - schedules

Έχουμε ήδη δει σχεδόν όλα αυτά ακριβώς από πάνω - μόνο για να τα καθαρίσετε, πρέπει πρώτα να συνδεθείτε στο Μητρώο Docker με ένα διακριτικό που έχει τα δικαιώματα διαγραφής εικόνων στο Μητρώο Docker (το διακριτικό εργασιών GitLab CI που εκδίδεται αυτόματα δεν έχει τέτοια δικαιώματα). Το διακριτικό πρέπει να δημιουργηθεί στο GitLab εκ των προτέρων και η τιμή του πρέπει να καθοριστεί στη μεταβλητή περιβάλλοντος WERF_IMAGES_CLEANUP_PASSWORD σχέδιο (Ρυθμίσεις CI/CD -> Μεταβλητές).

Η προσθήκη μιας εργασίας καθαρισμού με το απαιτούμενο χρονοδιάγραμμα γίνεται στο CI/CD ->
Δρομολόγια
.

Αυτό είναι όλο: ένα έργο στο Μητρώο Docker δεν θα αναπτύσσεται πλέον συνεχώς από αχρησιμοποίητες εικόνες.

Στο τέλος του πρακτικού μέρους, επιτρέψτε μου να σας υπενθυμίσω ότι πλήρεις καταχωρίσεις από το άρθρο είναι διαθέσιμες στο Git:

Αποτέλεσμα

  1. Λάβαμε μια λογική δομή συναρμολόγησης: ένα τεχνούργημα ανά έκδοση.
  2. Η συναρμολόγηση είναι καθολική και δεν απαιτεί μη αυτόματες αλλαγές όταν κυκλοφορούν νέες εκδόσεις του werf: η τεκμηρίωση στον ιστότοπο ενημερώνεται αυτόματα.
  3. Δύο εικόνες συναρμολογούνται για διαφορετικά περιγράμματα.
  4. Λειτουργεί γρήγορα, γιατί Η προσωρινή αποθήκευση χρησιμοποιείται όσο το δυνατόν περισσότερο - όταν κυκλοφορήσει μια νέα έκδοση του werf ή ένα άγκιστρο GitHub καλείται για δέσμευση αναθεώρησης, μόνο το αντίστοιχο τεχνούργημα με την αλλαγμένη έκδοση ξαναχτίζεται.
  5. Δεν χρειάζεται να σκεφτείτε τη διαγραφή αχρησιμοποίητων εικόνων: ο καθαρισμός σύμφωνα με τις πολιτικές της werf θα διατηρήσει σε τάξη το Μητρώο Docker.

Ευρήματα

  • Η χρήση του werf επιτρέπει στο συγκρότημα να λειτουργεί γρήγορα λόγω της προσωρινής αποθήκευσης τόσο του ίδιου του συγκροτήματος όσο και της προσωρινής αποθήκευσης κατά την εργασία με εξωτερικά αποθετήρια.
  • Η εργασία με εξωτερικά αποθετήρια Git εξαλείφει την ανάγκη κλωνοποίησης ολόκληρου του αποθετηρίου κάθε φορά ή επανεφεύρεσης του τροχού με δύσκολη λογική βελτιστοποίησης. Το werf χρησιμοποιεί μια κρυφή μνήμη και κάνει την κλωνοποίηση μόνο μία φορά και στη συνέχεια χρησιμοποιεί fetch και μόνο όταν είναι απαραίτητο.
  • Δυνατότητα χρήσης προτύπων Go στο αρχείο διαμόρφωσης build werf.yaml σας επιτρέπει να περιγράψετε ένα συγκρότημα του οποίου το αποτέλεσμα εξαρτάται από εξωτερικά δεδομένα.
  • Η χρήση του mount in werf επιταχύνει σημαντικά τη συλλογή αντικειμένων - λόγω της κρυφής μνήμης, η οποία είναι κοινή σε όλους τους αγωγούς.
  • Το werf διευκολύνει τη διαμόρφωση του καθαρισμού, κάτι που είναι ιδιαίτερα σημαντικό κατά τη δυναμική κατασκευή.

PS

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

Πηγή: www.habr.com

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