10

我将描述我的设置以使问题不那么抽象,但它们似乎并不特定于我的情况。

语境

我们有 Python-Django 后端和一个 VueJS 前端,每个都在一个存储库中,使用 Portainer(使用堆栈)配置和部署 Gitlab-CI。每个存储库的生产分支中的提交遵循以下路径:

  1. 犯罪
  2. gitlab-ci 管道:
    1. 构建 docker 镜像
    2. 测试图像(前端针对已部署的后端进行测试)
    3. 将图像标记为生产:最新
    4. 将图像推送回 gitlab 注册表
    5. webhook portainer中对应的服务(前端/后端)更新部署的镜像
  3. 搬运工:
    1. 拉图像
    2. 部署

问题

部署同步

想象一下,我们正在对前端和后端进行重大更改,并且两者都将与以前的版本不兼容。因此必须同时部署新版本。

在我们当前的设置中,我们必须首先部署后端(这将破坏已部署的前端),然后部署新的前端,修复生产,但有一个“停机”期。

测试的分支依赖

有时当我们在前端开发分支 feature-1 时,必须针对后端的分支 feature-1 进行测试。

在我们当前的设置中,前端中的所有提交都针对已部署的后端进行了测试(为避免在 CI 中复制后端,仅使用生产 API 地址),在这种情况下会导致错误的测试结果。

后端集成测试

当对后端进行提交时,它可能会破坏前端。

目前后端没有针对前端进行测试(只有另一种方式)。

可能的解决方案

对于部署同步问题,我考虑创建另一个存储库,其中只有一个文件指定应部署的前端和后端版本。此存储库中的提交将导致 Portanier 的两个服务 webhook 被“卷曲”以进行更新(后端和前端)。这并不能保证同时更新(在 Portainer 中可能会失败并且不会回滚),但它会比当前设置更好。

我不确定这里应该使用什么来指定版本:commit hash, git tag, branch, docker image version ... 最后一个可能避免重建和测试图像,但我认为图像名称和版本是固定的Portainer 的栈定义,不容易自动更新。

对于分支依赖项测试,我考虑在每个存储库(前端和后端)中都有一个文件,指定要测试后端/前端的哪个分支。但是每个存储库的 CI 必须复制整个部署环境(例如,运行一个新的后端和前端来测试每个前端提交)。这也将允许后端集成测试。由于我们使用的是 Docker,这并不是很复杂,但是每个 CI 管道都会花费额外的时间......此外,当第一个存储库(前端或后端)被提交时,它将引用另一个仍然不存在的分支存储库,并失败...

这些解决方案对我来说似乎很尴尬,特别是如果这些是使用 Docker 的 CI/CD 常见的问题。当我们添加更多的存储库时,它会变得更加丑陋。

备择方案?

感谢关注!

编辑:出于好奇,我目前的设置是基于这篇文章

4

2 回答 2

4
于 2018-11-21T14:45:42.030 回答
2

测试的分支依赖

有时,当我们在前端开发分支 feature-1 时,必须针对后端的分支 feature-1 进行测试。

在我们当前的设置中,前端中的所有提交都针对已部署的后端进行了测试(为避免在 CI 中复制后端,仅使用生产 API 地址),在这种情况下会导致错误的测试结果。

后端集成测试

当对后端进行提交时,它可能会破坏前端。

目前后端没有针对前端进行测试(只有另一种方式)。

在我目前的公司中,我们有 Django 用于前端(FE)和后端(BE),每个都在一个存储库中。我们正在关注基于主干的开发。我们还将 gitlab 用于 CI/CD。我推出了你在这里提到的内容,一点也不觉得尴尬。

环境与此分支模型之间的关系。

|分支|示例|环境|

|大师 |大师| 分期|

|release-v*|release-v1.1.10|preprod|

标签:

|标签|示例|环境|

|v<主要>.<次要>.<补丁>| v.1.1.10|生产|

一旦创建了分支/标签或对定义的分支进行了任何提交,gitlab 将触发自动构建/部署。

前端必须针对后端进行测试。我们使用功能分支来做到这一点。

特征/<分支摘要>

开发人员需要确保 FE 和 BE 上存在相同的功能分支名称。

为每个部署生成每个前端/后端的 URL,如下所示 -fe.< domain >.com for frontend -be.< domain >.com for backend

例如:两个 FE/BE 存储库中都有一个 feature/mytask。FE URL 是 mytask-fe.< domain >.com,BE URL 是 mytask-be.< domain >.com

您可以使用 docker-compose,但在我的情况下,我们的应用程序使用 helm 部署到 kubernetes。在这个实现的更进一步,我的 FE 和 BE 有一个由 traefik 管理的 k8s 入口。DNS 记录(对于每个 URL)是在(由 k8s DNS 控制器)中自动创建的,后端使用 DB 和 Redis,它们是在每次创建或更改功能分支时创建的。按照特性分支命名的约定,FE 知道如何连接到 BE,而 BE 知道如何使用自己的 DB 和 Redis。

例如: helm upgrade --install ${RELEASE_NAME} ...

RELEASE_NAME 是从 feature/<branch-summary> 中提取的(不超过 63 个字符)

其他事情,您可以考虑为功能分支部署初始化数据。就我而言

*) 开发人员将设法填充数据(可能在 k8s 中将脚本作为 init 容器运行)。如果开发人员将提交推送到相同的功能分支,这将触发重新部署,并且将重新初始化 DB / Redis 的所有数据。开发人员可能需要重新填充数据,QC 可能需要从该功能开始重新开始测试。

*) 避免在 gitlab 存储库中的 k8s 和分支中创建太多资源。我在 gitlab CI 中设置了一个删除功能,以便删除 BE/FE 存储库中的一个功能分支,这将分别触发 k8s 中的部署删除。

于 2019-01-06T16:25:30.260 回答