耗时三天,我将Gitlab CI由shell executor平滑迁移Docker环境

本文原载于 https://blog.shifudao.com, 原文链接

前言

在前一篇文章《浅谈如何打造对容器友好的应用》中,我谈到了对于容器化交付的软件,应该如何让软件本身适配容器环境。今天写一篇文章,谈谈我为何要将Gitlab CI迁移到Docker环境,以及我做了哪些努力。

我为什么将CI迁移到Docker环境?

之前我们的Gitlab已经在线上运行了多年,CI流程已经相对成熟。由于CI使用的较早,当时的Gitlab CI也只支持shell executor,所以就一直使用shell executor用到现在,并且工作的很好。

随着项目越来越多,开发节奏逐渐顺畅,shell executor的一些问题也逐步暴露出来了:

  • 难以并行化,资源冲突比较严重。如测试都需要用到PostgreSQL,为了保证测试能正常运行,不得不限定runner并发数只能是1
  • 资源利用不充分。比如某个集成测试需要跑10分钟左右,但是整体对服务器的资源消耗并不大,由于runner并发数是1,其他的CI任务只能排队等待。在提交密集的时候,整个CI流水线的效率成了项目交付的瓶颈
  • 隔离性很差。shell runner直接使用系统的shell,使用系统的运行环境,为了不影响其他正在运行的系统,基本上都得为CI单独部署一台甚至若干台服务器
  • 部署麻烦。如果为了迁移CI服务器,那就是一件折磨人的工作了。我需要在一台干净的服务器上安装上JDK, NodeJS, PostgreSQL, Android SDK, Hugo, …… 并且需要对目录、数据库等做初始化,配置合理的权限等等。这些工作少说也得一天的工作量。如果能将集成环境一起打包带走,那无疑是一件非常棒的体验。

随着Docker的出现,这一类的环境隔离的问题被解决了,因此并行化流水线的问题其实也就迎刃而解了。并且由于环境的隔离性,因此我可以放心的在一些资源利用并不充分的服务器上部署docker executor来进行CI流程,不会干扰正在运行中的系统和应用。这样整个CI的部署工作量少了很多,并且大大提高了CI的效率。

在简单的体验Docker executor之后,我下定决心将CI环境逐步迁移到Docker环境。

我做了哪些工作

在Docker环境中搭建CI环境不是一件轻松的事情,和shell环境直接运行CI相比:

  • 调试麻烦。shell环境可以直接访问操作系统的文件系统,拿到构建日志,甚至很容易重现构建错误并加以调整。但是Docker环境就完全是另一片天地。容器运行完毕即销毁,不做特殊的处理难以拿到运行日志,故障重现也不如shell那么方便。如果运行的是docker in docker环境,调试起来就更麻烦。
  • 集成麻烦。Docker等于每次启动都是一个完全干净的环境,对于测试来说这是最理想的环境,但是对于搭建这样的环境来说就比较繁琐了。我需要事先在脑海中过一遍这个stage需要用到哪些环境,然后对应准备这些环境的Docker镜像,然后在脑海中想清楚它们是怎么组装起来的,以及在容器中我应该如何初始化对应的运行环境。相比之下shell环境虽然第一次部署特别麻烦,工作量很大,但是毕竟是一次性工作,以后运行起来就非常轻松。
  • 相对耗时较长。在调试CI环境中,随时会遇到问题,甚至牵扯到需要更新镜像等问题。Docker环境运行CI往往需要花费比shell中更长的时间,因此加大了调试的时间

添加一个docker executor并不难,不过为了能在docker executor中构建docker镜像,需要用到docker in docker环境,因此在添加runner的时候就需要注意runner参数。

为了有别于shell runner(需要考虑到旧的兼容性,下面会叙述),需要添加一个tagdocker,这个可以通过runner register参数或在gitlab页面直接添加。

自制镜像。实际上最花时间的也是这部分。有些构建的环境比较繁琐,需要多个技术栈,而Docker的镜像大多是单一运行环境的镜像,因此需要自己定制镜像(如ionic,为了构建Android的apk安装包,需要环境有nodejs, java, gradle, android_sdk这么多种运行环境才能构建)

比如我自己就构建了以下几个镜像:

表面上看比shell环境工作量大了很多,但是这些工作量的付出是值得的。因为对于一个团队来说,大部分情况下技术栈都会保持相对的一个稳定,所以构建一次的docker镜像可以在多个项目进行复用,并且很方便的带着构建环境一并迁移,只要有docker环境就可以打包整个CI环境。

此外,为了保证镜像的一些必要更新,还添加了相应的github action定时任务,检测到FROM镜像更新的时候自动build(因为docker hub的的auto rebuild不会因为官方镜像的更新而触发)

事后的一些注意事项

shell executor 兼容性

由于之前大量的项目都跑在shell executor环境中,因此首先需要保证这些旧项目依旧能正常运行,gitlab会同时运行两套CI环境。为了让shell executor成为默认的runner,需要勾选runner配置中的Run untagged jobs,同时,docker runner则不能勾选这个选项。

对于期望使用docker的项目,在.gitlab-ci.yml配置中强制指定tag选择:

job:
  stage: build
  image: myimage
  scripts:
  - echo hello
  tags:
  - docker

这样只需要对新迁移到docker环境构建的项目修改ci脚本即可,而对旧的项目保持兼容,做到平滑迁移。

容量考虑

docker环境构建往往需要更大的磁盘空间,镜像、容器、存储卷、缓存等等,会比shell环境下占用多几倍的存储空间。对于磁盘空间不那么宽裕的服务器来说,需要充分考虑如何利用有限的存储空间。比如:

  • 尽可能复用镜像layer(使用同一版本的alpine做基础镜像等)
  • 通过定时任务清理掉不活跃的容器和存储卷

缓存考虑

为了加快构建速度,通常都需要使用构建缓存(通常是构建工具缓存的依赖包等等)。在shell环境下通常不需要为缓存特殊考虑,因为它直接用的系统文件系统,缓存直接存储在磁盘上。但是对于docker环境则必须考虑。gitlab ci对于缓存有个cache指令控制,这边我放几个供参考:

gradle的缓存

variables:
  GRADLE_USER_HOME: build/gradle_user_home

cache:
  key: my-project
  paths:
  - ${GRADLE_USER_HOME}/caches/
  - ${GRADLE_USER_HOME}/wrapper/

nodejs缓存

variables:
  NPM_CONFIG_CACHE: npm_cache
  NPM_CONFIG_REGISTRY: https://registry.npm.taobao.org
  NPM_CONFIG_ELECTRON_MIRROR: https://npm.taobao.org/mirrors/electron/
  SASS_BINARY_SITE: https://npm.taobao.org/mirrors/node-sass
  NPM_CONFIG_PHANTOMJS_CDNURL: https://npm.taobao.org/mirrors/phantomjs

cache:
  key: my-another-project
  paths:
  - ${NPM_CONFIG_CACHE}

由于gitlab ci的cache只能支持相对路径,不能用绝对路径,因此需要将构建工具产生的缓存改到当前目录下。加上key,并且标定为项目名,是为了尽可能复用缓存。因为一个项目通常依赖相对稳定,指定项目名为key可以尽可能复用同一个缓存(比如fork项目也可以享受到上游缓存的好处)。

后记

通过这次对Gitlab CI的迁移改造,服务器的资源利用率大大提升,也为了未来可以方便的迁移到k8s集群做了铺垫。未来期望能使用阿里云的serverless k8s集群环境做CI,一些细节还在研究中。

而且也充分考虑到了旧的CI环境兼容,做到平滑切换。对于一些旧项目或者不怎么维护的项目保持旧的环境就好,对于一些实在依赖太重,难以迁移到docker中构建的项目,保持旧的环境就好,不需要为了技术而技术,那就失去了意义。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容

  • CNundefined GitLab-CI与GitLab-Runner 一、持续集成(Continuous Int...
    夜游上河园阅读 4,538评论 0 6
  • 这是阿里内网的一篇文章,感有用,故转载来了,自己实际搭建了,故记录一下: 背景在日常工作中,我们往往会搭建基于je...
    新强吖阅读 5,944评论 0 4
  • 压缩:gzip/gunzip、bzip2/bunzip2、xz/unxz 归档:tar 归档+压缩:zip 1. ...
    yuanzicheng阅读 926评论 0 50
  • 人就一生,只此一生,我们总是希望遗憾可以少些再少些,幸福可以多些再多些,可偏偏世上事不如意者十之八九,但静下心来想...
    o小贝壳阅读 196评论 0 0
  • 在每一个人的成长中,老师都是一个必不可少的存在,而幼儿教师却是起着至关重要的作用。因为幼儿教师是一个孩子...
    稚初梦阅读 491评论 0 0