コンテナー内の_/etc/hosts
_にdocker Hostマシンの適切なIPアドレスを追加するユニバーサルシェルスクリプトを記述したいと思います。
アクセスしたいサービスを別のDockerコンテナーに入れることをお勧めしますが、CIで最も高速なテストを行うには、コンテナーからIPでDockerホストマシンにアクセスしたいので、それが必要です。
githubにたくさんのコメントがある問題 があり、人々はホストIPにアクセスするための統一された方法を作ることを求めていました。すべてのプラットフォームatmに共通の解決策はありません。
人々はこのようなスクリプトを作成します:
grep dockerhost /etc/hosts || echo $(ip r | grep ^default | cut -d" " -f3) dockerhost >> /etc/hosts
Docker Hostマシンにアクセスするために、同じアプローチを使用したいのですが、Mac atmでは機能しません。返される結果:
_ip r | grep ^default | cut -d" " -f3
_
docker HostマシンがMacの場合、_172.17.0.1
_は間違った答えを返します(_172.17.0.1
_を使用してコンテナーからMacに実際にアクセスすることはできません)。
Docker for Macに機能があるのはそのためです- 特別なホスト名 _docker.for.mac.localhost
_を使用して、コンテナーからホストMacにアクセスできます。
最初に_docker.for.mac.localhost
_を解決し、解決されたアドレスを_/etc/hosts
_に追加するユニバーサルsh
ellスクリプトを記述したいと思います。そうでない場合(つまり、Docker HostがMacではなくWindowsまたはLinuxのいずれかであることを意味します)、_ip r | grep ^default | cut -d" " -f3
_アプローチを使用し、_/etc/hosts
_にも追加します。
問題は、どのコンテナで_docker.for.mac.localhost
_を解決しようとすることができますか? (たとえば、一部のディストリビューションにはnslookup
がありません)。または、解決しようとするべきではなく、どこかから_docker.for.mac.localhost
_値を読み取ろうとするだけですか?
私の現在の考えは、_getent ahosts docker.for.mac.localhost
_を使用することです。コマンドが存在しない場合は、nslookup
を使用しようとします(つまり、Busyboxイメージにはgetent
コマンドがありません)。おそらく私は_docker.for.mac.localhost
_を解決しようとして間違っており、簡単に取得できます。あなたの考えを共有してください。
ありがとうございました。
Docker.for.mac.localhostを解決するというあなたの考えは、目標どおりにかなりうまくいきます。ほとんどすべてのコンテナーでそれを解決できる何かを見つける必要があるだけです。これはそれを行うはずです(そして私のテストによれば、持っています):
grep dockerhost /etc/hosts || echo $( (ping -c1 docker.for.mac.localhost || (ip r | grep ^default)) | grep -oE '([0-9]+\.){3}[0-9]+' ) dockerhost >> /etc/hosts
それをエントリポイントの一部として置くことができます(sh -c
)または何らかのinitスクリプトで。
詳細、コメント付きバージョン、および警告については、以下をお読みください。
Linuxに名前を解決させるだけです。 pingは最も簡単な選択ですが、ncとtracerouteはほとんどどこにでも存在します。他のすべてが失敗した場合は、最新の(BusyBox以外の)bashまたはsyslogで実際にこれを行うことができます。デフォルトでは、Dockerは同じネットワーク上の他のコンテナー(または、以前のバージョンではリンクされたコンテナー)の名前に応答する小さなDNSサーバーをセットアップします。その後 docker.for.mac.localhost
が追加されます。
何も解決しない場合、そのDNSサーバーはそれを解決しなかったため、ホストは通常どおり取得されます。代わりに/ proc/netメソッドを使用したいと思うかもしれませんが、それらは私のテストコンテナーでは同等のようです。
ここで、いくつかの注意点があります。まず、大きな問題です。ネットワーク接続がない場合、タイムアウトするまでに最大30秒かかります。以下の大きなスクリプトにいくつかの修正があります。また、コンテナーのビルド中にこれを実行することもできません(デフォルトでは、これをオーバーライドする方法があります)。むしろ、可能ですが、何も実行しません。Dockerはコンテナーを起動すると、新しい/ etc/hostsをマウントします。
より優れたバージョンではtimeout
を使用しますが、問題が発生します-(少なくとも)2つの互換性のないバージョンがあり、3つ目のケースはそれが存在しない可能性があると想定したい場合です。
grep dockerhost /etc/hosts || echo $( (
(if timeout -t1 env >/dev/null; then \
timeout -t1 ping -c1 docker.for.mac.localhost; \
Elif timeout 1s env >/dev/null; then
timeout 1s ping -c1 docker.for.mac.localhost; \
else \
ping -c1 docker.for.mac.localhost; \
fi) \
|| (ip r | grep ^default)) \
| grep -oE '([0-9]+\.){3}[0-9]+' ) dockerhost >> /etc/hosts
シェル組み込みではないバージョン(/usr/bin/env
ほとんどの場合)、それはよく知られているインターフェイス(つまり、入力なしで実行されます)を備えており、ファイルシステムに依存するls
などの厄介なコマンドとは異なり、環境上の理由で失敗することはほとんどありません。
そして最後に、私が使用しているものと同様の完全なコメント付きバージョン(私の後ろに来る人々が何が起こっているのかを理解できるように):
add_dockerhost_address() {
# The name we're checking for - in case this technique is useful on Windows
# if we get a Windows version instead of a cross-platform one
local MACHOST="docker.for.mac.localhost"
# The name we want to insert into /etc/hosts
local DOCKERHOSTNAME="dockerhost"
# Don't insert the name twice
if grep "$DOCKERHOSTNAME" /etc/hosts >/dev/null 2>&1; then
return 0
fi
# A command string we'll be building
local COMMAND=""
# Check for the ability to limit the timeout
if command -v timeout >/dev/null 2>&1; then
# We still have a problem - there are two widely used incompatible
# variants of timeout. Let's see which one we have.
# env should not be a builtin, doesn't require a pipe,
# has a consistent command line test, and is unlikely to fail
if timeout -t1 env >/dev/null 2>&1; then
COMMAND="timeout -t1 "
else
COMMAND="timeout 1s "
fi
fi
local IS_NOT_MAC=1
local IP=""
if command -v ping >/dev/null 2>&1; then
COMMAND="$COMMAND ping -c1 $MACHOST"
# Otherwise, BusyBox shows terminated.
IP=$(sh -c "$COMMAND" 2>&1)
# Exit codes: 0 - found the Host, 1/2 failed to find, 124/143 terminated
IS_NOT_MAC="$?"
fi
if [ "$IS_NOT_MAC" -eq 0 ]; then
IP=$(echo "$IP" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
else
IP=$(ip r | grep ^default | cut -d" " -f3)
fi
echo "$IP $DOCKERHOSTNAME" >> /etc/hosts
}
add_dockerhost_address
exec "/usr/sbin/apachectl" "-DFOREGROUND"
私はそれが言及されていると思います ここdocker.for.mac.Host.internal
が使用できること。 docker.for.mac.localhost
については言及されていませんが、私にとっても機能します。
次に、次の行を使用して、Docker for Macで実行しているかどうかを確認します。
$ getent hosts docker.for.mac.Host.internal
$?
は、docker.for.mac.Host.internal
が見つかったかどうかを通知します。
実際のIPを取得するには、次のようにawk
を使用することもできます。
$ getent hosts docker.for.mac.Host.internal | awk '{ print $1 }'