我正在尝试使用 jenkins 制作一个自定义 dockerfile。我会等到端口 8080 打开,而不是使用 netcat 执行丑陋的“睡眠 60”,但我对 bash 脚本和 netcat 不太有信心。
这是我正在尝试做的一个例子:
#!/bin/bash
opened=0
while [ "$opened" == "0" ]; do
echo "Waiting jenkins to launch on 8080..."
nc -vz localhost 8080
done
echo "Jenkins launched"
您无法将netcat设置为等待某个端口打开,因此您必须在进行下一次检查之前添加等待部分。试试这个:
#!/bin/bash
echo "Waiting jenkins to launch on 8080..."
while ! nc -z localhost 8080; do
sleep 0.1 # wait for 1/10 of the second before check again
done
echo "Jenkins launched"
我建议使用以下一款衬垫:
## netcat version:
timeout 22 sh -c 'until nc -z $0 $1; do sleep 1; done' stackoverflow.com 443
## pure bash version:
timeout 22 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' stackoverflow.com 443
连接建立后,这两个命令都会退出,每秒尝试一次,最多持续 22 秒。
请注意,由于
timeout
命令,当端口可访问时,退出代码为 0
,否则 124
(如果在给定时间内没有建立连接)。
按照here的建议,如果您没有安装
nc
,而只安装了bash
和coreutils
,您也可以执行以下操作:
#!/bin/bash
echo "Waiting jenkins to launch on 8080..."
while ! timeout 1 bash -c "echo > /dev/tcp/localhost/8080"; do
sleep 1
done
echo "Jenkins launched"
我发现这是一个很常见的问题,需要编写一个实用程序来等待端口打开,并具有可选的超时:
# without timeout
wait-port localhost:8080
# timeout after a minute
wait-port -t 60000 localhost:8080
它是开源的,可在 github.com/dwmkerr/wait-port 获取。希望其他人会发现它有用!
为了扩展 user987339 的答案,以下是如何轻松等待终端中的端口:
将此函数添加到您的 ~/.bashrc 设置文件中:
waitport() {
while ! nc -z localhost $1 ; do sleep 1 ; done
}
注销然后重新登录以加载 ~/.bashrc。然后,运行此命令来验证端口 3000 是否有服务器正在侦听:
$ waitport 3000
Connection to localhost port 3000 [tcp/hbci] succeeded!
这已在 macOS 上得到验证。它可能不适用于 Fedora/CentOS,因为它们缺少
-z
的 netcat
选项。
我用它来等待几个端口打开,没有 netcat:
while (! (: </dev/tcp/localhost/27017) &> /dev/null || ! (: </dev/tcp/localhost/9200) &> /dev/null); do
sleep 2;
done
根据需要更改
localhost
和端口。
这是我的单行 Bash 解决方案(使用 netcat),它等待 10 秒的 TCP 连接,并在等待期间向您提供是否成功或失败的反馈,如果端口打开,则返回退出代码
0
,否则1
:
bash -c 'echo -n "Waiting port 8080 .."; for _ in `seq 1 40`; do echo -n .; sleep 0.25; nc -z localhost 8080 && echo " Open." && exit ; done; echo " Timeout!" >&2; exit 1'
您可以将硬编码端口
8080
替换为 $1
并删除 bash -c
(如果代码片段保存在脚本文件 wait-port
中),然后在控制台中使用以下命令调用:wait-port 8080
。
这是3个终端的记录,其中两个等待端口打开,其他终端打开其中一个端口,因此当其中一个等待成功时,另一个超时:
虽然该行有很多指令,但如果您需要在无法首先存储脚本的主机中“远程”执行等待,那么它可能会很有用。在 Docker 容器中。
我编写了一个实用程序来等待端口打开,它还可以检查 MySQL、PostgreSQL、Redis 等可用性。
# Checking TCP port
wait4x tcp localhost:8080
# Checking TCP port with specific timeout (5 Minutes)
wait4x tcp localhost:8080 -t 5m
它是开源的,可在 https://github.com/atkrad/wait4x 获取。希望其他人会发现它有用!
这是一个有超时的 for 循环示例,因此它会尝试例如10 次,采用指数退避(2、4、8、16 秒等),但最终放弃。 Netcat 也有 1 秒超时。
for EXPONENTIAL_BACKOFF in {1..10}; do
nc -w 1 -z db.local 3306 && break;
DELAY=$((2**$EXPONENTIAL_BACKOFF))
echo "db not yet available, sleeping for $DELAY seconds"
sleep $DELAY
done
输出为:
db not yet available, sleeping for 2 seconds
db not yet available, sleeping for 4 seconds
db not yet available, sleeping for 8 seconds
db not yet available, sleeping for 16 seconds
在 CI 上运行测试之前,我使用此脚本检查端口。
#!/bin/bash
for _ in `seq 1 20`; do
echo -n .
if nc -z localhost $1; then
exit 0
fi
sleep 0.5
done
exit 1
$ bin/wait-port 3306
对于那些有困难的人
nc: invalid option -- 'z'
我试图在 docker 镜像中设置它。令人惊讶的是,该图像中的
-z
中没有 nc
的选项。
图像是 -
Linux elasticsearch 4.4.0-101-generic #124~14.04.1-Ubuntu SMP Fri Nov 10 19:05:36 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
我使用以下循环来等待端口打开。
#!/bin/bash
echo "Waiting elastic search to launch on 9200..."
open=0;
while [ $open -eq 0 ]
do
check_port=`nc -v -w 1 -i 1 127.0.0.1 9200 &> /dev/stdout`
echo $check_port
if [[ "$check_port" == *"Connected to"* ]]
then
break
fi
sleep 1
done
echo "Elastic Search launched"
以下是上述脚本的一行:
open=0;while [ $open -eq 0 ]; do check_port=`nc -v -w 1 -i 1 127.0.0.1 9200 &> /dev/stdout`; echo $check_port; if [[ "$check_port" == *"Connected to"* ]]; then break; fi; sleep 1; done
我使用这个示例用法
./xl_wait_port.sh [port] [ up | down ]
参数:
可以从 github xl_wait_port 下载。我是作者。
代码片段
echo Waiting for port $PORT_NO to go $MODE.
LOOP_FLAG=1
WARN_FLAG=1
while [ "$LOOP_FLAG" -gt 0 ]; do
LOOP_FLAG=1
STATUS=`lsof -i :$PORT_NO`
if [ "up" == $MODE ]; then
if [ "1" -eq "$STATUS" ]; then
LOOP_FLAG=0
fi
else
if [ "0" = "$STATUS" ]; then
LOOP_FLAG=0
fi
fi
RESULT=$((WARN_FLAG % 35))
if [ "$RESULT" -eq "0" ]; then
echo "Process is taking some time. Please check or wait."
fi
sleep 1
((WARN_FLAG++))
done
echo Port $PORT_NO is now $MODE.