
Hallo! Feature-Branch (auch bekannt als Deploy-Vorschau, Überprüfungs-App) — das ist, wenn nicht nur der Master-Zweig, sondern auch jeder Pull-Request auf einer einzigartigen URL bereitgestellt wird. Man kann testen, ob der Code in der Produktionsumgebung funktioniert, oder das Feature anderen Programmierern oder Produktmanagern zeigen. Während Sie an einem Pull-Request arbeiten, wird jedes neue Commit zu einem aktuellen Deployment des alten Codes gelöscht und ein neues Deployment für den neuen Code wird bereitgestellt. Fragen können auftreten, wenn Sie den Pull-Request in den Master-Zweig zusammengeführt haben. Der Feature-Branch ist nicht mehr erforderlich, aber die Ressourcen von Kubernetes befinden sich weiterhin im Cluster.
Weitere Informationen zu Feature-Branches
Einer der Ansätze, wie man Feature-Branches in Kubernetes erstellen kann, ist die Verwendung von Namespaces. Kurz gesagt, die Produktionskonfigurationen sehen so aus:
kind: Namespace
apiVersion: v1
metadata:
name: habr-back-end
...
kind: Deployment
apiVersion: apps/v1
metadata:
namespace: habr-back-end
spec:
replicas: 3
...Für den Feature-Branch wird ein Namespace mit seiner Kennung (zum Beispiel der Nummer des Pull-Requests) und einem bestimmten Präfix/Suffix (zum Beispiel, -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
...Insgesamt habe ich geschrieben Kubernetes Operator (eine Anwendung, die Zugriff auf die Cluster-Ressourcen hat), . Es entfernt die Namespaces, die sich auf alte Feature-Branches beziehen. In Kubernetes werden beim Löschen eines Namespaces auch andere Ressourcen in diesem Namespace automatisch gelöscht.
$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE ... ALTER
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7hWie man Feature-Branches in den Cluster integriert, kann man lesen und .
Motivation
Lassen Sie uns den typischen Lebenszyklus eines Pull-Requests mit kontinuierlicher Integration anschauen (kontinuierliche Integration):
- Wir pushen ein neues Commit in den Branch.
- Beim Build werden Linter und/oder Tests ausgeführt.
- Die Kubernetes-Konfigurationen des Pull-Requests werden dynamisch erstellt (zum Beispiel wird seine Nummer in eine bereitgestellte Vorlage eingesetzt).
- Die Konfigurationen gelangen mit kubectl apply in den Cluster (Deployment).
- Der Pull-Request wird in den Master-Zweig zusammengeführt.
Während Sie an einem Pull-Request arbeiten, wird jedes neue Commit zu einem aktuellen Deployment des alten Codes gelöscht und ein neues Deployment für den neuen Code wird bereitgestellt. Aber wenn der Pull-Request in den Master-Zweig zusammengeführt wird, wird nur der Master-Zweig gebaut. Das führt dazu, dass wir den Pull-Request bereits vergessen haben, während seine Kubernetes-Ressourcen weiterhin im Cluster vorhanden sind.
Wie man es verwendet
Installieren Sie das Projekt mit dem folgenden Befehl:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.ymlErstellen Sie eine Datei mit folgendem Inhalt und installieren Sie sie über kubectl apply -f:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 3Parameter namespaceSubstring benötigt, um Namespaces für Pull Requests von anderen Namespaces zu filtern. Zum Beispiel, wenn im Cluster die folgenden Namespaces existieren: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, dann wären die Kandidaten für die Löschung habr-back-end-pr-17, habr-back-end-pr-33.
Parameter afterDaysWithoutDeploy benötigt, um alte Namespaces zu löschen. Zum Beispiel, wenn der Namespace vor 3 Tagen 1 Stunde erstellt wurde, und der Parameter angibt 3 Tage, wird dieser Namespace gelöscht. Es funktioniert auch in umgekehrter Richtung, wenn der Namespace vor 2 Tagen 23 Stunden erstellt wurde, und der Parameter angibt 3 Tage, wird dieser Namespace nicht gelöscht.
Es gibt einen weiteren Parameter, der angibt, wie oft alle Namespaces gescannt werden, um die Tage ohne Deploy zu überprüfen — checkEveryMinutes. Standardmäßig beträgt er 30 Minuten.
Die DANE-Spezifikation ist in
In der Praxis wird Folgendes benötigt:
- um in einer isolierten Umgebung zu arbeiten.
- hebt den Kubernetes-Cluster lokal an.
- — Kommandozeileninterface zur Verwaltung des Clusters.
Heben wir den Kubernetes-Cluster lokal an:
$ minikube start --vm-driver=docker
minikube v1.11.0 auf Darwin 10.15.5
Verwendung des Docker-Treibers basierend auf dem vorhandenen Profil.
Starte Steuerungsplane-Node minikube im Cluster minikube.Geben Sie an kubectl lokalen Cluster standardmäßig verwenden:
$ kubectl config use-context minikube
Wechsel zu Kontext "minikube".Laden Sie Konfigurationen für die Produktionsumgebung herunter:
$ curl https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/configs/production.yml > stale-feature-branch-production-configs.ymlDa die Produktionskonfigurationen so eingestellt sind, dass sie alte Namespaces überprüfen, und in unserem neu angehobenen Cluster keine vorhanden sind, ersetzen wir die Umgebungsvariable IS_DEBUG auf true. Bei diesem Wert wird der Parameter afterDaysWithoutDeploy nicht berücksichtigt und die Namespaces werden nicht auf Tage ohne Deploy überprüft, sondern nur auf das Vorhandensein der Unterzeichenfolge (-pr-).
Wenn Sie auf Linux:
$ sed -i 's|false|true|g' stale-feature-branch-production-configs.ymlWenn Sie auf macOS:
$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.ymlInstallieren Sie das Projekt:
$ kubectl apply -f stale-feature-branch-production-configs.ymlÜberprüfen Sie, ob die Ressource im Cluster erschienen ist StaleFeatureBranch:
$ kubectl api-resources | grep stalefeaturebranches
NAME ... APIGROUP ... KIND
stalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranchÜberprüfen Sie, ob der Operator im Cluster erschienen ist:
$ kubectl get pods --namespace stale-feature-branch-operator
NAME ... STATUS ... AGE
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38sWenn Sie in seine Protokolle schauen, ist es bereit, Ressourcen zu verarbeiten StaleFeatureBranch:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Operator-Version: 0.0.1"}
...
... "msg":"Starte EventSource", ... , "source":"kind source: /, Kind="}
... "msg":"Starte Controller", ...}
... "msg":"Starte Worker", ..., "worker count":1}Installieren Sie die fertigen fixtures (fertige Konfigurationen zur Modellierung von Clusterressourcen) für die Ressource StaleFeatureBranch:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/stale-feature-branch.ymlIn den Konfigurationen ist angegeben, nach Namespaces mit dem Substring zu suchen -pr- alle 1 Minute.:
apiVersion: feature-branch.dmytrostriletskyi.com/v1
kind: StaleFeatureBranch
metadata:
name: stale-feature-branch
spec:
namespaceSubstring: -pr-
afterDaysWithoutDeploy: 1
checkEveryMinutes: 1Der Operator hat reagiert und ist bereit, die Namespaces zu überprüfen:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch wird verarbeitet.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}Installation fixtures, die zwei Namespaces enthalten (project-pr-1, project-pr-2) und deren deployments, Dienste, ingress, und so weiter:
$ 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 erstellt
deployment.apps/project-pr-1 erstellt
service/project-pr-1 erstellt
horizontalpodautoscaler.autoscaling/project-pr-1 erstellt
secret/project-pr-1 erstellt
configmap/project-pr-1 erstellt
ingress.extensions/project-pr-1 erstellt
namespace/project-pr-2 erstellt
deployment.apps/project-pr-2 erstellt
service/project-pr-2 erstellt
horizontalpodautoscaler.autoscaling/project-pr-2 erstellt
secret/project-pr-2 erstellt
configmap/project-pr-2 erstellt
ingress.extensions/project-pr-2 erstelltÜberprüfen wir, ob alle oben genannten Ressourcen erfolgreich erstellt wurden:
$ 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
...Da wir die debug, Namespaces project-pr-1 und project-pr-2, müssen auch alle anderen Ressourcen sofort gelöscht werden, unabhängig vom Parameter afterDaysWithoutDeploy. In den Logs des Operators ist das sichtbar:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace sollte gelöscht werden, da der Debug-Modus aktiviert ist.","namespaceName":"project-pr-1"}
... "msg":"Namespace wird verarbeitet.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace wurde gelöscht.","namespaceName":"project-pr-1"}
... "msg":"Namespace sollte gelöscht werden, da der Debug-Modus aktiviert ist.","namespaceName":"project-pr-2"}
... "msg":"Namespace wird verarbeitet.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace wurde gelöscht.","namespaceName":"project-pr-2"}Wenn wir die Verfügbarkeit der Ressourcen überprüfen, werden sie sich im Status Terminating (Löschprozess) oder bereits gelöscht (der Befehl gibt nichts aus).
$ 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
...Sie können den Erstellungsprozess fixtures mehrmals wiederholen und sich vergewissern, dass sie innerhalb einer Minute gelöscht werden.
Alternativen
Was kann man statt eines Operators machen, der im Cluster arbeitet? Es gibt mehrere Ansätze, die alle nicht perfekt sind (und ihre Mängel subjektiv sind), und jeder entscheidet selbst, was am besten für ein bestimmtes Projekt geeignet ist:
Den Feature-Branch während des Builds des Master-Branches löschen.
- Dafür muss man wissen, welcher Pull-Request zu dem Commit gehört, der gerade gebaut wird. Da der Feature-Branch-Namespace die ID des Pull-Requests enthält – seine Nummer oder den Namen des Branches – muss die ID immer im Commit angegeben werden.
- Builds des Master-Branches schlagen fehl. Zum Beispiel haben Sie folgende Schritte: Projekt herunterladen, Tests starten, Projekt bauen, Release erstellen, Benachrichtigungen senden, Feature-Branch des letzten Pull-Requests bereinigen. Wenn der Build beim Senden der Benachrichtigung fehlschlägt, müssen Sie alle Ressourcen im Cluster manuell löschen.
- Ohne den richtigen Kontext ist das Löschen des Feature-Branches im Master-Build nicht offensichtlich.
Verwendung von Webhooks ().
- Vielleicht ist das nicht Ihr Ansatz. Zum Beispiel in , unterstützt nur eine Art von Pipeline die Möglichkeit, ihre Konfigurationen im Quellcode zu speichern. Bei der Verwendung von Webhooks müssen Sie Ihr eigenes Skript zu deren Verarbeitung schreiben. Dieses Skript muss in der Jenkins-Oberfläche untergebracht werden, was schwer zu warten ist.
Eintragen und Kubernetes-Cluster hinzufügen.
- Zeitaufwand für das Schreiben und die Wartung.
- Der Operator arbeitet bereits in einem ähnlichen Stil, ist dokumentiert und wird unterstützt.
Vielen Dank für Ihre Aufmerksamkeit zu diesem Artikel. .
Quelle: habr.com
