Suppression d'une branche de fonctionnalités obsolète dans un cluster Kubernetes

Suppression d'une branche de fonctionnalités obsolète dans un cluster Kubernetes

Salut! Branche des fonctionnalités (alias déploiement d'aperçu, révision de l'application) - c'est à ce moment-là que non seulement la branche principale est déployée, mais également chaque demande d'extraction vers une URL unique. Vous pouvez vérifier si le code fonctionne dans un environnement de production ; la fonctionnalité peut être présentée à d'autres programmeurs ou spécialistes produit. Pendant que vous travaillez sur une pull request, chaque nouveau déploiement actuel de validation pour l'ancien code est supprimé et le nouveau déploiement pour le nouveau code est déployé. Des questions peuvent survenir lorsque vous avez fusionné une pull request dans la branche master. Vous n'avez plus besoin de la branche de fonctionnalités, mais les ressources Kubernetes sont toujours dans le cluster.

En savoir plus sur les branches de fonctionnalités

Une approche pour créer des branches de fonctionnalités dans Kubernetes consiste à utiliser des espaces de noms. En bref, la configuration de production ressemble à ceci :

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

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

Pour une branche de fonctionnalités, un espace de noms est créé avec son identifiant (par exemple, le numéro de demande d'extraction) et une sorte de préfixe/postfix (par exemple, -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
...

En général, j'ai écrit Opérateur Kubernetes (une application qui a accès aux ressources du cluster), lien vers le projet sur Github. Il supprime les espaces de noms appartenant aux anciennes branches de fonctionnalités. Dans Kubernetes, si vous supprimez un espace de noms, les autres ressources de cet espace de noms sont également supprimées automatiquement.

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

Vous pouvez lire comment implémenter des branches de fonctionnalités dans un cluster ici и ici.

Motivation

Examinons un cycle de vie typique d'une pull request avec intégration continue (continuous integration):

  1. Nous poussons un nouveau commit vers la branche.
  2. Lors du build, des linters et/ou des tests sont exécutés.
  3. Les configurations des pull request Kubernetes sont générées à la volée (par exemple, son numéro est inséré dans le modèle fini).
  4. À l'aide de kubectl apply, les configurations sont ajoutées au cluster (déploiement).
  5. La demande d'extraction est fusionnée dans la branche principale.

Pendant que vous travaillez sur une pull request, chaque nouveau déploiement actuel de validation pour l'ancien code est supprimé et le nouveau déploiement pour le nouveau code est déployé. Mais lorsqu’une pull request est fusionnée dans la branche master, seule la branche master sera construite. En conséquence, il s'avère que nous avons déjà oublié la pull request et que ses ressources Kubernetes sont toujours dans le cluster.

Comment utiliser

Installez le projet avec la commande ci-dessous :

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

Créez un fichier avec le contenu suivant et installez-le via kubectl apply -f:

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

Paramètre espace de nomsSous-chaîne nécessaire pour filtrer les espaces de noms pour les demandes d'extraction provenant d'autres espaces de noms. Par exemple, si le cluster possède les espaces de noms suivants : habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, alors les candidats à la suppression seront habr-back-end-pr-17, habr-back-end-pr-33.

Paramètre afterDaysWithoutDeploy nécessaire pour supprimer les anciens espaces de noms. Par exemple, si un espace de noms est créé 3 дня 1 час retour, et le paramètre indique 3 дня, cet espace de noms sera supprimé. Cela fonctionne également dans le sens inverse si l'espace de noms est créé 2 дня 23 часа retour, et le paramètre indique 3 дня, cet espace de noms ne sera pas supprimé.

Il existe un paramètre supplémentaire, il est responsable de la fréquence à laquelle tous les espaces de noms doivent être analysés et vérifié les jours sans déploiement - vérifierToutes les minutes. Par défaut, il est égal à 30 минутам.

Comment ça marche

En pratique, vous aurez besoin de :

  1. Docker pour travailler dans un environnement isolé.
  2. Minikube lèvera un cluster Kubernetes localement.
  3. kubectl — interface de ligne de commande pour la gestion du cluster.

Nous élevons un cluster Kubernetes localement :

$ 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.

Nous indiquons kubectl utiliser le cluster local par défaut :

$ kubectl config use-context minikube
Switched to context "minikube".

Téléchargez les configurations pour l'environnement de production :

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

Étant donné que les configurations de production sont configurées pour vérifier les anciens espaces de noms et que notre cluster nouvellement créé ne les possède pas, nous remplacerons la variable d'environnement IS_DEBUG sur true. Avec cette valeur le paramètre afterDaysWithoutDeploy n'est pas pris en compte et les espaces de noms ne sont pas vérifiés pendant les jours sans déploiement, uniquement pour l'occurrence de la sous-chaîne (-pr-).

Si vous êtes sur Linux:

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

Si vous êtes sur macOS:

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

Installation du projet :

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

Vérifier qu'une ressource est apparue dans le cluster StaleFeatureBranch:

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

On vérifie qu'un opérateur est apparu dans le cluster :

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

Si vous regardez ses logs, il est prêt à traiter les ressources StaleFeatureBranch:

$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Operator Version: 0.0.1"}
...
... "msg":"Starting EventSource", ... , "source":"kind source: /, Kind="}
... "msg":"Starting Controller", ...}
... "msg":"Starting workers", ..., "worker count":1}

Nous installons du prêt à l'emploi fixtures (configurations prêtes à l'emploi pour la modélisation des ressources du cluster) pour une ressource StaleFeatureBranch:

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

Les configurations indiquent de rechercher des espaces de noms avec une sous-chaîne -pr- une fois dans 1 минуту.:

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

L'opérateur a répondu et est prêt à vérifier les espaces de noms :

$ 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"}

Fixer fixtures, contenant deux espaces de noms (project-pr-1, project-pr-2) et eux deployments, services, ingress, et ainsi de suite:

$ 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

Nous vérifions que toutes les ressources ci-dessus ont été créées avec succès :

$ 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
...

Puisque nous avons inclus debug, espaces de noms project-pr-1 и project-pr-2, donc toutes les autres ressources devront être supprimées immédiatement sans tenir compte du paramètre afterDaysWithoutDeploy. Cela peut être vu dans les journaux de l'opérateur :

$ 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"}

Si vous vérifiez la disponibilité des ressources, elles seront dans le statut Terminating (processus de suppression) ou déjà supprimé (la sortie de la commande est vide).

$ 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
...

Vous pouvez répéter le processus de création fixtures plusieurs fois et assurez-vous qu’ils sont retirés dans la minute.

Des alternatives

Que peut-on faire à la place d'un opérateur qui travaille en cluster ? Il existe plusieurs approches, toutes imparfaites (et leurs défauts sont subjectifs), et chacun décide lui-même de ce qui est le mieux pour un projet particulier :

  1. Supprimez la branche de fonctionnalité lors de la construction d’intégration continue de la branche principale.

    • Pour ce faire, vous devez savoir quelle pull request se rapporte au commit en cours de construction. Étant donné que l'espace de noms de la branche de fonctionnalité contient l'identifiant de la pull request - son numéro ou le nom de la branche, l'identifiant devra toujours être spécifié dans le commit.
    • Les builds de branche principale échouent. Par exemple, vous disposez des étapes suivantes : télécharger le projet, exécuter des tests, construire le projet, créer une version, envoyer des notifications, effacer la branche de fonctionnalité de la dernière pull request. Si la construction échoue lors de l'envoi d'une notification, vous devrez supprimer manuellement toutes les ressources du cluster.
    • Sans contexte approprié, la suppression de branches de fonctionnalités dans la version principale n'est pas évidente.

  2. Utiliser des webhooks (exemple).

    • Ce n'est peut-être pas votre approche. Par exemple, dans Jenkins, un seul type de pipeline prend en charge la possibilité d'enregistrer ses configurations dans le code source. Lorsque vous utilisez des webhooks, vous devez écrire votre propre script pour les traiter. Ce script devra être placé dans l'interface Jenkins, difficile à maintenir.

  3. Écrire Cron et ajoutez un cluster Kubernetes.

    • Passer du temps à l'écriture et au support.
    • L'opérateur travaille déjà dans un style similaire, est documenté et pris en charge.

Merci de votre attention sur l'article. Lien vers le projet sur Github.

Source: habr.com

Ajouter un commentaire