Gitlab忽然不能部署了

大概三个月前的一天,师傅愁眉不展地跟我说:徒弟,不好了,我最近用咱们这gitlab打包公布的时候总是失败。

我说:原先不是好好的吗?

他说:是啊,原先的确很好用,也不晓得怎么了,最近这段时间就是不好用了,你说彻底不能用吧,也不是,偶然也能用,但总要重试那么好几次,有时候甚至十几次能力用。

我认真想了想,也没改啥啊,只是为了代码平安起见,把原先的giblab的IP地址从公网切换到了内网了,然而DNS我同时也改了,大家没有反映有什么问题啊。

我说:你这样的,你先把编译脚本改成ping gitlab.mydomain.com试试看能不能ping通。

ping了,不稳固,有时候通有时候不通。

这就奇了怪了,能ping到IP地址,阐明DNS没有问题,只是到这个IP地址不通。(到此我仍然执迷不悟,没有想到是路由的问题,前面再说)

被MTU误导的三个月

师傅开始尝试用做减法的形式定位问题,很快有了重大发现。

只有咱们不在工作中减少docker:dind服务,网络就没有问题,那阐明问题就出在这个dind上。

dind的全称是docker in docker,因为自身咱们编译用的gitlab runner就是运行在docker容器外面的,当初还要在这个容器外面再执行docker命令进行打包,就必须依赖这个dind服务,dind服务自身又是一个小的容器,它外面再启动一个docker守护过程,这样里面这个容器能力运行docker命令。

习惯性地关上Google,开始面向Google解决问题。

很多网页都把问题的焦点指向了一个名叫MTU的神秘设置,说这个dind容器缺省的MTU1500,在某种状况下会导致网络传输不稳固,跟咱们遇到的这个症状很类似。

最大传输单元 (Maximum Transmission Unit):最大传输单元是指材料链接层下面所能通过的最大数据包大小。最大传输单元这个参数通常与通信接口无关。 因特网协定容许IP分片,这样就能够将数据报包分成足够小的片段以通过那些最大传输单元小于该数据报原始大小的链路了。这一分片过程产生在IP层,它应用的是将分组发送到链路上的网络接口的最大传输单元的值。

问题变为:如何设置这个MTU?咱们须要理解gitlab流水线工作中的服务外面的子容器如何设置,查了很多材料,有人山盟海誓地说只有在service里减少一个command参数mtu=1400就能够了,然而试验之后发现还是不行,咱们把命令行改为ifconfig,间接查阅网卡参数,发现还是1500,于是查阅docker:dind源码,发现dind会读取一个环境变量DOCKERD_ROOTLESS_ROOTLESSKIT_MTU

于是问题又变成了:如何设置这个环境变量以让dind读到?尝试了各种办法,dind仍然读取不到。

静下心来,从新读Gitlab官网的文档,外面介绍了一个参数variables

Additional environment variables that are passed exclusively to the service.
提供给服务应用的附加的环境变量

仿佛这个货色就是咱们想要的,然而它有附加条件:此设置只能用于Gitlab 14.5版本及以上。而咱们的Gitlab版本还是13.12.3

降级Gitlab惊魂记

我找了一个宁静的周末,开始果决降级Gitlab,而后就差点陷入万劫不复之境。

我想,降级嘛,这还不是很简略的一件事件,而且对于咱们这样严格守规矩的人来说,降级只是减少一个版本号而已。

docker-compose.yml里本来就已有这一句了,这还是大概一年前初始装置gitlab时设置好的:image: 'gitlab/gitlab-ee:latest',那么这曾经是最高版了,于是间接docker-compose down而后docker-compose up -d应该就能够了吧?

不是的,它还是13.12.3

查资料,才晓得应该先docker-compose pull下来能力失去最新版。

好吧,按步骤执行。

坏了,gitlab容器怎么不停地重启?连忙执行docker logs查看容器,发现外面赫然写着一行大字:大版本的降级,必须先升到14.0版本!

郁闷,咱们还是先看看gitlab降级说明书吧,这外面倒是提到了降级门路:

8.11.Z -> 8.12.0 -> 8.17.7 -> 9.5.10 -> 10.8.7 -> 11.11.8 -> 12.0.12 -> 12.1.17 -> 12.10.14 -> 13.0.14 -> 13.1.11 -> 13.8.8 -> 13.12.15 -> 14.0.12 -> 14.9.0 -> latest 14.Y.Z

于是,间接将docker-compose.yml改成image: 'gitlab/gitlab-ee:14.0.12',竟然报告找不到包,再查阅gitlab标签,发现版本号前面竟然还要有-ee.0,你这后面曾经有ee了,为什么标签里还要再写一遍?(所谓ee就是企业版的简称Enterprise Edition,gitlab当初其实不辨别企业版和社区版,对立都要求大家应用企业版,只是你不付费的话,外面属于企业版的那局部性能就不能用而已)

改成image: 'gitlab/gitlab-ee:14.0.12-ee.0'再试一次,这次终于胜利了!

好吧,马不停蹄,升到14.9.0,然而gitlab容器又起不来了!

再次关上docker logs查看,这次是满屏的字符飞滚,仿佛在做什么数据库降级的事件,然而为什么会不停地重启呢?

再次Google搜寻,说是Gitlab14.0版本当前引进了数据库migration机制,每次降级都必须要等到上一个版本的迁徙实现之后能力进行下一版本的降级,而且这个迁徙过程可能长达几小时甚至数天!

坏了,我必定是降级过快了,上一个版本还没倒腾完,我就开始升下一版本了。

当初怎么办?我脑子飞快运行。向老板报告劫难?向共事们抵赖失误?说我把你们的代码全搞丢了?

沉着沉着。我想了五分钟,这么的吧,看能不能降级降回14.0

于是我再次把docker-compose.yml里改成14.0。重新启动,祷告数据没有失落。

14.0总算是启起来了,然而当我拜访页面的时候:

这下麻烦大了!

强忍悲哀,关上docker logs看,没有线索,报告说一切正常。

但页面就是500啊!

网上有材料说,遇到500不要慌,进到容器外面看打量。好吧,docker exec -it进到容器外面,运行gitlab-ctl tail看输入,这边一刷新页面,日志外面就报告短少一个叫services的数据库表!

那不还是毁了吗?我这数据库弄不好升到一半,代码又是旧的,咋整?上又上不去,下又下不来,这下麻烦大了。

没方法,再次Google,终于找到了同命相怜的兄弟。听听他的血泪控告:

我从13.12降级到14.0.7,我认为迁徙曾经完结了,所有都失常了,于是我就进行了容器,升到14.2,后果启动不起来了,于是我就又退回到14.0.7,这回产生了500谬误,日志详情如下:
ActionView::Template::Error (PG::UndefinedTable: ERROR: relation "services" does not exist
并且我没有备份。

几乎跟我遇到的状况截然不同。底下有人说,Gitlab每次降级前会主动把数据库备份在backup文件夹上面,这哥们儿说并没有,我也去看了,也没有。

好在他提交的bug报告里有咱们中国兄弟解决了这事,就是这位:

办法居然如此简略:缓缓升!

既然快升会出问题,就缓缓升,先降级到14.1.1,等迁徙完结之后,再降级到14.2.1这样的。

抱着最初一丝心愿,再次把docker-compose.yml降级到14.1.1,启动。

等了五分钟之后,容器终于启动起来了。

关上浏览器,拜访网页,祷告不要再500了。

啊,长舒一口气,终于看到了相熟的页面。

可不敢乱动了。依照既定步骤,到管理员监控上面查看迁徙进度,果然有14个工作正在迁徙。等这14个工作迁徙实现,我开始思考下一步口头。

终于找到了问题的本源

然而我还是想降级到Gitlab 14.5,我感觉既然曾经站到14.1.1上了,而且迁徙实现了,应该后续不会太难,保险起见,还是先升到14.2.1,这次也胜利了。

我静静地期待迁徙实现,而后再升到14.9.0。其实还能够再升到14.10.0,然而先不必了,14.9.0曾经够用。

于是咱们从新回到Gitlab,将dind的环境变量设置好,再次编译,不行,网络MTU还是1500

再次搜寻对于dind设置MTU的问题,设置办法其实还是和以前一样,就是设置command就够了,而后查看docker network inspect bridge,然而这里的MTUifconfig查出来的MTU并不一样,docker network里尽管曾经是1400了,然而ifconfig里显示的还是1500,这代表什么含意呢?

我模糊地感觉到,这个docker桥接网络的MTU可能和里面并不需要统一,但无论如何,容器外面当初曾经是1400了,甚至能够更低,但无论如何总是和里面无奈通信,并且我还尝试了ping www.baidu.com也是能够ping通的,只有到咱们的内网服务器无奈ping通。

太累了,我先去睡个午觉。

醒来之后,躺在床上,我开始思考这个问题:如果我不增加dind服务,就能够ping通,如果我加上了,就ping不通,那阐明这个dind服务批改了我的网络配置。

我看到如果我不加dind的话,我这个容器是两块网卡,一块是eth0,一块是localhost,这种状况下是失常的,但当我加上dind服务后,容器里就产生了三块网卡,多了一个docker0,会不会是我的这个ping申请只能在eth0上工作,不能在docker0上工作,而当减少了dind服务之后,所有的ping申请都主动跑到了docker0下来了呢?我能不能强制让ping申请走eth0呢?

再次尝试:ping -I eth0 -c 10 gitlab.mydomain.com,这次胜利了!

那阐明问题就出在docker0这块网卡上。

因为有了它,所有网络申请都走了这块网卡,导致网络不通。

那为什么网络申请会走这块网卡呢?认真看它的IP设置,我忽然意识到了问题。docker0docker的桥接网络。

By default, Docker uses 172.17.0.0/16 subnet range.
缺省状况下,Docker应用172.17.0.0/16作为子网范畴。

而咱们的内网地址172.17.111.27刚好也是在这个网段内!

那么这就解释得通了,原先咱们采纳公网IP的时候没有问题,咱们的容器拜访www.baidu.com也没有问题,独独只有拜访咱们的内网服务器的时候有问题,因为咱们的内网服务器地址刚好和docker的缺省内网地址重合,所以所有的网络申请都被转发到了docker的桥接网络内,导致无奈与内网服务器通信!

最初的决战

咱们不可能也没有必要批改内网服务器的地址,当初要钻研的是如何批改docker的缺省子网地址。

网上所有的贴子都是说批改/etc/docker/daemon.json这个文件,然而咱们的容器里基本就没有这个文件,因为咱们是在容器外面再起一个dind的服务,必须让dind获得这个批改之后的设置才行,而gitlabservice设置很无限,不可能轻易批改service容器里的内容。

又是一番强烈的搜寻,最初在另外一个老哥那里找到了答案:

  variables:    DAEMON_CONFIG: '{"bip": "192.168.123.1/24"}'  services:    - name: docker:dind      entrypoint: ["/bin/sh", "-c", "mkdir -p /etc/docker && echo \"${DAEMON_CONFIG}\" > /etc/docker/daemon.json && exec dockerd-entrypoint.sh"]

原理也很简略:强行批改了dind这个服务的入口地址,在开始执行之前将咱们想要批改的内容写入daemon.json,这下docker的桥接网格docker0的网段不和咱们的内网网段重合了,应该就失效了。

依照这个办法批改之后,再次执行编译过程,当初咱们再ping gitlab.mydomain.com间接就能够ping通了,不须要再指定网卡,阐明整个网络曾经失常。

至此,终于彻底解决了这个困扰咱们三个月之久的问题:在kubernetes网络中装置gitlab runner并运行一个docker打包的工作


回忆解决问题的整个过程,还是在一开始的时候疏忽了网络环境变动这个最大的变量,走了很多弯路,在这个过程中,咱们理解了什么是MTU,理解了Gitlab应该如何降级,理解了Docker的桥接网络的设置。尽管吃了一点亏,但播种是微小的,从此咱们又能够畅通无阻地应用Gitlab来进行继续部署了。