konakona
Dream Afar.
konakona
Helm Gitlab Runner pipeline curl: (6) Could not resolve host

最近遇到了一个奇妙的问题,在Kubernetes中的Gitlab runner网络不稳定。

pipeline(docker:bind)在stage执行docker build时,从阿里云镜像获取依赖巨慢无比,一次都没有完成过。

从构建中的runner pod 内 ping阿里云镜像的地址mirrors.aliyun.com是Bad address。这种奇怪的现象让我头大了2天。最后发现一切与/etc/resolv.conf里的ndots有关……小小的参数,杀伤力怎么那么大呢?

#Dockerfile

FROM daocloud.io/php:7.2-fpm-alpine
# 阿里镜像
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

apk update ...
https://blog.img.crazyphper.com/2020/04/image-3.png
pipeline执行1小时都做不完PHP的环境部署,不规律的不稳定,有的时候卡在拿gcc,有的时候卡在拿gd

起初我怀疑是集群内kube-dns运作出现了问题,准备了一个busybox试验。

# 安装一个旧版busybox,注意新版有bug
kubectl run busybox --image=busybox:1.28.3

# 让其检查各种不通的域名解析如何
kubectl get pod | grep busybox |awk '{system("kubectl exec "$1" nslookup mirrors.aliyun.com")}' 

kubectl get pod | grep busybox |awk '{system("kubectl exec "$1" nslookup blog.crazyphper.com")}' 
https://blog.img.crazyphper.com/2020/04/image-4-800x445.png
busybox vs pipeline

执行结果对比,busybox OK,说明集群本身没有问题。

我在宿主机的/etc/resolv.conf里增加2枚阿里云内网DNSIP,无效。

我在宿主机的/etc/docker/daemon.json里增加了DNS,无效。

vim /etc/docker/daemon.json

#增加dnspod的dns IP
"dns": ["119.29.29.29"]

vim /etc/resolv.conf

# 增加了这2行阿里云内网DNS
nameserver 100.100.2.138
nameserver 100.100.2.136


# 更新配置
systemctl daemon-reload

CoreDNS默认会将pod所在宿主机上的/etc/resolv.conf拿去使用(kube-dns同理),这次怎么没起作用呢?

https://blog.img.crazyphper.com/2020/04/image-5-4.png

使用docker exec -ti [runner容器id] --user root sh 以root权限进入容器排查:

https://blog.img.crazyphper.com/2020/04/image-5-1.png
ping kube-dns 10.96.0.10(失败)
ping 自己的博客(成功)
ping 阿里镜像(失败)

我惊了。

我将阿里云内网2枚DNS IP加入到/etc/resolv.conf中,再次ping 阿里镜像,发现可以了。

问题进入白热化……Gitlab本身应该没有对runner起什么作用,因为Gitlab是用docker-compose安装在服务器上,runner使用helm安装在集群内部,由集群进行编排。

Gitlab docs中搜索dns、nameserver关键字没有任何结果或者配置项,这也是为何我在Gitlab这个方向上毫无进展的原因。

经过大量的搜索,在下边这些链接中,我找到了原因:

发现了“罪魁祸首”——ndots。runner我设置为hostNetwork:true将优先请求集群所在域查询。

#runner-value.yaml
hostNetwork: true

在Kubernetes中,可以针对每个Pod设置DNS的策略dnsPolicy字段可以指定相应的策略,目前支持的策略如下:

  • Default: Pod继承所在宿主机的设置,也就是直接将宿主机的/etc/resolv.conf内容挂载到容器中。
  • ClusterFirst: 默认的配置,所有请求会优先在集群所在域查询,如果没有才会转发到上游DNS。
  • ClusterFirstWithHostNet: 和ClusterFirst一样,不过是Pod运行在hostNetwork:true的情况下强制指定的。
  • None: 1.9版本引入的一个新值,这个配置忽略所有配置,以Pod的dnsConfig字段为准。

kube-dns默认会给pod内的/etc/resolv.conf 设置ndots:5。这意味着任何包含少于5个.(点)的解析请求都将在所有搜索域中循环并试图解析。整个ndots就像一个神秘花园,扰乱了请求。

想要知道一个域名有几个.使用host domain命令。

https://blog.img.crazyphper.com/2020/04/image-5-2.png
可以看到阿里镜像只有3个点的报文

这也是为什么在runner构建的容器中可以ping通我的博客,却ping不到阿里镜像的原因,之一。

这与我安装的runner镜像版本有关image:gitlab/gitlab-runner:alpine-v12.5.0。alpine轻便,但是它对于遵循FQDN标准要求更加严格。可以使用尾随点.来绕过/etc/resolv.conf 的ndots

https://blog.img.crazyphper.com/2020/04/image-5-3.png
虽然绕过了ndots,仍然有解析问题,而且成功率低

我对这个解决办法并不满意,一个Dockerfile会从很多地方获取依赖,有些地方还是隐式的,无法修改。

可以通过安装非alpine版runner来解决,v12.1.0这个版本亲测可行,安装最新版会出现各种权限问题。

# 编辑runner的chart
vim values.yaml

#image: gitlab/gitlab-runner:alpine-v12.5.0
#使用这一镜像
image: gitlab/gitlab-runner:v12.1.0
#如果仍然不行,可以加上这个配置,让pod直接挂载宿主机的/etc/resolv.conf
#dnsPolicy: "Default"

#保存退出后,更新部署
helm upgrade --namespace kube-system -f gitlab-runner/values.yaml gitlab-runner gitlab/gitlab-runner

问题终于解决。

但是效率仍然不够友好,我希望在10分钟内完成一次CICD。

归根结底,应该是Kubernetes+Gitlab(Docker)+Gitlab Runner(Helm)这套组合对于PHP这类依赖编译项多的程序不够友好。这套组合对于JAVA却非常适合,因为依赖极少,在我之前的JAVA程序为首的集群中运行良好。

之后,我又对GitLab Runner进行了调试与优化,将它改成docker run的形式运作,每次CICD的时间平均稳定在8-10分钟。

https://blog.img.crazyphper.com/2020/04/image-5-5-800x275.png

赞赏
首页      程序开发      Linux      DevOps      Helm Gitlab Runner pipeline curl: (6) Could not resolve host

团哥

文章作者

继续玩我的CODE,让别人说去。 低调,就是这么自信。

发表评论

textsms
account_circle
email

konakona

Helm Gitlab Runner pipeline curl: (6) Could not resolve host
最近遇到了一个奇妙的问题,在Kubernetes中的Gitlab runner网络不稳定。 pipeline(docker:bind)在stage执行docker build时,从阿里云镜像获取依赖巨慢无比,一次都没有完成过。 从…
扫描二维码继续阅读
2020-04-16