删除 Kubernetes 集群中过时的功能分支

删除 Kubernetes 集群中过时的功能分支

您好! 特征分支 (又名部署预览、审查应用程序)——此时不仅部署了主分支,而且还部署了对唯一 URL 的每个拉取请求。您可以检查代码在生产环境中是否有效;该功能可以向其他程序员或产品专家展示。当您处理拉取请求时,每次新提交、旧代码的当前部署都会被删除,并且新代码的新部署将会推出。将拉取请求合并到主分支时可能会出现问题。您不再需要功能分支,但 Kubernetes 资源仍然在集群中。

有关功能分支的更多信息

在 Kubernetes 中创建功能分支的一种方法是使用命名空间。简而言之,生产配置如下所示:

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

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

对于功能分支,将使用其标识符(例如,拉取请求编号)和某种前缀/后缀(例如, -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
...

一般来说,我写了 Kubernetes运算符 (有权访问集群资源的应用程序), 链接到 Github 上的项目。它删除属于旧功能分支的名称空间。在 Kubernetes 中,如果删除某个命名空间,该命名空间中的其他资源也会自动删除。

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

您可以阅读有关如何将功能分支实现到集群中的信息 这里 и 这里.

动机

让我们看一下具有持续集成的典型拉取请求生命周期(continuous integration):

  1. 我们将新的提交推送到分支。
  2. 在构建过程中,运行 linter 和/或测试。
  3. Kubernetes 拉取请求配置是动态生成的(例如,其编号插入到完成的模板中)。
  4. 使用 kubectl apply,将配置添加到集群(部署)。
  5. 拉取请求合并到主分支中。

当您处理拉取请求时,每次新提交、旧代码的当前部署都会被删除,并且新代码的新部署将会推出。但是当拉取请求合并到主分支时,只会构建主分支。结果发现,我们已经忘记了拉取请求,它的 Kubernetes 资源仍然在集群中。

如何使用

使用以下命令安装项目:

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

创建一个包含以下内容的文件并通过以下方式安装 kubectl apply -f:

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

参数 命名空间子字符串 需要过滤命名空间以查找来自其他命名空间的拉取请求。例如,如果集群具有以下命名空间: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33,那么删除的候选者将是 habr-back-end-pr-17, habr-back-end-pr-33.

参数 没有部署后的日子 需要删除旧的命名空间。例如,如果创建了命名空间 3 дня 1 час 返回,参数表示 3 дня,该命名空间将被删除。如果创建了命名空间,它也会以相反的方向工作 2 дня 23 часа 返回,参数表示 3 дня,该命名空间不会被删除。

还有一个参数,它负责扫描所有命名空间并检查没有部署的天数的频率 - 每分钟检查一次。默认情况下是相等的 30 минутам.

怎么开动这个

在实践中,您将需要:

  1. 码头工人 用于在隔离环境中工作。
  2. 迷你酷 将在本地建立一个 Kubernetes 集群。
  3. Kubectl — 用于集群管理的命令行界面。

我们在本地建立一个 Kubernetes 集群:

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

指定 kubectl 默认使用本地集群:

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

下载生产环境的配置:

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

由于生产配置配置为检查旧的命名空间,而我们新提出的集群没有它们,因此我们将替换环境变量 IS_DEBUGtrue。有了这个值参数 afterDaysWithoutDeploy 不考虑在内,并且在没有部署的情况下不会检查命名空间,仅检查子字符串 (-pr-).

如果你在 Linux:

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

如果你在 macOS:

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

安装项目:

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

检查集群中是否出现了资源 StaleFeatureBranch:

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

我们检查集群中是否出现了操作员:

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

如果您查看其日志,它已准备好处理资源 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}

我们安装现成的 fixtures (用于对集群资源进行建模的现成配置)针对资源 StaleFeatureBranch:

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

配置指示使用子字符串搜索命名空间 -pr- 曾在 1 минуту.:

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

操作员已响应并准备检查命名空间:

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

fixtures,包含两个命名空间(project-pr-1, project-pr-2) 还有他们 deployments, services, ingress, 等等:

$ 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

我们检查以上所有资源是否已成功创建:

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

由于我们包括了 debug, 命名空间 project-pr-1 и project-pr-2,因此必须立即删除所有其他资源,而不考虑该参数 afterDaysWithoutDeploy。这可以在操作员日志中看到:

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

如果您检查资源的可用性,它们将处于以下状态 Terminating (删除过程)或已删除(命令输出为空)。

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

您可以重复创建过程 fixtures 多次并确保它们在一分钟内被删除。

替代品

除了在集群中工作的操作员之外,还能做什么?有几种方法,但它们都不完美(并且它们的缺点是主观的),每个人都自己决定什么最适合特定项目:

  1. 在主分支持续集成构建期间删除功能分支。

    • 为此,您需要知道哪个拉取请求引用了正在构建的提交。由于功能分支命名空间包含拉取请求标识符(其编号或分支名称),因此始终必须在提交中指定标识符。
    • 主分支构建失败。例如,您有以下阶段:下载项目、运行测试、构建项目、发布版本、发送通知、清除最后一个拉取请求的功能分支。如果发送通知时构建失败,您将必须手动删除集群中的所有资源。
    • 如果没有适当的上下文,删除主构建中的功能分支并不明显。

  2. 使用网络钩子(例子).

    • 这可能不是你的方法。例如,在 詹金斯,只有一种类型的管道支持将其配置保存在源代码中的功能。使用 webhooks 时,您需要编写自己的脚本来处理它们。这个脚本必须放在Jenkins界面中,这很难维护。

  3. 的cronjob 并添加 Kubernetes 集群。

    • 花时间写作和支持。
    • 该操作员已经以类似的方式工作,并有文档记录和支持。

感谢您关注本文。 链接到 Github 上的项目.

来源: habr.com

添加评论