Dockerコンテナーからホストポートにアクセスする方法


278

私はジェンキンスを実行しているDockerコンテナを持っています。ビルドプロセスの一環として、ホストマシンでローカルに実行されているWebサーバーにアクセスする必要があります。(ポートで実行するように構成できる)ホストWebサーバーをjenkinsコンテナーに公開できる方法はありますか?

編集:私はLinuxマシンでネイティブにdockerを実行しています。

更新:

以下の@larsks回答に加えて、ホストマシンからホストIPのIPアドレスを取得するには、次のようにします。

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

これはひどい答えですのでコメントを使用しますが、これはboot2dockerセットアップでない限り、一般的に172.17.1.78でアクセスできます。
CashIsClay 2015

@CashIsClay私はそれを試してみましたが、このエラーがまだ発生しましたcurl: (7) Failed to connect to 172.17.1.78 port 7000: No route to host
Tri Nguyen

指定しませんでした。boot2dockerを実行していますか、それともLinuxでネイティブにDockerを実行していますか?
larsk、2015

@larsks申し訳ありません。質問を更新しました-Linuxでネイティブに実行しています。
Tri Nguyen

回答:


206

LinuxでDockerをネイティブに実行する場合、docker0インターフェースのIPアドレスを使用してホストサービスにアクセスできます。コンテナ内から、これがデフォルトのルートになります。

たとえば、私のシステムでは:

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

そしてコンテナの中:

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

単純なシェルスクリプトを使用してこのIPアドレスを抽出するのはかなり簡単です。

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

iptablesDockerコンテナからの接続を許可するには、ホストのルールを変更する必要がある場合があります。このような何かがトリックを行います:

# iptables -A INPUT -i docker0 -j ACCEPT

これにより、Dockerコンテナーからホスト上のすべてのポートにアクセスできます。ご了承ください:

  • iptablesルールは順序付けられており、このルールは、その前にある他のルールに応じて、正しい動作をする場合としない場合があります。

  • (a)INADDR_ANY0.0.0.0(別名)でリッスンしているか、docker0インターフェースで明示的にリッスンしているホストサービスにのみアクセスできます。


1
ありがとう。iptablesを変更せずに、IPアドレスを取得するだけ
Tri Nguyen


7
Docker for MACはどうですか?私の知る限り、「Docker for MAC」で利用可能なdocker0ネットワークはありません。その場合、コンテナからホストに接続するにはどうすればよいですか?
ビジェイ2016

17
MAC v 17.06以降でDockerを使用する場合docker.for.mac.localhostは、localhostまたはの代わりに使用してください127.0.0.1。こちらがdocです。
merito 2017年

1
IPアドレスを取得する代わりにホストのホスト名を使用しました(ホストでのホスト名コマンド)
Marek F

312

macOSおよびWindowsの場合

Docker v 18.03以降(2018年3月21日以降)

host.docker.internal内部IPアドレスを使用するか、ホストが使用する内部IPアドレスに解決される特別なDNS名に接続します。

Linuxのサポートは保留中https://github.com/docker/for-linux/issues/264

以前のバージョンのDockerがインストールされたMacOS

Docker for Mac v 17.12からv 18.02

上記と同じですが、docker.for.mac.host.internal代わりに使用します。

Docker for Mac v 17.06からv 17.11

上記と同じですが、docker.for.mac.localhost代わりに使用します。

Docker for Mac 17.05以下

Dockerコンテナからホストマシンにアクセスするには、ネットワークインターフェースにIPエイリアスをアタッチする必要があります。必要なIPをバインドできます。他のIPには使用しないでください。

sudo ifconfig lo0 alias 123.123.123.123/24

次に、サーバーが上記のIPまたはをリッスンしていることを確認します0.0.0.0。localhost 127.0.0.1でリッスンしている場合は、接続を受け入れません。

次に、DockerコンテナーをこのIPにポイントするだけで、ホストマシンにアクセスできます!

テストするにはcurl -X GET 123.123.123.123:3000、コンテナ内で実行できます。

エイリアスは再起動のたびにリセットされるため、必要に応じて起動スクリプトを作成します。

ソリューションとその他のドキュメント:https : //docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


私はこれをうまくテストしました。ファイアウォールをオフにする必要はありません
アルバロg

15
2017年6月にリリースされた17.06以降、彼らの推奨はdocker.for.mac.localhost、ホストが使用する内部IPアドレスに解決される特別なMac専用DNS名に接続することです!...私はそれをテストしました、そしてそれは実際に働いています!:)
Kyr

私のようなMacユーザーのための答えにスポットを当てます。ありがとう。しかし、私がip route show | awk '/default/ {print $3}'理解できないことの1つは、なぜ1つのIP docker.for.mac.localhostが別のIPであるのかということです。
dmmd 2017


1
使用することをお勧めしますhost.docker.internalドッキングウィンドウコンテナと設定に127.0.0.1 host.docker.internalしてホストファイル。
junlin

85

コマンドで使用--net="host"し、DockerコンテナでDockerホストをポイントします。docker runlocalhost


15
Hyper-Vの(Windowsの場合)/ xhyve(Mac用):これまで私は、コンテナは、仮想化環境で実行するという事実による理解してMac用のWindows /ドッカー用Dpckerを使用してそれらのため動作しません
ninjaboy

6
この!これが答えです!
user3751385

15
参考までに:Docker Componse内 network_mode: "host"
jbarros

これは、クライアントとサーバーのDocker for Macバージョン19.03.1では動作しません。私はそれがうまくいったことを願っていますが、うまくいきません。
クレー

1
Macを使用している場合でも、2つのDockerコンテナー間の通信が必要な場合に機能し、すべてのアプリケーションをDockerイメージに変換するので十分です
bormat

27

docker-composeを使用したソリューション:ホストベースのサービスにアクセスするには、network_modeパラメーターhttps://docs.docker.com/compose/compose-file/#network_modeを使用でき ます

version: '3'
services:
  jenkins:
    network_mode: host

編集2020-04-27:ローカル開発環境でのみ使用することをお勧めします。


次に、ジェンキンスにアクセスする方法は?ホストネットワークモードを使用している場合、ポート転送が機能していないようです
Jeff Tian

1
これは非常にリスクの高いソリューションであり、推奨されていません。明示的に必要でない限り、コンテナーに対してホストネットワークを開かないでください
Fatemeh Majd

12

現在、MacとWindowsでこれを行う最も簡単な方法host.docker.internalは、ホストマシンを使用してホストマシンのIPアドレスに解決することです。残念ながら、まだLinuxでは動作しません(2018年4月現在)。


このソリューションは、Dockerバージョン19.03.1で機能しました。ここに記載されている他の多くのソリューションは機能しません。これは、docs.docker.com / docker
クレイ

12

私はまさにそれを行うためのDockerコンテナを作成しましたhttps://github.com/qoomon/docker-host

次に、単にコンテナー名dnsを使用してホストシステムにアクセスできます。 curl http://dockerhost:9200


それは賢い解決策です。これを大量のトラフィックで使用していることを知っていますか?このコンテナを介してすべてのトラフィックをプロキシするオーバーヘッドがあるかもしれません。
ブコラン

3
それだけでループバック・デバイスをオーバー動作するため、はい、それはほとんどオーバーヘッドすべてでとてもいい働きません
qoomon

11

このすべてのネットワーキングジャンクに対するより簡単な解決策は、サービスにドメインソケットを使用することです。とにかくホストに接続しようとしている場合は、ソケットをボリュームとしてマウントするだけで完了です。postgresqlの場合、これは次のように簡単でした。

docker run -v /var/run/postgresql:/var/run/postgresql

次に、データベース接続をセットアップして、ネットワークの代わりにソケットを使用します。文字通りそれは簡単です。


これは素晴らしいソリューションです。良くやった!
有料オタク

2
ちなみに、私たちはこれで大きな問題に遭遇しました:MacのDockerはマウントされたボリュームとしてのソケットをサポートしていません。これは、Macの人が試してみるまで水泳でした。:(
mlissner

ありがとう!Linuxの魅力のように動作しました!
Marcelo Cardoso

7

私はさまざまなソリューションを調査しましたが、これが最もハックの少ないソリューションであることがわかりました。

  1. ブリッジゲートウェイIPの静的IPアドレスを定義します。
  2. extra_hostsディレクティブの追加エントリとしてゲートウェイIPを追加します。

唯一の欠点は、これを行う複数のネットワークまたはプロジェクトがある場合、それらのIPアドレス範囲が競合しないことを確認する必要があることです。

Docker Composeの例を次に示します。

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

その後、ホスト名「dockerhost」を使用して、コンテナー内からホスト上のポートにアクセスできます。



3

ホストマシンで実行されているローカルウェブサーバーにアクセスするには、2つの方法があります。

  1. パブリックIPによるアプローチ1

    ホストマシンのパブリックIPアドレスを使用して、Jenkins Dockerコンテナー内のWebサーバーにアクセスします。

  2. ホストネットワークでのアプローチ2

    「--net host」を使用して、Jenkins Dockerコンテナーをホストのネットワークスタックに追加します。ホストのスタックにデプロイされたコンテナは、ホストインターフェースへの完全なアクセス権を持っています。ホストマシンのプライベートIPアドレスを使用して、Dockerコンテナー内のローカルWebサーバーにアクセスできます。

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

ホストネットワークでコンテナーを開始し、 Eg: docker run --net host -it ubuntu実行ifconfigして、Dockerコンテナーから到達可能なすべての使用可能なネットワークIPアドレスをリストします。

例:ローカルホストマシンでnginxサーバーを起動し、Ubuntu Dockerコンテナーからnginx WebサイトのURLにアクセスできます。

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

プライベートネットワークIPアドレスを使用してUbuntu dockerコンテナーから(ローカルホストマシンで実行されている)Nginx Webサーバーにアクセスします。

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes

3

以下のためのdocker-composeコンテナ間で使用して認められたソリューションをプライベートネットワークを作成するために、ブリッジネットワークを使用してdocker0いない作業のコンテナからの出力インターフェイスではないので、docker0代わりに、それはランダムに生成されたインターフェイスIDのような、です。

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

残念ながら、そのランダムIDは予測不可能であり、composeがネットワークを再作成する必要があるたびに変更されます(たとえば、ホストの再起動時)。これに対する私の解決策は、既知のサブネットでプライベートネットワークを作成し、iptablesその範囲を受け入れるように構成することです。

ファイルスニペットを作成します。

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

ご使用の環境で必要な場合は、サブネットを変更できます。を192.168.32.0/20使用docker network inspectして任意に選択し、デフォルトで作成されているものを確認しました。

iptablesホスト上でプライベートサブネットをソースとして許可するように構成します。

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

これが最も単純なiptablesルールです。宛先ポートなど、他の制限を追加することもできます。iptablesルールが正常に機能していることを確認したら、それらを永続化することを忘れないでください。

このアプローチには、繰り返し可能なため自動化できるという利点があります。私はansibleのtemplateモジュールを使用して、変数置換を含む構成ファイルをデプロイし、次にモジュールiptablesshellモジュールを使用して、ファイアウォールルールをそれぞれ構成して永続化します。


を示唆する複数の回答を見iptables -A INPUT -i docker0 -j ACCEPTましたが、それは私を助けませんでしたが、iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPTここで提案されたことが私の問題を解決しました。
テリーブラウン

1

これは古い質問で多くの回答がありましたが、私の文脈に十分に適合するものはありませんでした。私の場合、コンテナーは非常に無駄がなく、コンテナー内からホストのIPアドレスを抽出するために必要なネットワークツールが含まれていません。

また、この--net="host"アプローチは非常に大まかなアプローチであり、複数のコンテナを持つ十分に分離されたネットワーク構成が必要な場合には適用できません。

したがって、私のアプローチは、ホスト側でホストのアドレスを抽出し、それを--add-hostパラメーターを使用してコンテナーに渡すことです。

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

または、ホストのIPアドレスを環境変数に保存し、後でその変数を使用します。

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

その後、docker-hostコンテナのホストファイルに追加され、データベース接続文字列またはAPI URLで使用できます。


0

「すでに」作成された2つのDockerイメージがあり、相互に通信する2つのコンテナーを配置する場合。

そのためには、各コンテナーを独自の--nameで実行し、-linkフラグを使用して、コンテナー間の通信を有効にすることができます。ただし、Dockerのビルド中にはこれを取得しません。

あなたが私のようなシナリオにいるとき、それはあなたです

docker build -t "centos7/someApp" someApp/ 

あなたがしようとするとそれは壊れます

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

そして、「curl / wget」で行き詰まり、「route to host」が返されません。

その理由は、Dockerによって設定されたセキュリティであり、デフォルトではコンテナーからホストへの通信、またはホストで実行されている他のコンテナーへの通信が禁止されているためです。これは私にとって非常に驚くべきことだったと思いますが、ローカルマシンで実行されているDockerマシンのエコーシステムは、ハードルをあまりかけずに完璧に相互にアクセスできると期待します。

これについての説明は、次のドキュメントで詳しく説明されています。

http://www.dedoimedo.com/computers/docker-networking.html

ネットワークのセキュリティを低下させることで移行に役立つ2つの簡単な回避策が提供されます。

最も簡単な方法は、ファイアウォールをオフにするか、すべて許可することです。これは、systemctl stop firewalld、iptables -Fまたは同等のコマンドなど、必要なコマンドを実行することを意味します。

この情報がお役に立てば幸いです。


3
ちょうどメモとして、--link非推奨になりました
Mr.Budris '22

0

私(Windows 10、Docker Engine v19.03.8)の場合、これはhttps://stackoverflow.com/a/43541732/7924573https://stackoverflow.com/a/50866007/7924573の組み合わせでした。

  1. host / ipをhost.docker.internalに 変更します。
    例:LOGGER_URL = " http://host.docker.internal:8085 / log "
  2. するnetwork_modeセットブリッジ(あなたがポートフォワーディングを維持したい場合は、使用しない場合はホストを):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge または代わりに:使用を--net="bridge"あなたが(に似たドッキングウィンドウ・コン使用していない場合https://stackoverflow.com/a/48806927/7924573を
    以前の回答で指摘したように、これはローカル開発環境でのみ使用する必要があります
    詳細については、https//docs.docker.com/compose/compose-file/#network_modeおよびhttps://docs.docker.com/docker-for-windows/networking/#use-cases-and-workaroundsを参照してください。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.