ポートマッピングを使わずにDockerコンテナにアクセスする方法

この記事はDocker Advent Calendar 2018の16日目になります。

はじめに

記事書いといてアレなんですが
基本的にはポートマッピングを使ったほうがいいと思うので、あんまり使い所はないかもしれません。

自分の場合は、とあるライブラリでWebSocketのコネクションがどうしても上手くいかず
今回の方法に行き着いた感じです。

どこかで誰かの参考になれば幸いなので記事にしたいと思います。

Linuxの場合

コンテナ起動

例として、apacheコンテナを使用していきます。

以下のdocker-compose.ymlを用意して、コンテナを起動します。

$ vi docker-compose.yml
version: '3'
services:
  web:
    image: httpd:2.4-alpine
    expose:
      - "80"
    network_mode: host  # ホストのネットワークでコンテナを実行

$ docker-compose up -d

network_mode: host とすることで、ホストのネットワークに対してポート番号をexposeするため、マッピング無しでアクセス可能となります。

この設定はLinux環境限定のようです。

docs.docker.com

確認
$ docker ps --format "table {{.Image}}\t{{.Ports}}\t{{.Names}}"
IMAGE               PORTS               NAMES
httpd:2.4-alpine                        test_web_1

$ curl http://localhost
<html><body><h1>It works!</h1></body></html>

ポートマッピングしていませんが、アクセスできました。

Docker for Windowsの場合

Hyper-VでDockerデーモンが動いている都合上、仕方ないのかもしれませんが、
network_mode: host は使えないのでネットワークの設定が必要になります。

コンテナ起動

以下のdocker-compose.ymlを用意して、apacheコンテナを起動します。

$ vi docker-compose.yml
version: '3'
services:
  web:
    image: httpd:2.4-alpine
    expose:
      - "80"
    networks:
      my_network:
        ipv4_address: 172.99.0.2  # コンテナのIPを指定

networks:
  my_network:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.99.0.0/24  # ネットワークアドレスを指定

$ docker-compose up -d

ネットワークアドレスは172以外は自由に設定できます。
他のdocker networkで使われていないものを指定してください。

ルーティングテーブル設定

Docker for Windowsでは、デフォルトで以下の構成になっているようです。

  • 仮想スイッチ:10.0.75.0/24
  • DockerNAT:10.0.75.1
  • MobyLinuxVM:10.0.75.2

この内のMobyLinuxVMに、先ほどのネットワークアドレスをルーティングします。

$ route -p add 172.99.0.0/24 10.0.75.2
※管理者権限のコマンドプロンプトで実行

ルーティングテーブルを確認

$ route print

設定を削除する時はこちら

$ route delete 172.99.0.0

この設定については、以下の記事が大変参考になりました。 qiita.com

確認
$ docker ps --format "table {{.Image}}\t{{.Ports}}\t{{.Names}}"
IMAGE               PORTS               NAMES
httpd:2.4-alpine    80/tcp              test_web_1

$ curl http://172.99.0.2
<html><body><h1>It works!</h1></body></html>

アクセスできました。

Docker for Macの場合

すいません。分かりませんでした。

ただ、Macの場合はWndowsと違ってDocker for MacVirtualBoxが共存できるので
VirtualBox上のDockerで network_mode: host を使えば良いかなと思います。

最後に

Macについては思いっきり手抜きとなってしまいましたが、
そもそも今回の記事はDocker for WindowsVirtualBoxが共存できないことがきっかけになっています。

前述のWebSocketの件で最初は仕方なくVagrantで環境構築したんですが
DockerとVagrantを切り替えるために毎回PCを再起動する状況にノイローゼ寸前だったので、必死に調べた結果となります。 *1
何卒ご容赦ください。


以上、現場からでした。

*1:大人の事情でMacで開発するという選択肢はありません