コンテナ同士の連携:ネットワークとボリューム

記事タイトルとURLをコピーする

はじめに

こんにちは。孔子の80代目子孫兼技術5課の孔です。もう6月になりましたね。夏になってきて暑い日々が続いてるので、健康にも気をつけてくださいね。

前回のブログではDockerの使い方を簡単にみてみました。コマンドの仕組みのイメージがつかめたらいいかと思います。今回の話ではDockerのネットワークとボリュームについて解説します。ネットワークは、Dockerのコンテナ同士がどのようにやりとりをするのか、またホストIPをどのように経由して外部とつながるのかについて説明していきます。ボリュームは、Dockerのコンテナが共有する共通ボリュームについて説明します。

それでは、みてみましょう。Let's check it out!

Dockerにおいてのネットワーク

Dockerのネットワーク機能は、コンテナのネットワークを構成、管理するものとなります。仮想ネットワークをDockerで作成し、それぞれのネットワークにコンテナを配置することによって簡単にネットワークを構成することが可能になります。

もう少し具体的な話をするために、まずDockerのネットワーク一覧をみてみましょう表示するコマンドはdocker network lsとなります。

kong@KongnoAir docker % docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1c3d5534f8f6        bridge              bridge              local
3593069c284a        host                host                local
2d216a540abf        none                null                local

上記のシェルでNone, Host, Bridgeという単語がありますが、この三つはDockerをインストールした際にデフォルトでインストールされるネットワークとなります。それぞれのネットワーク上にコンテナを作成しながら特徴をみていきましょう。特定のネットワークにコンテナを作成するコマンドはdocker container run --net={ネットワーク名}となります。

Noneとは

Noneネットワークは、外部とも、そしてどのコンテナともつながらないネットワークを意味します。ローカル内で処理を完結したいコンテナはNoneネットワークに作成します。

kong@KongnoAir docker % docker run -it --net=none busybox sh
/ # ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

このように、Noneのネットワーク上に作成したコンテナはローカルネットワークしか存在してないことがわかります。他のコンテナとも、外部とも通信ができない状態です。

Hostとは

Hostネットワークは、ホストマシンとネットワークインターフェースを共有するネットワークとなります。コンテナのネットワークの設定をホストと一緒にしたい時に使います。ホストマシンのポートとコンテナのポートがマッピングされるため、コンテナでは80ポートをホストマシンの8080ポートをマッピングするようなことはできません。

Bridgeとは

Bridgeネットワークは、Dockerのコンテナ用の内部ネットワークを作成し、そのネットワークで仮想ネットワークインターフェースを作成してホストと通信のやりとりをするネットワークとなります。

bridge3

こちらの図をみていただくと、ホストマシンのネットワークインターフェースであるeth0と二つのBridgeがつながってます。それぞれのBridgeにコンテナは繋がり、このBridgeを経由してホストマシンとやりとりをします。Dockerをインストールし、ネットワークの接続状況を確認してみるとdocker0というアダプターができたのがわかります。

kong@KongnoAir docker % ifconfig docker0
docker0   Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:a2ff:fe10:ccf7/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:7 errors:0 dropped:0 overruns:0 frame:0
          TX packets:30 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:480 (480.0 B)  TX bytes:5025 (5.0 KB)

このアダプターを経由してDockerのBridgeネットワークとやりとりをしています。ちなみに、コンテナを作成する際にネットワークを指定しないとデフォルトのBridgeネットワークにアタッチされるような設定がされています。

補足:awsvpc

こちらはAWSのECSの話になりますので、興味がなければスキップで大丈夫です。ECSのタスクを定義する際にネットワークモード指定しますが、その中に上記の3つ意外にawsvpcというものが紛れ込んでます。

これはECS特有のもので、ECSクラスター上で作成される全てのタスクに固有のENIを付与するものとなります。ENIを一つ一つのタスクに付与することでSGをタスクごとに割り当てることができ、より細部までセキュリティ対策ができる仕組みになっています。より詳しい内容はドキュメントを参考にしてください。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-networking.html

Dokcerボリュームとは

Dockerボリュームは、コンテナ同士で同じマウントポイントを参照できる機能となります。コンテナが共通して使用するファイルがあればボリュームを作成し、コンテナがこちらのボリュームにマウントして使用することが可能になります。

共有ボリューム

例えば、DBMS(例えばMySQL)のコンテナを作成するとします。もしコンテナを作成し、そのコンテナの中にデータを保存していくと、コンテナに不具合が起きて新しいコンテナを作成しなければならない時にとても大変なことになります。せっかく簡単に環境を作成して消せるのがメリットであるDockerの良さをいかせてないですね。そのような時はデータベースが取り扱うデータをホストに保存し、コンテナで作成したDBMSはそこにマウントしておけば問題なく使えます。

さらに大事なことは、Dockerの思想に関することです。Dockerは思想として、コンテナはただのプロセスであるので一時的なものであり、その中身に差がないようなことが起きてはならないという考え方で作られました。まさにこのボリュームがその考え方を代弁するものとなりますね。

ボリュームを種類には2種類あり、Dockerデーモンがボリュームを作成してコンテナ同士で共有するスペースを作成するVolumesとホストのファイルシステム上にコンテナをマウントするBind Mountがあります。

volumes on the Docker host

それぞれ詳細をみてみましょう。

Volumes

Dockerデーモンがスペースを作成し、それをコンテナ同士で共有するやり方となります。作り方はdocker volume create {ボリューム名}で作成でき、こちらにコンテナをマウントする時はdocker container run -v {ボリューム名}/:{コンテナのパス}でマウントすることができます。

kong@KongnoAir docker % docker volume create test  // testという名のボリューム作成
test
kong@KongnoAir docker % docker volume ls
DRIVER              VOLUME NAME
local               test
kong@KongnoAir docker % docker container run -it -v test:/test busybox sh  // busyboxのshを起動します
/ # ls
bin   dev   etc   home  proc  root  sys   test  tmp   usr   var
/ # cd test
/test # ls  // 何もない状態
/test # echo "hello from volume!!" >> hello.txt
/test # ls
hello.txt
/test # cat hello.txt 
hello from volume!!
/test # exit
kong@KongnoAir docker % docker container run -it -v test:/test busybox sh  // 新しいコンテナを作成
/ # ls
bin   dev   etc   home  proc  root  sys   test  tmp   usr   var
/ # cd test/
/test # ls
hello.txt  // 先のコンテナで作成したファイルを確認できます
/test # cat hello.txt 
hello from volume!!

Bind mount

Bind mountは、ホストのファイルシステム上にコンテナをそのままマウントすることを指しています。別途ボリュームを用意する必要はなく、ホストマシンで修正した内容はそのままコンテナにも反映されます。こちらはコンテナを作成する際にdocker container run -v /{ホストのパス}:/{コンテナのパス}で指定可能です。ホストのパスを入力する際にスラッシュが入ってるのが違いですので、忘れずにつけましょう。

kong@KongnoAir ~ % pwd
/Users/kong
kong@KongnoAir ~ % echo "hello from host" >> hello.txt
kong@KongnoAir ~ % cat hello.txt
hello from host
kong@KongnoAir ~ % docker container run -v /Users/kong:/test -it busybox sh
/ # exit
kong@KongnoAir ~ % docker container run -v /Users/kong:/test -it --name bind_mount busybox sh  // bind_mountという名前のコンテナを作成
/ # ls
bin   dev   etc   home  proc  root  sys   test  tmp   usr   var
/ # cd test/
/test # ls
hello.txt  <私のホームディレクトリにある諸々のものは省略します…>
/test # cat hello.txt 
hello from host
/test # exit
kong@KongnoAir ~ % echo "hello from host again" >> hello.txt
kong@KongnoAir ~ % docker container start bind_mount                                                                                                         ~
bind_mount
kong@KongnoAir ~ % docker container exec -it bind_mount sh  // bind_mountという名前のコンテナのshを起動                                                                                                ~
/ # cat test/hello.txt 
hello from host
hello from host again

このように、ホストマシンで加えた修正がコンテナ上にも反映されていることがわかります。

最後に

今回はネットワークとボリュームについてみてみました。どちらもコンテナ同士で連携をする際に必ず必要な知識ですのでぜひ覚えておきましょう。次はオーケストレーションサービスであるswarmについてみてみたいと思います。それでは、お元気で!