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
容器缺省的 MTU
是1500
,在某种状况下会导致网络传输不稳固,跟咱们遇到的这个症状很类似。
最大传输单元 (
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 搜寻,说是 Gitlab
从14.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
,然而这里的MTU
和ifconfig
查出来的 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
设置,我忽然意识到了问题。docker0
是 docker
的桥接网络。
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
获得这个批改之后的设置才行,而 gitlab
的service
设置很无限,不可能轻易批改 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
来进行继续部署了。😄