スクエニ ITエンジニア ブログ

Docker を使って隔離 network を利用する

こんにちは、疑り深いホシイです。

複数の機能を組み合わせてシステムを構築するとき、それぞれの機能同士の通信は必要だがその他の通信は禁止したいということはよくあります。たとえば…

  • 開発中のプログラムで、想定している以外の通信が無いことを確認したい
  • 公開されているソフトウェア (OSS や container image 等) をちょっと試してみたいが、その素性が完全には確認できていないので、外部との通信を遮断した環境で実行してみたい

特に後者のような用途では、実行環境ごと隔離できると何かと便利です。今回は Docker を使ってやってみたいと思います。

Docker の実行 option を使用する

docker run するときに、--net=none をつけるだけで、container は network から隔離されます。
参考: None network driver

❯ docker run -it --rm --entrypoint=ash --net=none alpine
/ # ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1000
    link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00

単に実行するだけでよければ、これがかんたん便利です。
ただこれだと、host からも接続ができなくなるので web app などの動作確認はすこし不便です。

Docker Compose で隔離した network を使用する

システム内に複数の機能があり、それぞれは通信可能にしたいといった場合は単純にはいきません。こういったものに備え、Docker Compose を使用して、テンプレをつくっておくと便利そうです。

以下の compose.yaml で、nginx の container をふたつ起動し、お互いは専用の network で通信可能であるものの、片方の nginx container は専用 network 以外 からは隔離されている状態をつくります。これで、host からもブラウザ等で確認ができるようになります。

version: '3.8'

services:
  # 外との通信が可能な container
  nginx_e:
    image: nginx
    ports:
      - "127.0.0.1:8080:80" # host 側から接続できるようにする
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro # nginx_i への proxy 設定
    networks:
      - net_e
      - net_i
  # 内部通信専用 container
  nginx_i:
    image: nginx
    # ports:
    #   - "127.0.0.1:8081:80" # 接続できないので書いても意味はない
    networks:
      - net_i

networks:
  net_i:
    name: net_i
    internal: true
  net_e:
    name: net_e

一段目の nginx には単に reverse proxy させるため、以下の設定を mount させておきます。

server {
    listen       80;
    server_name  localhost;
    location / {
      proxy_pass http://nginx_i/;
    }
}

設定のキモは networks 下の internal: true で、document Networks top-level elements > Internal には以下のように書かれています。隔離した network をつくるためのものです。

By default, Compose provides external connectivity to networks. internal, when set to true, allows you to create an externally isolated network.

また、記事の趣旨とはじゃっかん離れますが、 ports127.0.0.1:8080:80 のように IP address つきで指定しています。IP address を省略して 8080:80 などとしても接続可能になりますが、この場合 0.0.0.0:8080:80 という意味になり、host とおなじ network にいる他の端末からも接続可能になります。安全ではない network を使うノマド族の皆様はご注意ください。(参考)

上記のふたつの file を用意して、(いつもどおり) 以下のようにして実行します。

docker compose up

network 構成はこのようになっています。

network 構成 概念図

一段目の nginx には host から http://127.0.0.1:8080 で接続でき、reverse proxy により二段目の nginx に request が行きます。host から二段目の nginx に直接接続できないことも確認できると思います。また、docker exec して二段目の nginx container の shell に入れば、internet 含む外部 network にも出ていけないことが確認できると思います。

これでテンプレとしては機能しそうです!あとは、二段目の nginx image を検証したいものに差し替えれば、いつでも好きな container image を安全に検証できそうです。

まとめ

今回は、隔離環境を用意することを目的に Docker network を使って便利テンプレをつくってみました。仮想化ツールが熟成して、様々なタスクがかんたんに実現できることがうれしい限りです。かたや、仮想化環境のネットワークは複雑になりがちなので、考慮漏れなどの穴がないように注意していきたいですね。

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!