Jenkins docker下JNLP slave节点远程连接报错port not reachable的解决

本文探讨了在Docker环境下,Jenkins Master运行于物理机容器中,使用JNLP协议连接Slave节点时遇到的"port not reachable"错误。问题的根本原因是Master容器使用了桥接网络模式,导致Slave无法连接。解决方案是将Master容器切换到host模式,并通过设置环境变量`JENKINS_SLAVE_AGENT_PORT`和`JENKINS_OPTS`来指定端口,从而实现多个Master容器在同一物理机上运行并正确通信。
摘要由CSDN通过智能技术生成

场景

jenkins master运行在物理机A的容器a中,jenkins agent运行在物理机B的容器b上,A和B是同一个局域网
当使用JNLP协议时,agent启动,主动连接master时闪退,报错port not reachable。(可能的表现:不用websocket连接则必然闪退;如果给节点连接启用websocket,则可能能连上,但很容易断开)

报错信息类似这样

baozhenchen@SC02CW70JMD6T Documents % java -jar agent.jar -jnlpUrl http://10.12.78.42:9001/computer/ccc/slave-agent.jnlp -secret a199192028ed581db11ca1a2a435e5c8fedb88ed948c7eb37edb4ad302908f39 -auth jagent:jagent -workDir "~/workspace"
十一月 22, 2020 3:28:09 下午 org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir
信息: Using ~/workspace/remoting as a remoting work directory
十一月 22, 2020 3:28:09 下午 org.jenkinsci.remoting.engine.WorkDirManager setupLogging
信息: Both error and output logs will be printed to ~/workspace/remoting
十一月 22, 2020 3:28:10 下午 hudson.remoting.jnlp.Main createEngine
信息: Setting up agent: ccc
十一月 22, 2020 3:28:10 下午 hudson.remoting.jnlp.Main$CuiListener <init>
信息: Jenkins agent is running in headless mode.
十一月 22, 2020 3:28:10 下午 hudson.remoting.Engine startEngine
信息: Using Remoting version: 4.2
十一月 22, 2020 3:28:10 下午 org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir
信息: Using /Users/baozhenchen/Documents/~/workspace/remoting as a remoting work directory
十一月 22, 2020 3:28:10 下午 hudson.remoting.jnlp.Main$CuiListener status
信息: Locating server among [http://10.12.78.42:9001/]
十一月 22, 2020 3:28:10 下午 org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver resolve
信息: Remoting server accepts the following protocols: [JNLP4-connect, Ping]
十一月 22, 2020 3:28:10 下午 org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver isPortVisible
警告: Connection refused (Connection refused)
十一月 22, 2020 3:28:10 下午 hudson.remoting.jnlp.Main$CuiListener error
严重: http://10.12.78.42:9001/ provided port:9101 is not reachable
java.io.IOException: http://10.12.78.42:9001/ provided port:9101 is not reachable
	at org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.resolve(JnlpAgentEndpointResolver.java:314)
	at hudson.remoting.Engine.innerRun(Engine.java:690)
	at hudson.remoting.Engine.run(Engine.java:518)

如果agent在物理机A中的容器启动(和master同一台物理机),则可以成功连接

根本原因

jenkins master容器使用的是bridge的网络模式,导致不能在主机以外连接jnlp。

agent会先尝试连接jenkins master的HTTP端口,这个端口因为做了映射,可以正确访问。通过HTTP端口来得知jenkins master的jnlp端口和ip地址。
而master不知道自己在容器里运行,他告知agent客户端的主机ip地址在bridge网络模式下是内网地址,只有物理机A可见,对于物理机B来讲不可访问,因而连接失败(报错有误导性)。
这个错误,和redis集群、couchbase集群不能使用bridge,要求使用host模式连接的道理是一样的。

jenkins master容器改为host模式连接就可以解决问题。

验证猜想

当我改为host模式,且不映射端口号时,agent通过访问物理机的8080端口,就可以正确的连上jenkins master,因而验证了jenkins master必须采用host网络模式部署的猜想。

但是,这里有个困难,host模式不支持端口映射,在物理机A上如果启动多个jenkins master容器,则端口号会冲突,不能满足我的定制端口号的需求。因而若要在主机A上面启动两个jenkins master,就只能通过注入环境变量的方式修改启动命令。

搜索过jenkins修改端口号,发现要更改jenkins配置文件。但要在容器启动前修改配置文件(还要持久化,要么就重新打一个容器–但又不通用),这样复杂的操作并不理想。

谷歌之,发现解法不好找,主要是提出这类问题的人很多,但是各种解决方案并不可用,或者是使用场景不能满足我的要求。

探索解决

此问题臭名昭著,在stackoverflow很多(大部分不需要映射端口,或者是使用多端口启动),但为我所用者少。故在拼凑了很多信息,翻看了jenkins/jenkins镜像中的启动命令的源码后,想到方法并解决了这个问题,特别记录之。

docker exec进入容器

root@sg2-shopee-cloud-devvm-test-10-129-140-26:/home/ld-sgdev/baozhen_chen# docker exec -it ed34114ca8c1 /bin/bash
[root@sg2-shopee-cloud-devvm-test-10-129-140-26 /]#

在容器里ps -ef观察启动脚本(不使用cat管道,则不能显示换行的文本)

[root@sg2-shopee-cloud-devvm-test-10-129-140-26 jenkins]# ps -ef | cat
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 Nov18 ?        00:00:07 /sbin/tini -- /usr/local/bin/jenkins.sh
root          6      1  0 Nov18 ?        00:28:20 java -Duser.home=/var/jenkins_home -Djenkins.model.Jenkins.slaveAgentPort=50000 -jar /usr/share/jenkins/jenkins.war
root       7628      0  0 14:13 pts/0    00:00:00 /bin/bash
root       7733   7628  0 14:55 pts/0    00:00:00 ps -ef
root       7734   7628  0 14:55 pts/0    00:00:00 cat

发现是由/usr/local/bin/jenkins.sh脚本作为入口,拉起了java [参数] -jar /usr/share/jenkins/jenkins.war,后者才是真正的启动命令,其中50000刚好是JNLP的端口号,看下是怎么样从/usr/local/bin/jenkins.sh里传进去的

查看启动脚本的源码部分

[root@sg2-shopee-cloud-devvm-test-10-129-140-26 /]# cat /usr/local/bin/jenkins.sh 
#! /bin/bash -e

: "${JENKINS_WAR:="/usr/share/jenkins/jenkins.war"}"
: "${JENKINS_HOME:="/var/jenkins_home"}"
: "${COPY_REFERENCE_FILE_LOG:="${JENKINS_HOME}/copy_reference_file.log"}"
: "${REF:="/usr/share/jenkins/ref"}"
touch "${COPY_REFERENCE_FILE_LOG}" || {
    echo "Can not write to ${COPY_REFERENCE_FILE_LOG}. Wrong volume permissions?"; exit 1; }
echo 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值