Ștergerea unei feature branch învechite în clusterul Kubernetes

Ștergerea unei feature branch învechite în clusterul Kubernetes

Bună! Ramură de caracteristici (cunoscută și sub numele de preview de implementare, aplicație de revizuire) — este atunci când se implementează nu doar ramura master, ci și fiecare pull request pe un URL unic. Poți verifica dacă codul funcționează în mediu de producție și poți arăta funcționalitatea altor programatori sau product manageri. Atâta timp cât lucrezi într-un pull request, fiecare nou commit anulează implementarea curentă pentru codul vechi, iar o nouă implementare pentru codul nou este efectuată. Probleme pot apărea atunci când ai fuzionat pull requestul în ramura master. Ramura de caracteristici nu îți mai este necesară, dar resursele Kubernetes sunt încă în cluster.

Încă despre ramurile de caracteristici

Una dintre abordările pentru a crea ramuri de caracteristici în Kubernetes — este utilizarea spațiilor de nume. Pe scurt, configurațiile de producție arată astfel:

kind: Namespace
apiVersion: v1
metadata:
  name: habr-back-end
...

kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: habr-back-end
spec:
  replicas: 3
...

Pentru ramura de caracteristici se creează un spațiu de nume cu identificatorul său (de exemplu, numărul pull request-ului) și cu un prefix/sufix (de exemplu, -pr-):

kind: Namespace
apiVersion: v1
metadata:
  name: habr-back-end-pr-17
...

kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: habr-back-end-pr-17
spec:
  replicas: 1
...

În general, am scris Kubernetes Operator (o aplicație care are acces la resursele cluster-ului), link către proiect pe Github. Aceasta șterge spațiile de nume care sunt legate de ramurile de caracteristici vechi. În Kubernetes, dacă ștergi un spațiu de nume, celelalte resurse din acest spațiu de nume sunt de asemenea șterse automat.

$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE            ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7h

Despre cum să implementezi ramurile de caracteristici în cluster, poți citi aici și aici.

Motivația

Hai să ne uităm la un ciclu de viață tipic al unui pull request cu integrare continuă (continuous integration):

  1. Trimitem un nou commit în ramură.
  2. La construcție, se rulează lintere și/sau teste.
  3. Configurările Kubernetes pentru pull request sunt generate din mers (de exemplu, numărul său este inserat în șablonul pregătit).
  4. Cu ajutorul kubectl apply, configurațiile ajung în cluster (implementare).
  5. Pull request-ul este fuzionat în ramura master.

Atâta timp cât lucrezi într-un pull request, fiecare nou commit anulează implementarea curentă pentru codul vechi, iar o nouă implementare pentru codul nou este efectuată. Dar atunci când pull requestul este fuzionat în ramura master, va fi construită doar ramura master. În cele din urmă, obținem că am uitat despre pull request, dar resursele sale Kubernetes sunt încă în cluster.

Cum să folosești

Instalează proiectul cu comanda de mai jos:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml

Creează un fișier cu următorul conținut și instalează-l prin kubectl apply -f:

apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
  name: stale-feature-branch
spec:
  namespaceSubstring: -pr-
  afterDaysWithoutDeploy: 3

Parametru namespaceSubstring este necesar pentru a filtra namespace-urile pentru pull request-uri din alte namespace-uri. De exemplu, dacă în cluster există următoarele namespace-uri: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, atunci candidații pentru eliminare vor fi habr-back-end-pr-17, habr-back-end-pr-33.

Parametru afterDaysWithoutDeploy este necesar pentru a elimina namespace-urile vechi. De exemplu, dacă un namespace a fost creat 3 zile 1 oră în urmă, iar în parametru este specificat 3 zile, acest namespace va fi eliminat. Funcționează și în sens invers, dacă un namespace a fost creat 2 zile 23 ore în urmă, iar în parametru este specificat 3 zile, acest namespace nu va fi eliminat.

Există și un alt parametru, acesta răspunde pentru cât de des să scaneze toate namespace-urile și să verifice zilele fără deploy — checkEveryMinutes. Implicit, este egal cu 30 minute.

Cum funcționează

În practică, este necesar:

  1. Docker pentru a funcționa într-un mediu izolat.
  2. Minikube va ridica un cluster Kubernetes local.
  3. kubectl — interfața de linie de comandă pentru gestionarea cluster-ului.

Ridicăm cluster-ul Kubernetes local:

$ minikube start --vm-driver=docker
minikube v1.11.0 pe Darwin 10.15.5
Folosind driverul docker bazat pe profilul existent.
Pornind nodul control minikube în clusterul minikube.

Specificați kubectl folosiți cluster-ul local implicit:

$ kubectl config use-context minikube
Comutat pe contextul "minikube".

Descărcăm configurațiile pentru mediu de producție:

$ curl https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml > stale-feature-branch-production-configs.yml

Deoarece configurațiile de producție sunt setate să verifice namespace-urile vechi, iar în clusterul nostru nou ridicat nu sunt, vom schimba variabila de mediu IS_DEBUG pe true. Cu această valoare, parametrul afterDaysWithoutDeploy nu este luat în considerare și namespace-urile nu sunt verificate pentru zile fără deploy, doar pentru conținutul subșirului (-pr-).

Dacă sunteți pe Linux:

$ sed -i 's|false|true|g' stale-feature-branch-production-configs.yml

Dacă sunteți pe macOS:

$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.yml

Instalăm proiectul:

$ kubectl apply -f stale-feature-branch-production-configs.yml

Verificăm că resursa a apărut în cluster StaleFeatureBranch:

$ kubectl api-resources | grep stalefeaturebranches
NAME                 ... APIGROUP                             ... KIND
stalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranch

Verificăm că operatorul a apărut în cluster:

$ kubectl get pods --namespace stale-feature-branch-operator
NAME                                           ... STATUS  ... AGE
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38s

Dacă ne uităm în jurnalele sale, este gata să proceseze resursele StaleFeatureBranch:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Versiunea Operatorului: 0.0.1"}
...
... "msg":"Pornind EventSource", ... , "source":"kind source: \/, Kind="}
... "msg":"Pornind Controller", ...}
... "msg":"Pornind lucrătorii", ..., "worker count":1}

Instalăm fixture-urile fixtures (configurații gata făcute pentru modelarea resurselor clusterului) pentru resursă StaleFeatureBranch:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/stale-feature-branch.yml

Configurările specifică că trebuie să se caute namespace-uri cu substring-ul -pr- o dată la 1 minut.:

apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
  name: stale-feature-branch
spec:
  namespaceSubstring: -pr-
  afterDaysWithoutDeploy: 1 
  checkEveryMinutes: 1

Operatorul a reacționat și este pregătit să verifice namespace-urile:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch is being processing.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}

Instalăm fixtures, conținând două namespace-uri (project-pr-1, project-pr-2) și ale lor deployments, servicii, ingress, și așa mai departe:

$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/first-feature-branch.yml -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/second-feature-branch.yml
...
namespace/project-pr-1 created
deployment.apps/project-pr-1 created
service/project-pr-1 created
horizontalpodautoscaler.autoscaling/project-pr-1 created
secret/project-pr-1 created
configmap/project-pr-1 created
ingress.extensions/project-pr-1 created
namespace/project-pr-2 created
deployment.apps/project-pr-2 created
service/project-pr-2 created
horizontalpodautoscaler.autoscaling/project-pr-2 created
secret/project-pr-2 created
configmap/project-pr-2 created
ingress.extensions/project-pr-2 created

Verificăm că toate resursele de mai sus au fost create cu succes:

$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
NAME                              ... READY ... STATUS  ... AGE
pod/project-pr-1-848d5fdff6-rpmzw ... 1/1   ... Running ... 67s

NAME                         ... READY ... AVAILABLE ... AGE
deployment.apps/project-pr-1 ... 1/1   ... 1         ... 67s
...

Deoarece am activat debug, namespace-urile project-pr-1 și project-pr-2, prin urmare și toate celelalte resurse, vor trebui să fie imediat șterse fără a lua în considerare parametrul afterDaysWithoutDeploy. În log-urile operatorului se vede acest lucru:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-1"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-1"}
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-2"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-2"}

Dacă verificăm prezența resurselor, ele vor fi în starea Terminating (proces de ștergere) sau deja șterse (ieșirea comenzii este goală).

$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...

Puteți repeta procesul de creare fixtures de mai multe ori și să vă asigurați că acestea vor fi șterse în decurs de un minut.

Alternative

Ce se poate face în locul operatorului care funcționează într-un cluster? Există câteva abordări, toate imperfecte (iar dezavantajele lor sunt subiective), iar fiecare decide ce se potrivește cel mai bine pentru proiectul său specific:

  1. A elimina ramura feature în timpul construcției ramurii master de integrare continuă.

    • Pentru aceasta trebuie să știi ce pull request se referă la commit-ul care este construit. Deoarece namespace-ul ramurii feature conține identificatorul pull request-ului - numărul sau numele ramurii, identificatorul va trebui să fie specificat întotdeauna în commit.
    • Construcțiile ramurilor master eșuează. De exemplu, aveți următorii pași: descărcați proiectul, rulați testele, construiți proiectul, faceți release, trimiteți notificările, curățați ramura feature a ultimului pull request. Dacă construcția eșuează la trimiterea notificării, va trebui să ștergi toate resursele din cluster manual.
    • Fără un context adecvat, ștergerea ramurii feature în construcția master nu este evidentă.

  2. Folosirea webhook-urilor (exemplu).

    • Este posibil ca acesta să nu fie abordarea ta. De exemplu, în Jenkins, doar un tip de pipeline suportă posibilitatea de a-și salva configurațiile în codul sursă. Când folosești webhook-uri, trebuie să scrii propriul script pentru procesarea lor. Acest script va trebui să fie plasat în interfața Jenkins-ului, ceea ce este greu de întreținut.

  3. Scrieți Cronjob și adaugă clusterul Kubernetes.

    • Cheltuiala de timp pentru scrierea și suportul acestuia.
    • Operatorul funcționează deja într-un stil similar, fiind documentat și întreținut.

Mulțumim pentru atenția acordată articolului. Link către proiectul de pe Github.

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