问题描述
在GitHub Actions中希望实现一个容器化的跨平台CI/CD环境,该环境需要支持Windows、MacOS和Linux(Ubuntu)环境,用于构建和测试大量的Java项目。用户希望能够按照以下方式进行操作:
1. 创建PR/合并请求。
2. 根据GitHub Actions工作流程所需的任务,触发相应的作业。这些作业会在一个全新的容器中运行(根据作业的需要,可能是Windows、MacOS或Ubuntu),并且每个作业都会在专门为该作业创建的容器中执行。
3. 作业完成后,销毁容器。可能需要设置同时运行的容器数量的上限。
当前的CI系统使用了一些Ubuntu和Windows虚拟机,这些虚拟机在启动时会注册为GitHub Actions的自托管运行器。此外,还有一些物理的Mac Mini,也被配置为自托管运行器。然而,由于Azure虚拟机经常出现随机的网络错误,导致Maven依赖文件被错误地下载或损坏,进而导致Maven崩溃,用户对这种情况感到烦恼。
用户的CI系统涵盖了许多不同的配置,涉及Windows、Mac和Ubuntu上的端到端测试。每个配置至少需要16GB内存和8个虚拟CPU。每次CI运行平均会运行大约20-30个这样的作业,持续时间从15分钟到90分钟不等。
考虑到用户当前将这些Windows和Ubuntu虚拟机托管为规模集(scale sets),在夜间可以减少虚拟机的数量,在白天人们工作时可以增加虚拟机的数量。然而,这种方式不方便,经常导致虚拟机在作业运行中夜间被销毁。因此,用户更希望使用临时性的容器。
幸运的是,GitHub Actions现在支持临时性的运行器(ephemeral runners),这似乎是用户所需要的。结合适用于每个操作系统的Docker镜像以及一个用于运行这些镜像的Kubernetes集群,这似乎是用户应该追求的方向。如果只需要在Linux上进行端到端测试,那么这种方式非常适用。然而,用户不确定Docker对于模拟Windows和MacOS的支持程度,希望能够得到一些建议。
用户也考虑过完全转向Azure DevOps Pipeline作为CI解决方案,因为它在Azure的规模集上能够更好地进行动态扩展。然而,Azure DevOps告知用户他们不能同时运行超过20个作业,而用户的CI管道中可能有10个不同的分支同时运行CI,每个分支至少需要10个作业,因此Azure DevOps并不适合用户的需求。另外,基于Codebuild的CI基础设施也不适用于用户。
解决方案
以下解决方案基于当前的技术和最佳实践。请根据实际情况进行调整和实施。
使用Ephemeral Runners 和 Kubernetes
考虑到你的需求,使用GitHub Actions的临时性运行器(ephemeral runners)结合Kubernetes集群可能是一个理想的解决方案。这将允许你在需要时动态创建和销毁容器,确保每个作业在干净的环境中运行,并且避免了长时间运行的虚拟机。
以下是实现此解决方案的步骤:
1. 配置Kubernetes集群:确保你有一个运行良好的Kubernetes集群,用于管理容器化作业。
2. 创建Docker镜像:为每个操作系统创建适当的Docker镜像,其中包含所需的依赖和工具。
3. 编写GitHub Actions Workflow:创建一个GitHub Actions的工作流程,当有新的PR或合并请求时触发。这个工作流程会在Kubernetes集群中动态创建一个容器,并在其中运行所需的作业。
4. 使用Ephemeral Runners:配置GitHub Actions以使用临时性运行器,确保每个作业都在一个新的容器中运行。
5. 自动化清理:在作业完成后,确保适时地销毁容器,以避免资源浪费。
请注意,这个解决方案可能需要一些Kubernetes和Docker的专业知识。你需要确保你的Kubernetes集群能够根据需要动态调度和管理容器。同时,你需要维护良好的镜像管理实践,以确保镜像的可靠性和一致性。
Windows 和 MacOS 支持
Docker对于Windows和MacOS的支持相对较好,你可以使用Docker Desktop来在本地模拟这些操作系统的环境。但是,需要注意的是,在Kubernetes集群中运行Windows和MacOS容器可能需要一些额外的配置和插件,以确保它们能够正常工作。
限制容器数量
为了避免资源过度使用,你可以考虑在Kubernetes中实施容器数量的限制。你可以使用Kubernetes的资源配额(Resource Quotas)来限制每个作业可以使用的资源量,以及并发运行的作业数量。
总结
在构建跨平台的容器化CI/CD环境时