
Pozdrav! Feature branch (aka deploy preview, review app) — to je kada se ne samo master grana deploya, već i svaki pull request na jedinstvenom URL-u. Možete provjeriti radi li kod u proizvodnom okruženju, a značajku možete pokazati drugim programerima ili produktologima. Dok radite na pull requestu, svaki novi commit uklanja trenutni deploy za stari kod, a novi deploy za novi kod se isporučuje. Pitanja se mogu pojaviti kada spojite pull request u master granu. Feature branch vam više nije potrebna, ali resursi Kubernetes-a i dalje su u klasteru.
Još o feature branch-ima
Jedan od pristupa kako napraviti feature branch-eve u Kubernetes-u je korištenje namespace-a. Ukratko, proizvodne konfiguracije izgledaju ovako:
kind: Namespace
apiVersion: v1
metadata:
name: habr-back-end
...
kind: Deployment
apiVersion: apps/v1
metadata:
namespace: habr-back-end
spec:
replicas: 3
...Za feature branch se stvara namespace sa njenim identifikatorom (na primjer, broj pull request-a) i nekim prefiksom/postfiksom (na primjer, -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
...Uglavnom, napisao sam Kubernetes Operator (aplikacija koja ima pristup resursima klastera), . Ona uklanja namespace-ove koji se odnose na stare feature branch-eve. U Kubernetes-u, ako se ukloni namespace, drugi resursi unutar tog namespace-a također se automatski uklanjaju.
$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7hO tome kako implementirati feature branch-eve u klasteru, možete pročitati i .
Motivacija
Hajde da pogledamo tipični životni ciklus pull request-a s kontinuiranom integracijom (kontinuirana integracija):
- Guramo novi commit u granu.
- Na gradnji se pokreću linters i/ili testovi.
- U hodu se formiraju konfiguracije Kubernetes pull request-a (na primjer, broj se umetne u gotov šablon).
- Pomoću kubectl apply konfiguracije se šalju u klaster (deploy).
- Pull request se spaja u master granu.
Dok radite na pull requestu, svaki novi commit uklanja trenutni deploy za stari kod, a novi deploy za novi kod se isporučuje. No, kada se pull request spoji u master granu, gradit će se samo master grana. Na kraju, ispada da smo zaboravili na pull request, a njegovi Kubernetes resursi još su uvijek u klasteru.
Kako koristiti
Instalirati projekt naredbom ispod:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.ymlKreirati datoteku s sljedećim sadržajem i instalirati preko kubectl apply -f:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 3Parametar namespaceSubstring potreban za filtriranje namespace-ova za pull request-ove iz drugih namespace-ova. Na primjer, ako postoje sljedeći namespace-ovi u klasteru: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, tada će kandidati za brisanje biti habr-back-end-pr-17, habr-back-end-pr-33.
Parametar afterDaysWithoutDeploy potreban za brisanje starih namespace-ova. Na primjer, ako je namespace kreiran prije 3 dana i 1 sat , a u parametru je navedeno 3 dana, ovaj namespace će biti obrisan. Radi i u obrnutom smjeru, ako je namespace kreiran prije 2 dana i 23 sata , a u parametru je navedeno 3 dana, ovaj namespace neće biti obrisan.
Postoji još jedan parametar, koji određuje koliko često skenirati sve namespace-ove i provjeravati dane bez deploy-a — checkEveryMinutes. Po defaultu je postavljen na 30 minuta.
Kako to funkcionira
U praksi, potrebno je:
- za rad u izoliranom okruženju.
- pokrenuti Kubernetes klaster lokalno.
- — komandna linija za upravljanje klasterom.
Pokrećemo Kubernetes klaster lokalno:
$ minikube start --vm-driver=docker
minikube v1.11.0 na Darwin 10.15.5
Koristeći docker driver na osnovu postojećeg profila.
Pokrećem kontrolnu platformu minikube u klasteru minikube.Unesite kubectl koristiti lokalni klaster po defaultu:
$ kubectl config use-context minikube
Prebačeno na kontekst "minikube".Preuzimamo konfiguracije za production okruženje:
$ curl https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml > stale-feature-branch-production-configs.ymlBudući da su production konfiguracije postavljene da provjeravaju stare namespace-ove, a u našem novokreiranom klasteru ih nema, zamijenit ćemo varijablu okruženja IS_DEBUG na true. Sa ovom vrijednošću, parametar afterDaysWithoutDeploy se ne uzima u obzir i namespace-ovi se ne provjeravaju na dane bez deploy-a, samo na prisutnost podstringa (-pr-).
Ako ste na Linux:
$ sed -i 's|false|true|g' stale-feature-branch-production-configs.ymlAko ste na macOS:
$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.ymlInstaliramo projekt:
$ kubectl apply -f stale-feature-branch-production-configs.ymlProvjeravamo da li je resurs StaleFeatureBranch:
$ kubectl api-resources | grep stalefeaturebranches
IME ... APIGROUP ... VRSTA
stalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranchProvjeravamo da li je u klasteru instaliran operator:
$ kubectl get pods --namespace stale-feature-branch-operator
IME ... STATUS ... STAROST
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Radi ... 38sAko pogledamo njegove logove, spreman je za obradu resursa StaleFeatureBranch:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Operator Version: 0.0.1"}
...
... "msg":"Pokretanje EventSource", ... , "izvor":"vid vrste: /, Vid="}
... "msg":"Pokretanje Kontrolera", ...}
... "msg":"Pokretanje radnika", ..., "broj radnika":1}Instaliramo gotove fixtures (gotove konfiguracije za modeliranje resursa klastera) za resurs StaleFeatureBranch:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/stale-feature-branch.ymlU konfiguracijama je navedeno da traži namespace-ove s podstringom -pr- jednom u 1 minuta.:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 1
checkEveryMinutes: 1Operator je reagirao i spreman je provjeriti namespace-ove:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch je u obradi.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}Instaliramo fixtures, koja sadrži dva namespace-a (project-pr-1, project-pr-2) i njihove deploymente, servise, ingress, i tako dalje:
$ 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 kreiran
deployment.apps/project-pr-1 kreiran
service/project-pr-1 kreiran
horizontalpodautoscaler.autoscaling/project-pr-1 kreiran
secret/project-pr-1 kreiran
configmap/project-pr-1 kreiran
ingress.extensions/project-pr-1 kreiran
namespace/project-pr-2 kreiran
deployment.apps/project-pr-2 kreiran
service/project-pr-2 kreiran
horizontalpodautoscaler.autoscaling/project-pr-2 kreiran
secret/project-pr-2 kreiran
configmap/project-pr-2 kreiran
ingress.extensions/project-pr-2 kreiranProvjeravamo da li su svi resursi gore uspješno kreirani:
$ 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
...Budući da smo uključili debug, namespace-ove project-pr-1 i project-pr-2, stoga će se svi ostali resursi odmah ukloniti bez obzira na parametar afterDaysWithoutDeploy. U logovima operatora to je vidljivo:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace treba biti uklonjen jer je omogućen debug način.","namespaceName":"project-pr-1"}
... "msg":"Namespace se obrađuje.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace je uklonjen.","namespaceName":"project-pr-1"}
... "msg":"Namespace treba biti uklonjen jer je omogućen debug način.","namespaceName":"project-pr-2"}
... "msg":"Namespace se obrađuje.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace je uklonjen.","namespaceName":"project-pr-2"}Ako provjerite prisutnost resursa, bit će u statusu Terminating (proces uklanjanja) ili su već uklonjeni (izlaz komande je prazan).
$ 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
...Možete ponoviti proces kreiranja fixtures several times and ensure that they will be removed within a minute.
Alternatives
What can be done instead of an operator that works in a cluster? There are several approaches, all of them are not ideal (and their disadvantages are subjective), and everyone decides what suits their specific project best:
Delete the feature branch during the continuous integration build of the master branch.
- For this, you need to know which pull request corresponds to the commit that is being built. Since the feature branch namespace contains the pull request identifier - its number, or the branch name, this identifier always needs to be specified in the commit.
- Builds of master branches fail. For example, you have the following stages: download the project, run tests, build the project, release it, send notifications, clean up the feature branch of the latest pull request. If the build fails when sending a notification, you will have to manually delete all resources in the cluster.
- Without the proper context, deleting the feature branch in the master build is not obvious.
Using webhooks ().
- Perhaps this is not your approach. For example, in , only one type of pipeline supports the ability to save its configurations in the source code. When using webhooks, you need to write your own script for processing them. This script must be placed in the Jenkins interface, which is difficult to maintain.
Write and add the Kubernetes cluster.
- Time spent on writing and maintaining.
- The operator already works in a similar style, is documented, and supported.
Thank you for your attention to the article. .
Izvor: habr.com
