GitLab-runner使用podman执行器时内部容器网络异常排查
问题背景
- 本地执行
podman play kube pod.yaml可正常启动Pod,应用运行正常 - 在以podman为执行器的GitLab-runner环境执行相同命令时出现多类网络异常
- GitLab runner版本:14.9.2(CI runner)、15.0.0(本地GitLab runner)
- 已配置参数:启动gitlab-runner时添加
--privileged与--network=host参数,Pod配置中设置hostNetwork: true与privileged: true
现象汇总
- GitLab-runner内启动的容器无法访问外部网络(无法执行软件包安装等操作),但GitLab-runner容器自身可正常访问外部网络
- 无论在GitLab-runner环境还是本地环境,访问
POD_NAME:8080/均提示connection refused;宿主机直接访问localhost:8080可正常加载页面,runner环境内访问localhost:8080提示“No route to host” - 两类环境启动的容器
/etc/hosts配置存在明显差异 - 同Pod内容器可通过所有端口互相访问,该特性在两类环境中均生效
本地环境容器/etc/hosts内容
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.88.0.113 cqe dd88a3440675-infra 127.0.1.1 cqe cqe-dispatcher 127.0.1.1 cqe cqe-umbsender 127.0.1.1 cqe cqe-frontend 127.0.1.1 cqe cqe-db 127.0.1.1 cqe cqe-umbreader
GitLab-runner内容器/etc/hosts内容
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.88.0.117 runner--project-0-concurrent-0 runner--project-0-concurrent-0-d244dbca3614d5aa-build-2 10.88.0.2 cqe 4a46f7216e30-infra 10.88.0.1 host.containers.internal 10.88.0.117 host.containers.internal
测试用Pod网络相关配置
apiVersion: v1 kind: Pod metadata: labels: name: cqe spec: hostNetwork: true privileged: true restartPolicy: Always containers: - name: db - name: frontend securityContext: runAsUser: 5000 runAsGroup: 5000 ports: - containerPort: 8080 hostPort: 8080 protocol: TCP - name: dispatcher securityContext: runAsUser: 5000 runAsGroup: 5000 - name: umbreader workingDir: /clusterqe-django securityContext: runAsUser: 5000 runAsGroup: 5000 - name: umbsender workingDir: /clusterqe-django securityContext: runAsUser: 5000 runAsGroup: 5000
问题根因与解答
1. GitLab-runner内启动的容器无法访问外部网络的原因
核心原因是嵌套容器场景下Pod配置的hostNetwork: true未实际生效。
- 本地裸金属环境运行podman时,podman有权限直接操作宿主机网络命名空间,
hostNetwork: true参数生效,Pod直接复用宿主机网络栈,可以正常访问外网。 - GitLab-runner本身是运行在宿主机上的容器,其内部安装的podman属于嵌套运行的容器引擎。即使给runner配置了
--privileged和--network=host,runner内部的podman默认仍会创建独立的CNI网桥(即10.88.0.0/16网段的内部网络)给启动的Pod使用,不会真正复用外层宿主机的网络栈。 - 这种场景下,内部CNI网桥的流量没有配置对应的iptables源地址转换(MASQUERADE)规则,同时runner容器默认未开启IP转发,导致10.88.0.0/16网段的Pod流量无法转发到外部网络,自然无法访问外网。而runner容器本身直接使用宿主机网络,所以自身外网访问正常。
2. 无法通过Pod名访问暴露端口的原因
两类环境下该问题的根因不同:
- 本地环境:
hostNetwork生效时,podman会自动在每个容器的/etc/hosts中添加127.0.1.1 <Pod名> <容器名>的解析条目,但127.0.1.1属于容器自身的回环地址。部署的frontend服务是绑定在宿主机网络栈的8080端口,不是绑定在每个业务容器自身回环的8080端口,访问解析到127.0.1.1的Pod名时自然会提示connection refused。 - GitLab-runner环境:
hostNetwork未生效,podman给Pod创建了独立的网络命名空间,/etc/hosts中Pod名cqe解析到10.88.0.2,这是Pod的infra容器(仅用于持有网络命名空间的基础容器)的IP,infra容器本身不运行任何业务服务,也没有做8080端口的映射,访问该IP的8080端口必然被拒绝。 - 额外说明:同Pod内的容器共享网络命名空间,直接访问
localhost:端口即可访问同Pod其他容器的服务,不需要通过Pod名访问。
3. 两类环境/etc/hosts配置存在差异的原因
差异完全来自hostNetwork参数是否生效:
- 本地环境
hostNetwork生效,Pod没有独立的网络命名空间和独立CNI IP,podman会按照hostNetwork模式的规则生成hosts文件:将Pod名、各容器名解析到127.0.1.1的本地回环地址,infra条目解析到宿主机在CNI网桥的IP。 - GitLab-runner内
hostNetwork未生效,Pod被分配了独立的CNI网段IP,podman按照默认bridge网络模式生成hosts文件:将Pod名解析到infra容器的独立IP,额外添加host.containers.internal条目用于访问宿主机,和hostNetwork模式的生成逻辑完全不同。
修复方案
- 优先方案:启动GitLab-runner时,将宿主机的podman socket(
/run/podman/podman.sock)、容器存储目录(/var/lib/containers)挂载进runner容器,让runner内的podman命令直接调用宿主机的podman服务,避免嵌套运行容器引擎,hostNetwork等参数就可以和本地环境表现一致。 - 若必须使用嵌套podman:需要在runner容器内部开启IP转发,配置CNI网桥的iptables MASQUERADE规则,允许10.88.0.0/16网段的流量转发到外网;同时在Pod配置中添加
hostAliases,将Pod名解析到127.0.0.1,即可通过Pod名访问同Pod服务。 - 同Pod服务访问统一使用
localhost:端口的方式,不要依赖Pod名解析,避免不同环境下解析规则差异导致的异常。
内容的提问来源于stack exchange,提问作者hrondor
相关产品推荐
相关产品推荐

