我有两台机器HostA和HostB,并且正确配置了consul和docker守护程序,以便我可以使用docker network create -d overlay sharednet
我有TestScript.sh
来检查网络是否存在以及是否创建网络。 HostA和HostB都提供此脚本。我在A上只有一个MasterScript.sh
,它基本上只在每台机器上调用TestScript.sh
。运行MasterScript.sh
之后,我看到一个令人惊讶的结果,创建了两个同名的网络!这可以说是一个docker daemon同步问题。
[HostA]# docker network ls
NETWORK ID NAME DRIVER
ad492bba9efa sharednet overlay
ba53d4e7b739 sharednet overlay
[HostB]# docker network ls
NETWORK ID NAME DRIVER
ad492bba9efa sharednet overlay
ba53d4e7b739 sharednet overlay
预期的行为是当我在HostA上创建网络testnw
时,然后在HostB上我会看到类似这样的内容
[HostB]# docker network ls
68994f95cd67 testnw overlay
[HostB]# docker network create -d overlay testnw
Error response from daemon: network with name testnw already exists
由于某些限制,我无法修改MasterScript.sh
,但我可以修改TestScript.sh
。所以问题是,我有可能在这个限制下解决这种竞争条件吗?
答案 0 :(得分:0)
此问题已报告给Docker Github,目前正在https://github.com/docker/docker/issues/20648
下进行跟踪答案 1 :(得分:0)
这个问题仍然没有解决,但是我可以使用 run-one
命令轻松地避免它(而不是 run command
,它变成了 run-one run command
,如果命令返回一个错误仍在运行)。
(您可以通过 run-one
验证 which run-one
命令是否可用)
步骤:
docker network create "$1"
)。run-one
调用脚本来创建网络(无论应在何处创建),以确保它不会为同一个网络 (run /path/to/script network-name
) 执行两次。您可以在下面的(演示)脚本中看到这种方法的实际效果:
#!/bin/bash
set -eou pipefail
RED='\033[0;31m'
NC='\033[0m' # No Color
function error {
msg="$(date '+%F %T') - ${BASH_SOURCE[0]}:${BASH_LINENO[0]}: ${*}"
>&2 echo -e "${RED}${msg}${NC}"
exit 2
}
file="${BASH_SOURCE[0]}"
command="${1:-}"
if [ -z "$command" ]; then
error "[error] no command entered"
fi
shift;
case "$command" in
"clean")
sudo docker network prune -f
;;
"test1")
run-one "$file" "test:concurrent" "test:network"
;;
"test2")
run-one "$file" "test:concurrent" "test:network:unique"
;;
"test:concurrent")
echo "===========before==========="
sudo docker network ls
echo "============================"
cmd="$1"
pids=()
for i in $(seq 1 3); do
"$file" "$cmd" &
pids["${i}"]=$!
done
idx=0
for pid in "${pids[@]}"; do
wait "$pid" && status="$?" || status="$?"
idx=$((idx + 1))
if [ "$status" != '0' ]; then
echo "error in process $pid (#$idx)"
fi
done
echo "===========after============"
sudo docker network ls
echo "============================"
;;
"test:network:unique")
run-one "$file" "test:network"
;;
"test:network")
sudo docker network create "my-network"
;;
*)
echo -e "${RED}[error] invalid command: $command${NC}"
exit 1
;;
esac
那么:
/path/to/script clean
以删除未使用的网络(确保在开发环境中运行此脚本)。/path/to/script test1
并看到有 3 个名为 my-network
的网络。/path/to/script clean
。/path/to/script test2
并看到只有 1 个名为 my-network
的网络(由于 run-one
命令,3 个进程中有 2 个最终出错,只有一个创建网络).除了必须创建脚本并引用它之外,脚本添加了另一个抽象层(如果您打算使用网络选项,这可能会增加复杂性)这一事实使得该解决方案充其量被描述为一种解决方法。
也就是说,这很容易实现,我不认为这应该被标记为黑客行为,尽管 IMO 应该在 docker 引擎方面(可能在 API 中)提供适当的解决方案。
使用 docker-compose
可能不太容易实现,除非您从一个可以轻松更改的脚本中运行它,并且您事先知道网络的名称。