一次京东云NAT网络下的gitlab-ci错误排查
背景
由于历史原因,我们是京东云的大客户,关于京东云,可以说是又爱又恨,我们作为早期客户,没少踩坑,随着京东云这几年逐步走向正轨,产品也是越来越稳定,功能也越来越丰富,衷心的希望我们的合作能够一直保持。
我年初加入公司后,发现公司IT建设较落后,所以下大力气开始进行改造,将代码从svn迁移到git,是所有后续工作的基础,这里我选用了自建gitlab作为git管理工具,并为每个项目编写了gitlab-ci,用来做提交代码后的编译检查。
由于种种原因,最开始只有一台服务器,除了gitlab,还有跑runner、jenkins、registry、sentry等工具和服务,虽然都是通过docker架设的,但稳定性也是相当让人堪忧,所以最近将gitlab和runner进行了迁移。
为了拆分这些服务,我在京东云上搭建了基于nat的vpc,服务器A作为nat网关暴露在公网上,其他服务访问外网均通过服务器A完成,外部访问内网服务则全通过服务器A的反向代理实现,gitlab是一台内网独立的ecs,runner也是独立的一台ecs。反向代理、ssh tunnel全部配置完成后,基本访问和提交代码全都正常,但是runner注册后,问题来了。
问题
我的gitlab-ci用的runner,是通过如下配置进行注册的:
docker run --rm -v /root/gitlab-runner/${name}/config:/etc/gitlab-runner gitlab/gitlab-runner register \
--non-interactive \
--executor "docker" \
--docker-image "alpine:latest" \
--url "http://xxxxx/" \
--registration-token "token" \
--description "${name}" \
--tag-list "${taglist}" \
--run-untagged="true" \
--locked="false"
我的gitlab-ci是这样写的:
image: maven:3.6.0-jdk-8
stages:
- build
- test
variables:
MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode"
cache:
paths:
- .m2/repository/
- target/
build:
stage: build
script:
- mvn $MAVEN_CLI_OPTS compile
test:
stage: test
script:
- mvn $MAVEN_CLI_OPTS test -Ptest -DargLine="-Djdk.net.URLClassPath.disableClassPathURLCheck=true"
其中settings.xml文件里配置了阿里云的maven仓库镜像。
当在runner中执行mvn命令时,会发现所有的jar包依赖,均不能下载,全部卡住。当我把阿里云的maven镜像换成官方中央仓库的地址,一切正常。经过反复实验,发现阿里云的maven镜像用的是https,而官方中央仓库用的是http。
接着curl了https://www.baidu.com,也是卡住。随便找了个jar包,通过wget下载,http的可以正常下载,而https的全都卡住,telnet了443端口,是通的。由此,基本可以判断为证书检查出了问题,wget加上–no-check-certificate参数,一切正常,看来果然是证书的问题。
问题:京东云nat网络下,内网ecs的docker容器内,访问https的资源,会有证书问题,导致资源不能正常加载,一直卡住。使用mvn命令,没有任何错误提示,其他命令没有尝试。
解决方法
通过现象,基本可以判断为docker的网络环境配置的问题,知道了原因,解决起来就简单了。
既然是网络问题,那就让docker直接接在主机的网络上,不使用默认的bridge网络。
停止所有runner,修改注册runner的脚本,增加–docker-network-mode “host”,如下:
docker run --rm -v /root/gitlab-runner/${name}/config:/etc/gitlab-runner gitlab/gitlab-runner register \
--non-interactive \
--executor "docker" \
--docker-image "alpine:latest" \
--docker-network-mode "host" \
--url "http://xxxxxx/" \
--registration-token "token" \
--description "${name}" \
--tag-list "${taglist}" \
--run-untagged="true" \
--locked="false"
重新注册runner后,阿里云的jar包依赖终于可以正常下载了:)
总结
这个问题着实让我慌了一下,google了半天,一直没有找到解法,由于网络知识的匮乏,导致一开始就没往网络这方面想,直到咨询了京东云的技术人员,才知道可能是网络的问题。
事实证明,解决任何问题,应该先怀疑自己,再怀疑其他,尤其是成熟的技术和应用。很多事情,往往都是源于自己的无知。
至于为什么多层nat下会出现证书问题,是京东云的问题,还是docker默认的bridge网络问题?还是二者一结合就这样?这恐怕得等把nat学明白了再下结论了。