Docker

Dockerのネットワークを理解する【深く知る】

Docker

みなさんはDocker使っていますか?Dockerを利用することすぐに開発環境や検証環境が構築できるので非常に便利ですよね。

すでにDockerを使っている方は知っていると思いますが、実際にDockerを使ってコンテナを構築する時にはネットワーク周りの設定はしてないと思います。(基本的な使い方の場合)

しかし、外部からコンテナへのアクセスや、コンテナから外部ネットワークへの通信、さらにはコンテナ間の通信もできます。一体何故なんでしょうか?

ネットワークを意識せずに使えるというのがDockerの便利な面でもあるのですが、ネットワークエンジニアとしては、Dockerのネットワークについて理解しておかねばならないでしょう。

ということでDockerのネットワークについて調査してみました。

Dockerのネットワークの種類

Dockerのネットワークを確認するコマンド「docker network ls」を実行して確認すると、Dockerをインストールされたタイミングでで3つのデフォルトネットワーク(bridge,host,none)が作られています。

bash-3.2$ doker network ls
NETWORK ID          NAME                      DRIVER              SCOPE
43ca95bdf23c        bridge                    bridge              local
4b933f00b1a7        host                      host                local
1528bb7a0297        none                      null                local

コンテナのネットワークを指定せずに利用すると「Bridge」が利用されます。 Bridgeのポイントとしては以下のような感じです。

  • Bridgeはコンテナが接続される仮想スイッチみたいな感じ
  • Bridgeのネットワークはデフォルトだと「172.17.0.0/16」が利用される
  • ホストでifoconfigとかすると、仮想Bridge(bridge0)が作成されていることが分かる。
    ※Macの場合はbridge0、Linuxの場合はdocker0という名称のようです。
  • コンテナが外部ネットワークへ接続する際には、Bridgeを経由してNATされて通信する
  • 外部ネットワークからコンテナへアクセスするにはポートをマッピングしてアクセスを許可させる必要がある
  • 同じBridgeネットワークに接続しているコンテナは互いにアクセス(ping疎通など)できる
  • Docker Composeでコンテナを構築した場合は、自動的に新しいBridgeネットワークが構築される(172.17.0.0/16以外が作成される)
  • 何もオプションなどを指定しないでコンテナを起動すると「Bridge」に接続される
  • vethというLinuxで使われている仮想NICみたいな技術を利用してコンテナとBridge間が接続されている
  • vethはペアで作られる。ペアのveth間で通信が可能となる

PlantUMLで図にしてみました、こんな感じでしょうか。

Dockerネットワークの確認方法

それではもう少し具体的にDockerのネットワークを確認してみます。

まず、Docker Composeでコンテナを2台作成してみます。今回は例としてgitlabとgitlab-runnerの検証で使ったコンテナを使って確認します。Docker Composeでコンテナを作成したことがない方は以下をdocker-compose.ymlとして利用してみてください。

version: '3'
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab-test'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab-test'
        gitlab_rails['gitlab_shell_ssh_port'] = 4022
        # Add any other gitlab.rb configuration here, each on its own line
    ports:
      - "80:80"
      - "4022:22"
    volumes:
      - './srv/gitlab/config:/etc/gitlab'
      - './srv/gitlab/logs:/var/log/gitlab'
      - './srv/gitlab/data:/var/opt/gitlab'
  runner:
    image: 'gitlab/gitlab-runner:latest' 
    restart: always
    volumes:
      - ./srv/gitlab-runner/config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock

docker-compose up -d コマンドでコンテナを起動すると以下のように新しくgitlab_defaultというBridgeネットワークが作られていることが確認できます。

bash-3.2$ docker network ls
NETWORK ID          NAME                      DRIVER              SCOPE
43ca95bdf23c        bridge                    bridge              local
3be68aa6a988        gitlab_default            bridge              local
4b933f00b1a7        host                      host                local
1528bb7a0297        none                      null                local

次にコンテナと共に作成されたネットワークがどうなっているのか確認してみます。「docker network inspect <ネットワーク名>」のコマンドから詳細が確認できます。

bash-3.2$ docker network inspect gitlab_default
[
    {
        "Name": "gitlab_default",
        "Id": "3be68aa6a9884384efb6efd5ac83bdf5a07ee203cb5d26fd3a60a07b18966268",
        "Created": "2020-04-15T12:32:53.4043827Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.22.0.0/16",
                    "Gateway": "172.22.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "3e278c71f001ac26ed64e4efce6fb64e234e797973d44b5a1df900bff222585e": {
                "Name": "gitlab_runner_1",
                "EndpointID": "2a0844b864ff556ff264726e037cc6e1d1d4386e627cc7489b699a0ee29b492a",
                "MacAddress": "02:42:ac:16:00:02",
                "IPv4Address": "172.22.0.2/16",
                "IPv6Address": ""
            },
            "bf8f4a9679a1035c6f95c0731f1c1b71eb61350f27de1f05d4a82a3037d51b9c": {
                "Name": "gitlab_gitlab_1",
                "EndpointID": "83e635dc3d83a1db5e27ff76d6173a18a0673f41c8e0bab66b556fdd96007f40",
                "MacAddress": "02:42:ac:16:00:03",
                "IPv4Address": "172.22.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "gitlab",
            "com.docker.compose.version": "1.25.4"
        }
    }
]

出力された内容を見ると以下のことが分かります。

  • Bridgeネットワークが自動的に作成されている(”Driver”: “bridge”の部分)
  • Bridgeの内部ネットワークは「172.22.0.0/16」が使われている
    →作られた環境によって異なります。自動的にネットワークが作成されてることがポイントです。
  • 各コンテナ(gitlab_runner_1とgitlab_gitlab_1)に対して「172.22.0.2」と「172.22.0.3」が自動的に割り当てられている

Docker Composeでのネットワークの指定方法

それでは最後に自動的に作成されるコンテナ内部ネットワークを指定する方法について説明します。

基本的に内部ネットワークを指定するシチュエーションは少ないのですが、必要となるパターンとしては、アプリケーション内の設定で他コンテナのIPアドレスを設定しなければならない場合などです。

今回はgitlabとgitlab-runnerのコンテナを作成して利用しようとした際に、gitlab-runner側にgitlabコンテナIPアドレスを設定する必要がありました。

実際のDocker Composeでの設定方法は以下となります。

version: '3'
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab-test'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab-test'
        gitlab_rails['gitlab_shell_ssh_port'] = 4022
        # Add any other gitlab.rb configuration here, each on its own line
    ports:
      - "80:80"
      - "4022:22"
    volumes:
      - './srv/gitlab/config:/etc/gitlab'
      - './srv/gitlab/logs:/var/log/gitlab'
      - './srv/gitlab/data:/var/opt/gitlab'
    networks:
      gitlab_net:
        ipv4_address: 172.16.238.2
  runner:
    image: 'gitlab/gitlab-runner:latest' 
    restart: always
    volumes:
      - ./srv/gitlab-runner/config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
    extra_hosts:
      - "gitlab-test:172.16.238.2"
    networks:
      gitlab_net:
        ipv4_address: 172.16.238.3

networks:
  gitlab_net:
      ipam:
        config:
          - subnet: 172.16.238.0/24

必要となる設定箇所は2点です。

①各コンテナ内のneworksで指定したいIPアドレスを記載する
②networksでsubnetを指定する

当然ですが、sabnetとIPアドレスのネットワーク設定は正しくして下さい。

まとめ

基本的にネットワークを指定するシチュエーションは少ないですが、Dockerのネットワークについての理解がかなり深まりました。

Dockerのオススメ勉強方法

私がオススメするDocker初心者向けの最初に購入すべき書籍は「さわって学ぶクラウドインフラ docker基礎からのコンテナ構築です。

さわって学ぶクラウドインフラ docker基礎からのコンテナ構築

本書ではDockerの基本的な概念などの座学ももちろんありますが、実際に、Dockerのインストール方法やWebサーバーをコンテナで構築するハンズオンを通じて学習することができるため、特に初心者の方はは分かりやすい内容となっています。

今回は以上となります。

コメント