GitLab Auto DevOps on Kubernetes 挂起,网络超时,无法执行yj
GitLab Auto DevOps on Kubernetes hangs, network timeouts, cannot execute yj
使用 GitLab Auto DevOps to build and deploy application from my repository to microk8s 时,构建作业通常需要很长时间才能 运行,最终超时。该问题在 99% 的情况下都会发生,但有些构建 运行 可以解决。通常,构建在构建脚本中的不同时间停止。
项目不包含 .gitlab-ci.yml
文件,完全依赖 Auto DevOps 功能发挥其魔力。
对于 Spring Boot/Java 项目,通过 Gradle 包装器下载 Gradle 时构建经常失败,有时在下载依赖项本身时也会失败。错误信息非常模糊,一点帮助也没有:
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in e9ec110c0dfe
-----> Gradle app detected
-----> Spring Boot detected
The command '/bin/sh -c /bin/herokuish buildpack build' returned a non-zero code: 35
有时候,运气好的话,错误是不一样的:
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in fe284971a79c
-----> Gradle app detected
-----> Spring Boot detected
-----> Installing JDK 11... done
-----> Building Gradle app...
-----> executing ./gradlew build -x check
Downloading https://services.gradle.org/distributions/gradle-7.0-bin.zip
..........10%...........20%...........30%..........40%...........50%...........60%...........70%..........80%...........90%...........100%
To honour the JVM settings for this build a single-use Daemon process will be forked. See https://docs.gradle.org/7.0/userguide/gradle_daemon.html#sec:disabling_the_daemon.
Daemon will be stopped at the end of the build
> Task :compileJava
> Task :compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Could not download netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar (io.netty:netty-resolver-dns-native-macos:4.1.65.Final)
> Could not get resource 'https://repo.maven.apache.org/maven2/io/netty/netty-resolver-dns-native-macos/4.1.65.Final/netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar'.
> Could not GET 'https://repo.maven.apache.org/maven2/io/netty/netty-resolver-dns-native-macos/4.1.65.Final/netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar'.
> Read timed out
对于 React/TypeScript 问题,症状相似,但错误本身以不同的方式出现:
[INFO] Using npm v8.1.0 from package.json
/cnb/buildpacks/heroku_nodejs-npm/0.4.4/lib/build.sh: line 179: /layers/heroku_nodejs-engine/toolbox/bin/yj: Permission denied
ERROR: failed to build: exit status 126
ERROR: failed to build: executing lifecycle: failed with status code: 145
问题似乎主要发生在 GitLab 运行ners 本身部署在 Kubernetes 中时。 microk8s 使用 Project Calico 实现虚拟网络。
什么给了?为什么错误消息毫无帮助?有没有办法显示详细的构建日志或调试构建步骤?
这似乎是由 Calico 网络层和 Docker 的网络配置之间的不兼容 MTU 设置引起的网络问题(以及无法正确自动配置 MTU?)当 MTU 值不正确时匹配,网络数据包变得碎片化,Docker runners 无法完成 TLS 握手。据我了解,这只会影响 DIND (docker-in-docker) 跑步者。
即使找到这个也需要跳过几个环节。你必须:
- 启动 CI 管道并等待作业“挂起”
kubectl exec
进入 current/active GitLab runner pod
- 找出
DOCKER_HOST
环境变量的正确值(例如通过 grepping /proc/$pid/environ
。很可能是 tcp://localhost:2375
。
- 导出
docker
客户端使用的值:export DOCKER_HOST=tcp://localhost:2375
docker ps
然后 docker exec
进入实际的 CI 作业容器
- 使用 ping 和其他工具找到合适的 MTU 值(但是 MTU 是什么?Docker、Calico、OS、路由器,...?)。使用 curl/openssl 验证(某些)https 站点是否从 DIND 容器内部引起问题。
执行
microk8s kubectl get -n kube-system cm calico-config -o yaml
并查找 veth_mtu
值,该值很可能会设置为 1440
。 DIND 使用相同的 MTU,因此无法发送或接收某些网络包(每个虚拟网络需要将自己的 header 添加到网络包中,这会在每一层添加几个字节)。
天真的解决方法是将 Calico 设置更改为更高或更低的值,但不知何故这并没有真正起作用,即使在 Calico 部署之后也是如此。此外,该值似乎不时重置为原始值;可能是由 microk8s 的自动更新引起的(作为 Snap)。
那么什么是真正有效且永久的解决方案呢?可以通过编写自定义 .gitlab-ci.yml
文件并简单地包含 Auto DevOps 模板来覆盖 Auto DevOps 的 DIND 设置:
build:
services:
- name: docker:20.10.6-dind # make sure to update version
command: ['--tls=false', '--host=tcp://0.0.0.0:2375', '--mtu=1240']
include:
- template: Auto-DevOps.gitlab-ci.yml
build.services
定义是从 Jobs/Build.gitlab-ci
模板复制而来的,并使用额外的 --mtu
选项进行了扩展。
到目前为止,我通过将 DIND MTU 设置为 1240 获得了很好的体验,这比 Calico 的 MTU 低 200 字节。作为一个额外的好处,它不会影响任何其他 pods' 网络设置。对于 CI 构建,我可以接受 non-optimal 网络设置。
参考文献:
使用 GitLab Auto DevOps to build and deploy application from my repository to microk8s 时,构建作业通常需要很长时间才能 运行,最终超时。该问题在 99% 的情况下都会发生,但有些构建 运行 可以解决。通常,构建在构建脚本中的不同时间停止。
项目不包含 .gitlab-ci.yml
文件,完全依赖 Auto DevOps 功能发挥其魔力。
对于 Spring Boot/Java 项目,通过 Gradle 包装器下载 Gradle 时构建经常失败,有时在下载依赖项本身时也会失败。错误信息非常模糊,一点帮助也没有:
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in e9ec110c0dfe
-----> Gradle app detected
-----> Spring Boot detected
The command '/bin/sh -c /bin/herokuish buildpack build' returned a non-zero code: 35
有时候,运气好的话,错误是不一样的:
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in fe284971a79c
-----> Gradle app detected
-----> Spring Boot detected
-----> Installing JDK 11... done
-----> Building Gradle app...
-----> executing ./gradlew build -x check
Downloading https://services.gradle.org/distributions/gradle-7.0-bin.zip
..........10%...........20%...........30%..........40%...........50%...........60%...........70%..........80%...........90%...........100%
To honour the JVM settings for this build a single-use Daemon process will be forked. See https://docs.gradle.org/7.0/userguide/gradle_daemon.html#sec:disabling_the_daemon.
Daemon will be stopped at the end of the build
> Task :compileJava
> Task :compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Could not download netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar (io.netty:netty-resolver-dns-native-macos:4.1.65.Final)
> Could not get resource 'https://repo.maven.apache.org/maven2/io/netty/netty-resolver-dns-native-macos/4.1.65.Final/netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar'.
> Could not GET 'https://repo.maven.apache.org/maven2/io/netty/netty-resolver-dns-native-macos/4.1.65.Final/netty-resolver-dns-native-macos-4.1.65.Final-osx-x86_64.jar'.
> Read timed out
对于 React/TypeScript 问题,症状相似,但错误本身以不同的方式出现:
[INFO] Using npm v8.1.0 from package.json
/cnb/buildpacks/heroku_nodejs-npm/0.4.4/lib/build.sh: line 179: /layers/heroku_nodejs-engine/toolbox/bin/yj: Permission denied
ERROR: failed to build: exit status 126
ERROR: failed to build: executing lifecycle: failed with status code: 145
问题似乎主要发生在 GitLab 运行ners 本身部署在 Kubernetes 中时。 microk8s 使用 Project Calico 实现虚拟网络。
什么给了?为什么错误消息毫无帮助?有没有办法显示详细的构建日志或调试构建步骤?
这似乎是由 Calico 网络层和 Docker 的网络配置之间的不兼容 MTU 设置引起的网络问题(以及无法正确自动配置 MTU?)当 MTU 值不正确时匹配,网络数据包变得碎片化,Docker runners 无法完成 TLS 握手。据我了解,这只会影响 DIND (docker-in-docker) 跑步者。
即使找到这个也需要跳过几个环节。你必须:
- 启动 CI 管道并等待作业“挂起”
kubectl exec
进入 current/active GitLab runner pod- 找出
DOCKER_HOST
环境变量的正确值(例如通过 grepping/proc/$pid/environ
。很可能是tcp://localhost:2375
。 - 导出
docker
客户端使用的值:export DOCKER_HOST=tcp://localhost:2375
docker ps
然后docker exec
进入实际的 CI 作业容器- 使用 ping 和其他工具找到合适的 MTU 值(但是 MTU 是什么?Docker、Calico、OS、路由器,...?)。使用 curl/openssl 验证(某些)https 站点是否从 DIND 容器内部引起问题。
执行
microk8s kubectl get -n kube-system cm calico-config -o yaml
并查找 veth_mtu
值,该值很可能会设置为 1440
。 DIND 使用相同的 MTU,因此无法发送或接收某些网络包(每个虚拟网络需要将自己的 header 添加到网络包中,这会在每一层添加几个字节)。
天真的解决方法是将 Calico 设置更改为更高或更低的值,但不知何故这并没有真正起作用,即使在 Calico 部署之后也是如此。此外,该值似乎不时重置为原始值;可能是由 microk8s 的自动更新引起的(作为 Snap)。
那么什么是真正有效且永久的解决方案呢?可以通过编写自定义 .gitlab-ci.yml
文件并简单地包含 Auto DevOps 模板来覆盖 Auto DevOps 的 DIND 设置:
build:
services:
- name: docker:20.10.6-dind # make sure to update version
command: ['--tls=false', '--host=tcp://0.0.0.0:2375', '--mtu=1240']
include:
- template: Auto-DevOps.gitlab-ci.yml
build.services
定义是从 Jobs/Build.gitlab-ci
模板复制而来的,并使用额外的 --mtu
选项进行了扩展。
到目前为止,我通过将 DIND MTU 设置为 1240 获得了很好的体验,这比 Calico 的 MTU 低 200 字节。作为一个额外的好处,它不会影响任何其他 pods' 网络设置。对于 CI 构建,我可以接受 non-optimal 网络设置。
参考文献: