Implementarea noastră de Continuous Deployment pe platforma clientului

La True Engineering, am configurat un proces de livrare continuă a actualizărilor pe serverele clienților și dorim să împărtășim această experiență.

La început, am dezvoltat un sistem online pentru client și l-am desfășurat în propriul nostru cluster Kubernetes. Acum soluția noastră de înaltă capacitate a fost transferată pe platforma clientului, pentru care am configurat un proces complet automatizat de Continuous Deployment. Datorită acestui lucru, am accelerat time-to-market-ul – livrarea modificărilor în mediul de producție.

În acest articol, vă vom prezenta toate etapele procesului de Continuous Deployment (CD) sau livrarea actualizărilor pe platforma clientului:

  1. cum începe acest proces,
  2. sincronizarea cu Git-repozițiul clientului,
  3. compilarea backend-ului și frontend-ului,
  4. desfășurarea automată a aplicației în mediu de testare,
  5. desfășurarea automată în Prod.

Pe parcurs, vom împărtăși detaliile configurației.

Implementarea noastră de Continuous Deployment pe platforma clientului

1. Începerea CD

Continuous Deployment începe atunci când dezvoltatorul publică modificările în ramura de livrare a Git-repoziției noastre.

Aplicația noastră funcționează pe baza unei arhitecturi de microservicii, iar toate componentele sale sunt stocate într-un singur repo. Datorită acestui lucru, toate microserviciile sunt compilate și instalate, chiar dacă unul dintre ele a fost modificat.

Am organizat activitatea printr-un singur repo din mai multe motive:

  • Conveniența dezvoltării – aplicația se dezvoltă activ, așa că se poate lucra direct cu tot codul.
  • Un pipeline CI/CD unic care garantează că aplicația, ca un sistem unitar, trece prin toate testele și este livrată în mediu prod al clientului.
  • Excludem confuzia în versiunile – nu trebuie să păstrăm o hartă a versiunilor microserviciilor și să descriem pentru fiecare microserviciu propria configurație în scripturile Helm.

2. Sincronizarea cu Git-repozițiul de cod sursă al clientului

Modificările efectuate sunt sincronizate automat cu Git-repozițiul clientului. Acolo este configurată compilarea aplicației, care se pornește după actualizarea ramurii, și desfășurarea în prod. Ambele procese au loc în mediul lor din Git-repoziție.

Nu putem lucra direct cu repository-ul clientului, deoarece avem nevoie de mediile noastre pentru dezvoltare și testare. Pentru aceste scopuri, folosim propriul nostru repository Git — acesta este sincronizat cu repository-ul lor Git. De fiecare dată când un dezvoltator publică modificările în ramura corespunzătoare a repository-ului nostru, GitLab trimite imediat aceste modificări clientului.

Implementarea noastră de Continuous Deployment pe platforma clientului

După aceea, trebuie să facem construcția. Aceasta constă din mai multe etape: construcția backend-ului și frontend-ului, testarea și livrarea în producție.

3. Construcția backend-ului și frontend-ului

Construcția backend-ului și frontend-ului este o sarcină paralelă care se desfășoară în sistemul GitLab Runner. Configurarea construcției inițiale se află în același repository.

Tutorial pentru scrierea scripturilor YAML pentru construcția în GitLab.

GitLab Runner preia codul din repository-ul necesar, construiește aplicația Java și o trimite în Docker registry. Aici construim backend-ul și frontend-ul, obținem imagini Docker pe care le stocăm în repository-ul clientului. Pentru gestionarea imaginilor Docker folosim pluginul Gradle.

Sincronizăm versiunile imaginilor noastre cu versiunea de release care va fi publicată în Docker. Pentru o funcționare fluidă, am adus câteva configurări:

1. Între mediul de testare și cel de producție, containerele nu sunt reconstruite. Am realizat parametrizări astfel încât același container să poată funcționa fără reconstrucție cu toate setările, variabilele de mediu și serviciile, atât în mediu de testare cât și în producție.

2. Pentru a actualiza aplicația prin Helm, trebuie să specificăm versiunea acesteia. Construirea backend-ului, frontend-ului și actualizarea aplicației sunt trei sarcini diferite, așadar este important să folosim aceeași versiune a aplicației peste tot. Pentru această sarcină, folosim datele din istoricul Git, deoarece avem configurația cluster-ului K8S și a aplicației într-un singur repository Git.

Primim versiunea aplicației din rezultatele executării comenzii
git describe --tags --abbrev=7.

4. Implementarea automată a tuturor modificărilor în mediu de testare (UAT)

Următoarea etapă în acest script de construcție este actualizarea automată a cluster-ului K8S. Acest lucru se întâmplă cu condiția ca întreaga aplicație să fie construită și toate artefactele să fie publicate în Docker Registry. După aceasta, se lansează actualizarea mediului de testare.

Actualizarea cluster-ului este inițiată cu ajutorul Actualizare Helm. Dacă ceva nu decurge conform planului, Helm va reveni automat și de la sine la toate modificările sale. Nu este necesară monitorizarea funcționării sale.

Furnizăm, împreună cu montajul, configurația cluster-ului K8S. Prin urmare, următorul pas este actualizarea acesteia: configMaps, deployments, services, secrets și orice alte configurații K8S pe care le-am modificat.

După aceasta, Helm inițiază actualizarea RollOut a aplicației în mediu de testare. Înainte ca aplicația să fie desfășurată în producție. Acest lucru este realizat pentru ca utilizatorii să poată verifica manual funcțiile de business pe care le-am publicat în mediu de testare.

5. Desfășurarea automată a tuturor modificărilor în Prod

Pentru a desfășura actualizarea în mediu de producție, este suficient să apăsați un buton în GitLab — iar containerele sunt imediat livrate în mediu de producție.

Același aplicație poate funcționa fără recompilare în medii diferite — testare și producție. Folosim aceleași artefacte, fără a schimba nimic în aplicație, iar parametrii sunt definiți din exterior.

Parametrizarea flexibilă a setărilor aplicației depinde de mediu în care această aplicație va fi executată. Am externalizat toate setările mediilor: totul este parametrizat prin configurația K8S și parametrii Helm. Când Helm desfășoară montajul în mediu de testare, se aplică parametrii de testare, iar în mediu de producție — parametrii de producție.

Cea mai complicată a fost parametrizarea tuturor serviciilor și variabilelor utilizate, care depind de mediu, și transformarea lor în variabile de mediu și descrieri-configurare a parametrilor de mediu pentru Helm.

În parametrii aplicației sunt folosite variabile de mediu. Valorile lor sunt definite în containere prin K8S configmap, care este templinizat folosind șabloane Go. De exemplu, definirea unei variabile de mediu pentru denumirea domeniului poate fi realizată astfel:

APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }}

.Values.global.env – în această variabilă se stochează denumirea mediului (prod, stage, UAT).
.Values.app.properties.app_external_domain – în această variabilă definim domeniul dorit în fișierul .Values.yaml

At the time of updating the application, Helm creates the configmap.yaml file from templates and fills the APP_EXTERNAL_DOMAIN value with the necessary value depending on the environment in which the update occurs. This variable is set within the container. It is accessible from the application, meaning that in each application environment, this variable will have a different value.

Recently, Spring Cloud has added support for K8S, including work with configMaps: Spring Cloud Kubernetes. While the project is actively being developed and changes significantly, we cannot use it in production yet. However, we are actively monitoring its status and using it in DEV configurations. As soon as it stabilizes, we will switch from using environment variables to it.

În concluzie

So, Continuous Deployment is set up and functioning. All updates happen with the press of a button. Delivery of changes to the production environment is automatic. Importantly, updates do not halt system operations.

Implementarea noastră de Continuous Deployment pe platforma clientului

Plans for the future: automatic database migration

We are considering an upgrade of the database and the possibility of rolling back these changes. After all, two different versions of the application are running simultaneously: the old one is operational, while the new one is being launched. The old version will only be turned off when we are sure that the new version is working. Database migration must allow operation with both versions of the application.

Therefore, we cannot simply change the column name or other data. But we can create a new column, copy data from the old column into it, and write triggers that will simultaneously copy and update data in the other column during updates. After a successful deployment of the new application version, following the post-launch support period, we will be able to remove the old column and the unnecessary trigger.

If the new version of the application is not functioning correctly, we can revert to the previous version, including the previous database version. In short, our changes will allow simultaneous operation with multiple versions of the application.

We plan to automate the database migration through a K8S job, integrating it into the CD process. We will definitely share this experience on Habr.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster