Eliminando unha rama de funcións obsoleta nun clúster de Kubernetes

Eliminando unha rama de funcións obsoleta nun clúster de Kubernetes

Ola! Rama de características (tamén coñecido como aplicación de vista previa de implementación, revisión) - é cando non só se desprega a rama mestra, senón tamén cada solicitude de extracción a un URL único. Podes comprobar se o código funciona nun ambiente de produción; a función pódese mostrar a outros programadores ou especialistas en produtos. Mentres estás a traballar nunha solicitude de extracción, elimínase cada nova implementación actual de confirmación do código antigo e desenvólvese a nova implementación do novo código. Poden xurdir preguntas ao combinar unha solicitude de extracción na rama principal. Xa non necesitas a rama de funcións, pero os recursos de Kubernetes aínda están no clúster.

Máis información sobre ramas de características

Un enfoque para facer ramas de funcións en Kubernetes é usar espazos de nomes. En resumo, a configuración de produción é así:

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

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

Para unha rama de funcións, créase un espazo de nomes co seu identificador (por exemplo, o número de solicitude de extracción) e algún tipo de prefixo/postfixo (por exemplo, -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 xeral, escribín Operador Kubernetes (unha aplicación que ten acceso aos recursos do clúster), ligazón ao proxecto en Github. Elimina os espazos de nomes que pertencen a ramas de funcións antigas. En Kubernetes, se eliminas un espazo de nomes, outros recursos dese espazo de nomes tamén se eliminan automaticamente.

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

Podes ler sobre como implementar ramas de características nun clúster aquí и aquí.

Motivación

Vexamos un ciclo de vida típico de solicitude de extracción con integración continua (continuous integration):

  1. Impulsamos un novo compromiso coa filial.
  2. Na compilación, realízanse linters e/ou probas.
  3. As configuracións de solicitude de extracción de Kubernetes xéranse ao voo (por exemplo, o seu número insírese no modelo rematado).
  4. Usando kubectl apply, engádense configuracións ao clúster (implementación).
  5. A solicitude de extracción fusionase coa rama mestra.

Mentres estás a traballar nunha solicitude de extracción, elimínase cada nova implementación actual de confirmación do código antigo e desenvólvese a nova implementación do novo código. Pero cando unha solicitude de extracción se fusiona coa rama mestra, só se construirá a rama mestra. Como resultado, resulta que xa nos esquecemos da solicitude de extracción e os seus recursos de Kubernetes aínda están no clúster.

Como usar

Instala o proxecto co seguinte comando:

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

Crea un ficheiro co seguinte contido e instálalo mediante kubectl apply -f:

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

Parámetro namespaceSubcadea necesario para filtrar espazos de nomes para solicitudes de extracción doutros espazos de nomes. Por exemplo, se o clúster ten os seguintes espazos de nomes: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, entón os candidatos á eliminación serán habr-back-end-pr-17, habr-back-end-pr-33.

Parámetro afterDaysWithoutDeploy necesario para eliminar espazos de nomes antigos. Por exemplo, se se crea un espazo de nomes 3 дня 1 час atrás, e o parámetro indica 3 дня, este espazo de nomes eliminarase. Tamén funciona na dirección oposta se se crea o espazo de nomes 2 дня 23 часа atrás, e o parámetro indica 3 дня, este espazo de nomes non se eliminará.

Hai un parámetro máis, que é o responsable da frecuencia con que analizar todos os espazos de nomes e comprobar hai días sen implementación: checkEveryMinutes. Por defecto é igual 30 минутам.

Chat isto

Na práctica, necesitarás:

  1. Estivador para traballar nun ambiente illado.
  2. Minikube creará un clúster de Kubernetes localmente.
  3. kubectl — Interface de liña de comandos para a xestión de clústeres.

Creamos un clúster de 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.

Indicamos kubectl use clúster local por defecto:

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

Descarga de configuracións para o ambiente de produción:

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

Dado que as configuracións de produción están configuradas para comprobar espazos de nomes antigos e o noso clúster recén creado non os ten, substituiremos a variable de ambiente IS_DEBUG en true. Con este valor o parámetro afterDaysWithoutDeploy non se ten en conta e os espazos de nomes non se verifican durante días sen implementación, só para a aparición da subcadea (-pr-).

Se estás conectado Linux:

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

Se estás conectado macOS:

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

Instalación do proxecto:

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

Comprobando que apareceu un recurso no clúster StaleFeatureBranch:

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

Comprobamos que apareceu un operador no clúster:

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

Se miras os seus rexistros, está listo para procesar recursos 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}

Instalamos ready-made fixtures (configuracións preparadas para modelar recursos de clúster) para un recurso StaleFeatureBranch:

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

As configuracións indican buscar espazos de nomes cunha subcadea -pr- unha vez dentro 1 минуту.:

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

O operador respondeu e está preparado para comprobar os espazos de nomes:

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

Conxunto fixtures, que contén dous espazos de nomes (project-pr-1, project-pr-2) e eles deployments, services, ingress, etcétera:

$ 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

Comprobamos que todos os recursos anteriores foron creados con éxito:

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

Xa que incluímos debug, espazos de nomes project-pr-1 и project-pr-2, polo tanto, todos os demais recursos terán que ser eliminados inmediatamente sen ter en conta o parámetro afterDaysWithoutDeploy. Isto pódese ver nos rexistros do operador:

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

Se comproba a dispoñibilidade de recursos, estarán no estado Terminating (proceso de eliminación) ou xa eliminado (a saída do comando está baleira).

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

Podes repetir o proceso de creación fixtures varias veces e asegúrese de que se eliminan nun minuto.

Alternativas

Que se pode facer en lugar dun operador que traballa nun clúster? Hai varios enfoques, todos son imperfectos (e as súas deficiencias son subxectivas), e cada un decide por si mesmo o que é mellor para un proxecto en particular:

  1. Eliminar a rama de funcións durante a compilación de integración continua da rama mestra.

    • Para iso, cómpre saber que solicitude de extracción se relaciona co commit que se está a construír. Dado que o espazo de nomes da rama de características contén o identificador da solicitude de extracción: o seu número ou o nome da rama, o identificador sempre terá que especificarse na confirmación.
    • As construcións das ramas mestras están fallando. Por exemplo, tes as seguintes etapas: descarga o proxecto, realiza probas, crea o proxecto, fai un lanzamento, envía notificacións, borra a rama de funcións da última solicitude de extracción. Se a compilación falla ao enviar unha notificación, terás que eliminar todos os recursos do clúster manualmente.
    • Sen o contexto axeitado, a eliminación de ramas de funcións na compilación mestra non é obvia.

  2. Usando webhooks (exemplo).

    • Este pode non ser o teu enfoque. Por exemplo, en Jenkins, só un tipo de canalización admite a posibilidade de gardar as súas configuracións no código fonte. Ao usar webhooks, debes escribir o teu propio script para procesalos. Este script terá que colocarse na interface de Jenkins, que é difícil de manter.

  3. Para escribir Cronjob e engade un clúster de Kubernetes.

    • Dedicar tempo á escritura e ao apoio.
    • O operador xa traballa nun estilo similar, está documentado e apoiado.

Grazas pola túa atención ao artigo. Ligazón ao proxecto en Github.

Fonte: www.habr.com

Engadir un comentario