我将描述我的设置以使问题不太抽象,但问题似乎并非我所要解决的。
我们在存储库中分别具有Python-Django后端和VueJS前端,并配置了Gitlab-CI并使用Portainer(使用堆栈)进行部署。 每个存储库的生产分支中的提交都遵循以下路径:
想象一下,我们正在对前端和后端进行重大更改,并且两者都将与以前的版本不兼容。因此,新版本必须同时部署。
在当前设置中,我们必须首先部署后端(将会破坏已部署的前端),然后部署新的前端,以固定生产,但周期为“停工”。
有时候我们在前端开发分支功能1时,必须从后端对分支功能1进行测试。
在我们当前的设置中,将针对部署的后端测试前端中的所有提交(为避免在CI中复制后端,仅使用生产API地址),在这种情况下会导致错误的测试结果。
对后端的提交完成后,可能会破坏前端。
当前后端尚未针对前端进行测试(仅相反)。
对于部署同步问题,我考虑过创建另一个存储库,该存储库只有一个文件,该文件指定应部署的前端和后端的版本。在此存储库中的提交将导致Portanier的服务Web挂钩都被“卷曲”以进行更新(后端和前端)。这不能保证同时进行更新(Portainer中的更新可能会失败,并且不会回滚),但是比当前设置要好。
我不确定在此处指定版本时应该使用什么:提交哈希,git标签,分支,docker映像版本...最后一个可以避免不必重建和测试映像,但是我认为映像的名称和版本已在Portainer的堆栈定义中固定,并且不容易自动更新。
对于分支相关性测试,我考虑过在每个存储库(前端和后端)中都有一个文件,用于指定要从后端/前端中测试哪个分支。但是,每个存储库的CI必须复制整个部署环境(例如,运行新的后端和前端以测试每个前端提交)。这也将允许后端集成测试。由于我们使用的是Docker,这并不是很复杂,但是每个CI管道都需要花费额外的时间...此外,当第一个存储库(前端或后端)被提交时,它将在另一个存储库中引用一个尚不存在的分支存储库,然后失败...
这些解决方案对我来说似乎很尴尬,特别是如果这些是Docker在CI / CD中常见的问题。当我们向组合中添加更多存储库时,它可能变得更加难看。
替代品?
感谢您的关注!
(编辑:出于好奇,我当前的设置基于此article)
答案 0 :(得分:1)
部署同步
想象一下,我们正在对前端和后端进行重大更改,并且两者都将与以前的版本不兼容。因此,新版本必须同时部署。
在当前设置中,我们必须首先部署后端(将会破坏已部署的前端),然后部署新的前端,以固定生产,但周期为“停工”。
我不是portainer用户,但是也许您可以依靠某个docker-compose.yml
文件,同时收集后端和前端的版本?在这种情况下,它们可以同时更新...
根据portainer/portainer#1963和this doc page的定义,portainer似乎支持docker-compose和swarm堆栈。
this blog中也记录了docker swarm提供的一些功能,可以在不停机的情况下执行服务升级,但是我不知道在portainer中可以在多大程度上进行配置。
可能的解决方案
我不确定在此处指定版本时应该使用什么:提交哈希,git标签,分支,docker映像版本...最后一个可以避免不必重建和测试映像,但是我认为映像的名称和版本已在Portainer的堆栈定义中固定,并且不容易自动更新。
尽管提交哈希是精确的标识符,但它们可能不足以识别不兼容的版本。因此,您可能想依靠semantic versioning在Git后端存储库上使用标签(和/或分支)。
然后,您可以相应地标记相应的Docker映像,并在需要时引入一些同义标记。例如,假设后端已发布1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0, 1.2.1, 1.2.2
版,则标准做法是像这样标记Docker映像:
project/backend:2.0.2
= project/backend:2.0
= project/backend:2
project/backend:2.0.1
project/backend:2.0.0
project/backend:1.1.1
= project/backend:1.1
= project/backend:1
project/backend:1.1.0
project/backend:1.0.1
= project/backend:1.0
project/backend:1.0.0
(如果需要,删除旧图像)
后端集成测试
当前后端尚未针对前端进行测试(仅相反)。
好的,但是我想您的方法是相当标准的(前端取决于后端,而不是相反)。
无论如何,我记得即使被测系统是前端,也可能值得进行单元测试(与集成测试相比,其开发和运行成本更低),从而使开发的第一阶段成为可能在触发必要的集成测试之前,可以快速运行这些单元测试。
测试的分支依赖性
在我们当前的设置中,将针对部署的后端测试前端中的所有提交(为避免在CI中复制后端,仅使用生产API地址),在这种情况下会导致错误的测试结果。
这可能不够灵活:通常,CI / CD假定集成测试是使用专用后端实例(“ dev”服务器或“ pro-prod”服务器)运行的,并且所有集成测试和系统测试都通过了,将映像部署到“产品”服务器(并进行监控等)
我从您的帖子中看到您正在使用GitLab CI,它具有一些native Docker support,因此也许可以轻松实现。
一些提示:
假定后端已在非向后兼容版本中进行了修改,并且相应的Docker映像在注册表中可用(例如,GitLab CI的映像)。然后,您可以在前端配置中更改该图像的规范(例如,在GitLab CI conf文件中用project/backend:1
替换project/backend:2
。)
您的后端可能已实现为REST Web服务,在这种情况下,您可能还希望在URL中添加版本前缀,以便在从project/backend:1
切换到project/backend:2
时使用(具有不兼容的更改),如果需要,两个版本可以同时部署到URL https://example.com/api/v1/…
和https://example.com/api/v2/…
此外,除了只有两个带有CI / CD的存储库的解决方案(分开测试后端,并针对后端的相关版本测试前端)之外,还可以考虑您首先建议的解决方案:
对于部署同步问题,我考虑过创建另一个存储库,该存储库只有一个文件,该文件指定应部署的前端和后端的版本。在此存储库中的提交将导致Portanier的服务Web挂钩都被“卷曲”以进行更新(后端和前端)。这不能保证同时进行更新(Portainer中的更新可能会失败,并且不会回滚),但是比当前设置要好。
您可以略微修改此方法,以免发生这样的部署失败:您可以在第三个存储库中添加一些配置项设置,该配置项仅包含一个docker-compose.yml
文件,然后从前端配置项移动集成测试那个“组成” CI ...
(仅供参考,此方法类似于此DigitalOcean tutorial中建议的方法,该方法通过一些docker-compose.test.yml
文件实现了集成测试。)
答案 1 :(得分:0)
测试的分支依赖性
有时候我们在前端开发分支功能1时,必须>从后端对分支功能1进行测试。
在我们当前的设置中,将针对部署的后端测试前端中的所有提交(为避免在CI中复制后端,仅使用生产API地址),在这种情况下会导致错误的测试结果。
和
后端集成测试
对后端的提交完成后,可能会破坏前端。
当前后端尚未针对前端进行测试(仅相反)。
在我目前的公司中,我们在存储库中有用于前端(FE)和后端(BE)的Django。 我们正在关注基于主干的开发。我们还将gitlab用于CI / CD。 我推出了您在这里提到的内容,一点也不觉得尴尬。
环境与该分支模型之间的关系。
|分支|示例|环境|
|主|主|分期|
| release-v * | release-v1.1.10 | preprod |
标签:
|标签|示例|环境|
| v <主要>。<次要>。<补丁> | v.1.1.10 |生产|
一旦创建了分支/标签或对已定义分支的任何提交,gitlab将触发自动构建/部署。
前端必须针对后端进行测试。我们使用功能分支来做到这一点。
功能/ <分支摘要>
开发人员需要确保FE和BE上都存在相同的功能分支名称。
为每个部署生成每个前端/后端的URL,如下所示
-fe。
例如:FE / BE库中都有一个功能/我的任务。 FE URL是mytask-fe。<域> .com,BE URL是mytask-be。<域> .com
您可以使用docker-compose,但就我而言,我们的应用程序是使用helm部署到kubernetes的。 在此实现的基础上,My FE和BE具有k8s入口,由traefik管理。 DNS记录(针对每个URL)是通过k8s DNS控制器自动创建的,后端使用的是DB和Redis,它们在每次创建或更改功能分支时都会创建。按照功能分支命名的约定,FE知道如何连接到BE,BE知道如何使用其自己的DB和Redis。
例如: 安全升级-安装$ {RELEASE_NAME} ...
RELEASE_NAME是从功能/ <分支摘要>中提取的(不超过63个字符)
其他方面,您可能会考虑有关为功能分支部署初始化数据。 就我而言
*)开发人员将设法填充数据(也许在k8s中将脚本作为init容器运行)。 如果开发人员将提交推送到同一功能分支,则将触发重新部署,并且将重新初始化DB / Redis的所有数据。开发人员可能需要重新填充数据,而质量控制人员可能需要从此功能开始重新开始测试。
*),以避免在k8s和gitlab存储库中的分支中创建太多资源。 我在gitlab CI中设置了删除功能,以便删除BE / FE存储库中的功能分支,这将分别触发k8s中的部署删除。