2

使用できるように、consul と docker デーモンが適切に構成された 2 台のマシン HostA と HostB があります。docker network create -d overlay sharednet

ネットワークが存在するかどうかTestScript.shを確認し、存在しない場合はネットワークを作成する必要があります。このスクリプトは、HostA と HostB の両方で使用できます。私はまた、基本的に各マシンMasterScript.shで呼び出すだけの A のみを持っています。TestScript.shを実行するとMasterScript.sh、驚くべき結果が表示されます。同じ名前の 2 つのネットワークが作成されました!!! これはおそらく docker デーモンの同期の問題です。

[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

予想される動作は、testnwHostA でネットワークを作成したときに、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. 問題は、この制限の下でこの競合状態を解決することは可能ですか?

4

2 に答える 2

0

この問題はまだ解決されていませんが、run-oneコマンドを使用して簡単に回避できました ( の代わりにrun commandになりrun-one run command、コマンドがまだ実行されている場合はエラーを返します)。

(run-oneコマンドが使用可能かどうかは で確認できますwhich run-one)

手順:

  1. ネットワークを作成するスクリプトを作成します ( のようにネットワーク名をパラメーターとして受け入れる場合がありますdocker network create "$1")。
  2. run-one同じネットワークに対してスクリプトが 2 回実行されていないことを確認するために を使用してスクリプトを呼び出して、ネットワークを (作成する必要がある場所に) 作成します ( run /path/to/script network-name)。
  3. ?
  4. 利益!

以下の (デモ) スクリプトで、このアプローチの動作を確認できます。

#!/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

それで:

  1. 実行/path/to/script cleanして未使用のネットワークを削除します (このスクリプトは必ず開発環境で実行してください)。
  2. を実行/path/to/script test1して、 という名前の 3 つのネットワークがあることを確認しますmy-network
  3. もう一度実行/path/to/script cleanします。
  4. 実行/path/to/script test2して、名前が付けられたネットワークが 1 つしかないことを確認しますmy-network(3 つのプロセスのうち 2 つがrun-oneコマンドによりエラーになり、1 つだけがネットワークを作成しています)。

スクリプトを作成して参照する必要があるという事実は別として、スクリプトが別の抽象化レイヤーを追加するという事実 (ネットワーク オプションを使用する場合は、複雑さが増す可能性があります) により、このソリューションはせいぜい回避策として説明されます。

とはいえ、これは簡単に達成でき、これをハックと呼ぶべきではないと思いますが、IMO の適切な解決策は Docker エンジン側 (おそらく API) にあるはずです。

これはdocker-compose、簡単に変更できるスクリプトから実行し、事前にネットワークの名前を知っている場合を除き、タフで簡単に実現できない場合があります。

于 2021-07-19T23:35:31.133 に答える