
Ciao! Branch di funzionalità (alias anteprima del deploy, app di review) — è quando non viene deployato solo il ramo master, ma anche ogni pull request su un URL unico. Puoi verificare se il codice funziona nell'ambiente di produzione, la funzionalità può essere mostrata ad altri programmatori o product manager. Mentre lavori nella pull request, ogni nuovo commit rimuove l'attuale deploy del vecchio codice e viene eseguito un nuovo deploy per il nuovo codice. Possono sorgere domande quando hai unito la pull request nel ramo master. La branch di funzionalità non ti serve più, ma le risorse di Kubernetes sono ancora nel cluster.
Ancora sulle branch di funzionalità
Uno dei modi per creare branch di funzionalità in Kubernetes è utilizzare i namespace. In breve, la configurazione di produzione appare così:
kind: Namespace
apiVersion: v1
metadata:
name: habr-back-end
...
kind: Deployment
apiVersion: apps/v1
metadata:
namespace: habr-back-end
spec:
replicas: 3
...Per la branch di funzionalità viene creato un namespace con il suo identificatore (ad esempio, il numero della pull request) e qualche prefisso/suffisso (per esempio, -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
...In generale, ho scritto Kubernetes Operator (applicazione che ha accesso alle risorse del cluster), . Rimuove i namespace che appartengono a vecchi feature branch. In Kubernetes, se si elimina un namespace, anche le altre risorse in quel namespace vengono eliminate automaticamente.
$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7hPer informazioni su come implementare i feature branch nel cluster, puoi leggere e .
Motivazione
Diamo un'occhiata al ciclo di vita tipico di un pull request con integrazione continua (integrazione continua):
- Inviamo un nuovo commit nel branch.
- Durante la build, vengono eseguiti linters e/o test.
- Le configurazioni per il pull request di Kubernetes vengono generate al volo (ad esempio, il numero viene inserito in un modello predefinito).
- Con kubectl apply, le configurazioni vengono inviate nel cluster (deploy).
- Il pull request viene unito nel branch master.
Mentre lavori su un pull request, ogni nuovo commit fa sì che il deploy attuale per il vecchio codice venga eliminato e venga creato un nuovo deploy per il nuovo codice. Ma quando il pull request viene unito nel branch master, verrà costruito solo il branch master. Di conseguenza, il pull request viene dimenticato, mentre le sue risorse Kubernetes sono ancora nel cluster.
Come utilizzare
Installa il progetto con il comando qui sotto:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.ymlCrea un file con il seguente contenuto e installalo tramite kubectl apply -f:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 3Caratteristica namespaceSubstring necessario per filtrare i namespace per le pull request da altri namespace. Ad esempio, se nel cluster ci sono i seguenti namespace: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, allora i candidati per la rimozione saranno habr-back-end-pr-17, habr-back-end-pr-33.
Caratteristica afterDaysWithoutDeploy necessario per rimuovere i vecchi namespace. Ad esempio, se un namespace è stato creato 3 giorni 1 ora fa, e nel parametro è specificato 3 giorni, questo namespace sarà rimosso. Funziona anche al contrario, se un namespace è stato creato 2 giorni 23 ore fa, e nel parametro è specificato 3 giorni, questo namespace non sarà rimosso.
C'è un altro parametro che determina con quale frequenza scansionare tutti i namespace e controllare i giorni senza deploy — checkEveryMinutes. Per impostazione predefinita è pari a 30 minuti.
Come funziona
In pratica, sarà necessario:
- per operare in un ambiente isolato.
- solleverà un cluster Kubernetes localmente.
- — interfaccia a riga di comando per gestire il cluster.
Solleviamo un cluster Kubernetes localmente:
$ minikube start --vm-driver=docker
minikube v1.11.0 on Darwin 10.15.5
Using the docker driver based on existing profile.
Starting control plane node minikube in cluster minikube.Indichiamo kubectl utilizzare il cluster locale per impostazione predefinita:
$ kubectl config use-context minikube
Cambiato a contesto "minikube".Scarichiamo le configurazioni per l'ambiente di produzione:
$ curl https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml > stale-feature-branch-production-configs.ymlPoiché le configurazioni di produzione sono impostate per controllare i vecchi namespace, e nel nostro nuovo cluster non ci sono, sostituiremo la variabile d'ambiente IS_DEBUG con true. Con questo valore, il parametro afterDaysWithoutDeploy non viene considerato e i namespace non vengono controllati per giorni senza deployment, ma solo per la presenza di una sottostringa (-pr-).
Se ti trovi su Linux:
$ sed -i 's|false|true|g' stale-feature-branch-production-configs.ymlSe ti trovi su macOS:
$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.ymlInstalliamo il progetto:
$ kubectl apply -f stale-feature-branch-production-configs.ymlVerifichiamo che nel cluster sia apparso il risorso StaleFeatureBranch:
$ kubectl api-resources | grep stalefeaturebranches
NOME ... APIGROUP ... TIPO
stalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranchVerifichiamo che nel cluster sia apparso l'operatore:
$ kubectl get pods --namespace stale-feature-branch-operator
NOME ... STATO ... ETÀ
stale-feature-branch-operator-6bfbfd4df8-m7sch ... In esecuzione ... 38sSe guardiamo nei suoi log, è pronto a gestire le risorse StaleFeatureBranch:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Versione dell'operatore: 0.0.1"}
...
... "msg":"Inizio EventSource", ... , "source":"kind source: /, Kind="}
... "msg":"Inizio Controller", ...}
... "msg":"Inizio lavoratori", ..., "worker count":1}Installando i fixtures pronti fixtures (configurazioni pronte per simulare le risorse del cluster) per la risorsa StaleFeatureBranch:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/stale-feature-branch.ymlNelle configurazioni è specificato di cercare i namespace con la sottostringa -pr- ogni 1 minuto.:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 1
checkEveryMinutes: 1L'operatore ha reagito ed è pronto a controllare i namespace:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Ramo funzionale scaduto in elaborazione.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}Installiamo fixtures, contenenti due namespace (project-pr-1, project-pr-2) e i loro deployments, servizi, ingress, e così via:
$ 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/progetto-pr-1 creato
deployment.apps/progetto-pr-1 creato
service/progetto-pr-1 creato
horizontalpodautoscaler.autoscaling/progetto-pr-1 creato
secret/progetto-pr-1 creato
configmap/progetto-pr-1 creato
ingress.extensions/progetto-pr-1 creato
namespace/progetto-pr-2 creato
deployment.apps/progetto-pr-2 creato
service/progetto-pr-2 creato
horizontalpodautoscaler.autoscaling/progetto-pr-2 creato
secret/progetto-pr-2 creato
configmap/progetto-pr-2 creato
ingress.extensions/progetto-pr-2 creatoVerifichiamo che tutte le risorse sopra siano state create con successo:
$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n progetto-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n progetto-pr-2
...
NOME ... PRONTO ... STATO ... ETÀ
pod/progetto-pr-1-848d5fdff6-rpmzw ... 1/1 ... In esecuzione ... 67s
NOME ... PRONTO ... DISPONIBILE ... ETÀ
deployment.apps/progetto-pr-1 ... 1/1 ... 1 ... 67s
...Poiché abbiamo attivato debug, i namespaces project-pr-1 e project-pr-2, tutte le altre risorse devono essere eliminate immediatamente, senza considerare il parametro afterDaysWithoutDeploy. Questo è visibile nei log dell'operatore:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Il namespace dovrebbe essere eliminato poiché la modalità debug è attivata.","namespaceName":"project-pr-1"}
... "msg":"Il namespace è in fase di elaborazione.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Il namespace è stato eliminato.","namespaceName":"project-pr-1"}
... "msg":"Il namespace dovrebbe essere eliminato poiché la modalità debug è attivata.","namespaceName":"project-pr-2"}
... "msg":"Il namespace è in fase di elaborazione.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Il namespace è stato eliminato.","namespaceName":"project-pr-2"}Se controlli la disponibilità delle risorse, saranno in stato Terminating (in fase di eliminazione) o già eliminate (l'output del comando è vuoto).
$ 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
...Puoi ripetere il processo di creazione fixtures più volte e verificare che vengano eliminati entro un minuto.
Alternative
Cosa si può fare invece di un operatore che lavora nel cluster? Ci sono diversi approcci, tutti non ideali (e i loro svantaggi sono soggettivi), e ognuno decide cosa si adatta meglio al progetto specifico:
Eliminare il branch di funzionalità durante la build dell'integrazione continua del branch master.
- Per farlo, è necessario sapere quale pull request è associata al commit che viene buildato. Poiché il namespace del feature branch contiene l'identificativo del pull request - il suo numero o il nome del branch, sarà sempre necessario specificare l'identificatore nel commit.
- I build dei branch master falliscono. Ad esempio, avete i seguenti passaggi: scaricare il progetto, eseguire i test, compilare il progetto, fare il rilascio, inviare notifiche, pulire il feature branch dell'ultimo pull request. Se il build fallisce durante l'invio delle notifiche, dovrete eliminare manualmente tutte le risorse nel cluster.
- Senza il giusto contesto, eliminare il feature branch in un build master non è ovvio.
Utilizzo di webhook ().
- Forse non è il vostro approccio. Ad esempio, in , solo un tipo di pipeline supporta la possibilità di mantenere le sue configurazioni nel codice sorgente. Utilizzando i webhook, è necessario scrivere un proprio script per gestirli. Questo script dovrà essere collocato nell'interfaccia di Jenkins, il che è difficile da mantenere.
Scrivere e aggiungere al cluster Kubernetes.
- Il costo in termini di tempo per scrivere e mantenere.
- L'operatore già lavora in uno stile simile, è documentato e supportato.
Grazie per l'attenzione all'articolo. .
Fonte: habr.com
