Docker 在英雄联盟游戏中的实践探索

【原文编者的话】Riot将Docker和Jenkins相结合,以此来构建流水线(Pipeline)。这篇博客是Riot实践Docker的系列博客的第一篇,主要介绍了他们的目标和理念;后续博客则以教程的形式一步一步地记录Riot的Docker实践。

Docker 在英雄联盟游戏中的实践探索

容器技术已经风靡全球,我们欢迎容器化领域的新霸主们。

然而,他们也给Riot的流水线工程团队(Pipeline Engineering team)的同事们带来了新挑战。我叫Maxfield Stewart,是Riot的工程师,我们组主要负责构建流水线(Pipeline)——从代码签入(check in)到部署的一切工作,甚至更多。如果说持续交付是一首主题曲的话,那么我们就是用清唱的方式演唱它。我们运转的是一个类似云的环境,管理着Riot最大的一个服务器和虚拟机集群。其中的一个庞然大物是构建集群(Build Farm),由大量的物理机和虚拟机组成。它是从数年前的一个小集群发展而来的,当时只负责构建英雄联盟的游戏客户端。

最近,我们已经融入了Docker容器技术。我们是如何将容器与传统的构建集群集成,并使其越来越像一个自服务的基于云的工作引擎呢?我们能否使用Dockerfiles定义构建环境,并与我们常用的开源架构相结合呢?我们又能不能抛弃传统的基于虚拟机的云,转身拥抱容器云呢?

Docker 在英雄联盟游戏中的实践探索

上述问题已经持续了相当长的一段时间,就像寒冰射手(Ashe)的箭一样。接下来,我将通过一个系列博客介绍我们的团队是如何尝试回答上述问题的。本文是其中第一篇博客,主要是介绍我们的团队背景,以及我们为什么要整合容器技术。在后续博客中,我将具体地分享如何整合Jenkins和Docker。第一篇教程是一个基础介绍(http://engineering.riotgames.com/news/putting-jenkins-docker-container)。如果你对于使用容器创建构建集群、持续交付、帮助工程师快速交付,那么这个系列就是你要的。请准备好:我将从基本介绍,逐步深入,最终介绍如何使用Docker承载真正的业务。

一年之前,我们将持续集成引入到了英雄联盟。在那之前,我们拼命地尝试以一个常规节奏来发布英雄联盟,但是我们步履维艰。因此我们打算尽可能自动化这一切,从构建流水线到创建测试环境,获得了大量的成果,包括提高交付一致性、减少构建时间、改善总体完成度。英雄联盟从一天几次的构建,增长到了每天30次构建。

Docker 在英雄联盟游戏中的实践探索

构建英雄联盟可不是开玩笑的,其中包括了超过150个任务,我们构建每个重要的版本。每次构建有各种形式,从传统的debug构建到新版本,以及专门为了包括腾讯和Garena在内的全球合作伙伴准备的变种版本。我们可以追踪到每次构建、什么测试环境、什么测试内容、PBE以及快速部署成产品。我们可以一键创建测试环境,并且可以在几个星期内从20个测试环境增加到70多个,包括450多个虚拟机。构建英雄联盟只是构建集群的一部分工作,构建集群本身支持了Riot各个工程团队的3300多个构建任务。然而,这一构建流程并不是完美的,这些陈旧的工具有时需要连接起来才能工作。在持续集成中,我们秉持4项原则:

  1. 我们认为工程师团队必须能完全掌控他们的技术栈,包括对于构建环境的管理员权限。
  2. 我们认为配置即代码。团队应当尽可能使用源码控制来维护他们自己的构建流水线和环境。
  3. 我们认为每当工程师执行一次构建,都需要针对所有可部署的配置构建一个可交付的版本。一个“构建”并不只是编译代码而已,而是所有可部署的组件的集合。
  4. 我们认为一次交付就是一个产品决策(shipping is a product decision)。只需按一下按钮,产品团队就能够部署并查看最新版本。

Docker 在英雄联盟游戏中的实践探索

我们需要世界一流的技术栈才能达到这些目标。通常有三种选择:完全重头编写、购买别人的工具或者定制化开源项目。

我们选择了第三种。在这篇博客中,我不想比较各种CI工具。不过,通过修改开源工具来符合我们的需求是一个最好的折中方案:不需要重头编写;可以与开源世界合作;如果有必要的话,可以轻易脱离它。

因此,我们的技术栈非常简单:

  • 开源版本的Jenkins
  • Jenkins的任务DSL插件(Job DSL Plugin)
  • Jenkins的构建流插件(Build Flow plugin)
  • 将各个组件连接在一起的工程独创性

我们选择和继续使用Jenkins,是因为它是灵活的、开源的、易于处理我们的基本构建操作。总体来说,Jenkins是易于创建一个构建流水线的,符合我们持续交付的核心需求(如上所述)。作为一款广泛应用的开源工具,我们有一个极具活力的社区在与我们合作。与重头编写自定义工具相比,工程师团队可以利用开源标准的实现,这是很有帮助的,也是具有风险的。开源标准经常变化,昨天的一个好主意明天就可能变成一个坏主意。然而,利用合适的插件和技术诀窍,我们只用了少量的代码、配置和开销,就完成了一个全自动的持续集成链。

那么,Docker发挥了什么作用呢?让我们回想一下我提到的持续交付的核心原则。最近,我们团队遇到的一个挑战是构建环境的所有权。之前,工程师们通过Packer.io定义自己的虚拟机镜像,然后给产品团队集群的root权限。本质上,我们需要通过Jenkins这一个工作流引擎定义一个内部的云环境。我们探索了几个通用的配置管理工具,如Puppet和Chef,来实现虚拟云环境,并使工程师们能控制这些机器。

然后,Docker出现了。

这件事情就变得简单了:Dockerfile比其他工具更易于维护。在Docker的帮助下,我们意识到容器更容易管理了。如果我们把Docker中Dockerfile的概念和构建环境的所有权结合起来,我们就进入了工程天堂。

Docker 在英雄联盟游戏中的实践探索

Docker很善于解决部署中的挑战。我主要关注Docker是如何帮助工作流引擎、构建系统和流水线,同时也熟悉了如何将其作为一个部署工具和方法论。Riot管理着大量的微服务,而容器和微服务的组合就像花生酱和巧克力的组合。因为Docker成为了一个“Thing(tm)”,我们也会使用它来解决其他的一些问题。

流水线工程团队的梦想变得更真实了:我们想要一个流水线构建工具,它能动态地加速持续交付流水线,使用框架代码来按需地一键构建环境。为了创建一个完整的构建流水线,我们之前是通过自动化配置虚拟机来实现的,现在我们认为使用Docker容器来完成。

需要说明的是,Docker并不是一个完美的整体解决方案。它不能解决Windows和OSX的构建环境中的问题,也不能和我们使用的每个工具结合。但是,Docker确实解决了Linux平台中我们遇到的很多困难。在Riot,我们在平台和后端上进行了大量的工程工作。包括核心的后台服务在内,几乎所有的特性都是通过跑在Linux上的微服务来提供的。因此,如何优化解决方案空间是值得我们投入时间和精力的。

我们已经开始将Docker与现有的构建栈结合,并获得了一些早期的成就。我们创建了Jenkins的一键部署环境,在容器中部署,加速了测试和调试过程。我们从一个小型集群(大概500个任务)开始,使用容器作为构建环境,在所有权和迭代速度上团队也提供了积极的反馈,包括:

  • 基于Linux构建微服务和网站的工程师们能够以编程的方式定义他们的构建环境了
  • 本地的构建环境和构建集群中的构建环境是完全一致的(在后续博客中,我将介绍如何做到这一点)
  • 动态资源分配意味着降低整体计算成本
  • 一台虚拟机可以处理4个不同的组合300多个构建任务,这原本是通过8台虚拟机完成的

这篇博客仅仅是一个系列话题的介绍,这个系列将覆盖多个领域,以教程的形式发布,提供实例和源码。首先,系列博客将介绍如何使用Docker来部署Jenkins,包括各种最佳实践,并通过一个真实应用引入Docker的基础知识;然后,系列博客将探索容器化构建环境的各种方案,并介绍Riot是如何将Docker融入Jenkins的生态环境;最后,将介绍流水线工程团队是如何完成最终目标的。

相关推荐