我有一个系统(“主机”),使用 LXC(即“客户机”)运行多个容器。我在客户机中安装了 Jenkins,它们出现按照预期工作,除非他们不响应请求。 (我之前已经成功安装过几次 Jenkins,包括 LXC。)在这种情况下,观察到的问题是内置的 Jenkins Web 服务器(Jetty)没有响应 HTTP 请求,即使这些请求是从它正在运行的 LXC 客户机内部发出的,即指向localhost
。
我已经努力解决这个问题好几天了,但没有成功。
这是您尝试从以下位置联系 Jenkins Web 服务器时获得的信息localhost
:
root@base:~# curl -vI http://localhost:8080/jenkins/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> HEAD /jenkins/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
>
在正常工作的情况下,您应该会收到 HTTP-403,因为您尚未通过身份验证,并且回复时间不应超过一两秒,但即使过了几个小时,也没有回复。Jenkins 日志文件也没有报告任何错误。
我需要帮助来找出该问题的根本原因并解决它,以便 Jenkins 安装能够按预期工作并可访问。
有没有什么指点可以说明在哪里可以找到并修复这个问题?
以下是我已经研究过的一些内容:
- 詹金斯配置:配置文件
/etc/default/jenkins
与我的其他工作设置类似,并且只有很少的变化(例如,仅绑定到本地主机和前缀)。 - Apache 配置:我检查了 Apache 反向代理配置,并与其他正常工作的系统进行了比较,但这不是问题。此外,Apache 始终可以访问(例如“它有效!”页面),即使在 LXC 容器外部也可以访问,因此流量不会被防火墙规则阻止。Apache 会失败,HTTP-502 代理错误因为 Jenkins 不会回复它。(话虽如此,我已经卸载了 Apache 以简化环境。)
- 日志文件:Jenkins 日志文件
/var/log/jenkins/jenkins.log
没有报告任何问题,这些问题通常会显示为异常的 Java 堆栈跟踪。 - 防火墙规则(
iptables -S
):所有链/规则(INPUT
、FORWARD
和OUTPUT
)都设置为ACCEPT
。不过,由于此处的通信是在范围内localhost
,因此即使存在其他防火墙规则,我也不认为会出现问题。 - 网络数据包和端口(
netstat -tapon
):显示 Jenkins(java 进程)正在监听预期端口(默认为 8080,但我尝试过其他端口);在客户端发送如上所示的请求ESTABLISHED
后,它还显示连接为(两端均连接) 。这表示 TCP 握手成功。curl
- 网络流量(
tcpdump -i lo
):显示正在进行的三次握手;它解释了为什么netstat
显示连接为ESTABLISHED
。 - 与工作设置比较:我所做的其他 Jenkins 安装具有类似的环境和配置(例如 Ubuntu 18.04 主机、对 Jenkins 配置文件的相同更改、安装程序等)。
- 重现问题:我尝试过(并且失败的)在其他系统中重现该问题;我使用了完全相同的环境、安装过程、配置等(例如我的笔记本电脑、工作中的独立服务器、家中的独立服务器、相同的 LXC 版本、匹配的客户操作系统映像指纹等);一切都按预期工作外部有问题的生产服务器(Dell PowerEdge R640 服务器)。
- 从轨道1轰炸该系统:我已多次从头销毁/重建所有容器(包括销毁存储所有数据的 ZFS 池);但这并没有什么区别。
- 直接在主机上安装:我已经确认直接在主机上安装 Jenkins(即在任何 LXC 容器/客户机之外)也会出现该问题。
- 排除 Java/JVM:我可以确认其他基于 Java 的应用程序可以正常工作,所以它确实不是似乎是影响任何/所有基于 Java 的程序的问题。(我通过设置 Apache Tomcat 服务器对此进行了测试,结果如预期的那样运行。)
- 重新定位主机:为了排除潜在的数据中心环境问题,我将服务器移到了我的办公桌区域,那里有另一台可以正常工作的测试服务器。这没什么区别。
- 运行独立 Jetty:我找到了与 Jenkins 捆绑版本最接近的 Jetty 服务器版本。无法重现该问题。独立Jetty 服务器按预期响应请求,但与 Jenkins 捆绑在一起的服务器仍然没有响应。(Jenkins 的 Jetty 版本在日志中报告为
jetty-9.4.z-SNAPSHOT; built: 2018-06-05T18:24:03.829Z
。网站上没有这个.z-SNAPSHOT
名称的版本Jetty 发布页面,因此我使用了基于构建日期的最接近的匹配来进行此测试9.4.11.v20180605
:) - 从 OpenJRE 切换到 Oracle JRE:安装/设置要使用的 Oracle JRE(即
update-alternatives --config java
)。观察到相同的无响应行为。
有些问题我已经看过,但是不相关或者没有帮助:
- 无法访问 Jenkins 服务器
- 无法使用 nginx 访问 Jenkins
- 为 Jenkins 和 Sonar 使用 SSL 更正 Apache 反向代理配置
- 访问詹金斯时出现代理错误
- 反向代理 Linux 容器
我读过的书远不止这些;它们只是一个样本。
1这是唯一可以确定的方法……大多数情况下……
答案1
以下是对同一问题的更详细解释 https://issues.jenkins-ci.org/browse/JENKINS-33412
以前的 Jenkins 版本将底层 jetty 使用的线程数限制为 40(handlerCountMax 选项)。默认情况下,jetty 使用 Runtime.getRuntime().availableProcessors()/2 线程作为选择器。如果 CPU 核心数足够高(例如 70)或 jetty ssl 连接器也启动并且 CPU 核心数超过 36,则线程将耗尽并且 http 请求会卡住。考虑迁移到最新的 jenkins 并手动定义 jetty 的线程数 - 检查这些 jetty 参数 - qtpMaxThreadsCount、jettyAcceptorsCount、jettySelectorsCount。
答案2
总结
如果有70 或以上托管 Jenkins 的系统 CPU 不足,则 Jenkins/Jetty 会卡住并且无法工作。请确保运行 Jenkins 的系统/容器具有少于 70可用的 CPU 或将您的 Jenkins 安装升级到至少 2.138。2,已于今日(2018-10-10)发布。
概括
事实证明 Jenkins 2.138。1Ubuntu 18.04 LTS 存储库中的 Jenkins/Jetty 存在一个错误,导致在具有 70 个或更多 CPU 的系统上 Jenkins 2.138 没有响应。2于2018年10月10日今天发布,它修复了几个潜在问题,其中一个导致了我遇到的问题。
变更日志如下这里。对我来说关键的修复是这个:
我可以确认这个错误修复确实解决了该问题,并在我的具有 72 个 CPU 的服务器上验证了这一点。
如果您(暂时)无法升级您的 Jenkins 安装,请继续阅读以了解可能的解决方法。
解决方法(针对容器)
如果您在 LXC 内部安装 Jenkins,那么您可以使用以下命令来控制它:
lxc config set <container> limits.cpu N
,其中N < 70
;并且lxc exec <container> -- systemctl restart jenkins.service
您可能还需要更新配置文件配置,您可以按如下方式操作:
lxc profile set <container-profile> limits.cpu N
具有与上面相同的注意事项。如果您使用的是虚拟机(例如 VirtualBox、VMware 等),那么您仍然可以设置虚拟机可用的 CPU 数量。
附言:感谢 Pavel他的帖子,这让我朝着正确的方向去尝试 CPU/核心数量。