118
128

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

改めてDockerを理解する⑥[Dockerのネットワークについて]

Last updated at Posted at 2025-01-05

はじめに

こんにちは!ITスクールRareTECHにてCS(Customer Support)を担当している池村です。今回の記事はDockerのネットワークについてです。ここは初学者にとってとてもつまづきやすいポイントだと思っています。

というかネットワークの知識が必須なんですよね。ネットワークの基礎を疎かにしていると痛い目を見ます。(ブーメランですが💧)

281209c1-26d6-49a2-92f8-71086936b543_720.png

Dockerネットワークとは

コンテナの中は、基本的に独立した環境なので、外との通信や、コンテナ間の通信を実現させるためにはネットワークを繋げてあげる必要があります。

Dockerのネットワークは作ることができます。
まずは作り方から見ていきましょう。

ネットワークを作成
docker network create my_network

上記のコマンドを叩くと、ネットワークが作成できます。

ネットワーク一覧を確認
docker network ls

上記コマンドを叩くことで、一覧が出ると思います。
デフォルトでいくつかあるネットワークについては後ほど説明するとして、先ほど作成したmy_networkはあるでしょうか?

次にネットワークの詳細を見てみましょう。

ネットワークの詳細
docker network inspect my_network

以下が筆者のローカル環境上の表示結果です。

実行結果
[
    {
        "Name": "my_network",
        "Id": "eb552f0eafb95b88844be750416ba7c19cff66a903b6fc30ce81b175776b7442",
        "Created": "2025-01-04T14:44:19.314223857+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.117.0/24",
                    "Gateway": "192.168.117.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

全部を理解する必要は本当にないのですが、主要なところは押さえておきたいですね。

Name

ネットワークの名前ですね。

Id

ネットワークを識別するためのユニークなIDです。

Created

作成した日時ですね。

Scope

localになっているので、ローカルのホストのみ有効なネットワークです。要は自分のPC上で動くためだけのものです。(細かく言うと自身のPC上のDockerEngineのみ)これがglobalになっていると複数ホスト間で動きます。複数ホストは分散システムや別のサーバーで動くコンテナとも共有できるという意味です。

Driver

ネットワークの種類です。詳しくは後述します。

IPAM

ここはかなり重要で、IPアドレスの管理について書かれています。特に重要なのが以下になります。
Subnet: 192.168.117.0/24
ネットワークの範囲(サブネット)です。このネットワーク内で使用できるIPアドレスが 192.168.117.1 から 192.168.117.254 に設定されています。
Gateway: 192.168.117.1
このネットワークのゲートウェイ(ルーターの役割を果たすアドレス)です。コンテナが外部のネットワークにアクセスする際にこのアドレスを使用します。

Containers

現在このネットワークが使われているコンテナを表示します。空なので、今は何も接続されていないただのネットワークです。

飛ばした項目は初学者が覚えてもあまり効果がないので、飛ばしてOKです。

ネットワークの種類について

このネットワークにもいくつか種類があるのでご紹介します。
ただ、基本はBridgeです。

Bridge

これはコンテナ間の通信を可能にするネットワークです。
これを作成することで、例えば何かしらの言語でWebアプリを動かすコンテナと、MySQLなどのデータベースを動かすコンテナ間を通信させることができます。前項で作成したのもBridgeネットワークになります。ポートフォワーディングを使うことで外部との接続も可能です。

Host

Hostは名前の通り、ホストであるサーバー or PCのネットワークを使って通信を行うことができます。ホストのネットワークを直接使うわけですから、速度に関してはとても早いです。もちろんポートもホストのポートを使うことができます。セキュリティの観点からもあまりオススメする繋ぎ方ではないと思っています。よっぽどのことがない限りBridgeを使いたいですね。
使いたい場合は以下のコマンドを叩いてください。

Hostの使い方
docker run --network host my_container

None

こちらはネットワークから完全に分離する形です。何も繋がっていないので外部とも別コンテナとも通信できません。私自身あまり使ったことないですね。

Noneの使い方
docker run --network none my_container

Overlay(上級者向け)

複数のホストにまたがったネットワークを作成します。
分散システム向けで、複数ホストをまたげる分速度もBridgeより遅いです。IPアドレスはDockerが管理しています。分散システム向けって何?と言われると、DockerSwarmやKubernetesのことを指すことが多いです。が、これらはかなり上級者向けて初学者はもっと後半で学習することになります。

Macvlan(上級者向け)

こちらは、コンテナが独自のIPアドレスとMACアドレスを持つことができるものです。これはルータとかスイッチからも独立したデバイスとして認識されるので、例えば家のプリンターとかとも直接通信できるわけです。ただ、IPアドレスを割り当ててあげる必要はあります。

ポートフォワーディングについて

ではポートフォワーディングについてみていきましょう。
これはホストのポートとコンテナのポートを繋げてあげることですね。そうすることでコンテナの中に外部の通信を送ることができます。

ポートとは?

ポートはPCやサーバーで通信を受け取る際の入り口のことですね。
コンピュータはどの通信をどのポートで受け取るか決まっています。例えばHTTPの通信なら80番、SSHの通信なら22番とかです。これはそのままプロトコル(通信規格)と関係しています。
すでに決まっているポートの他に、自由に使えるポートがあって、Dockerでコンテナに繋げるのはそちらの自由なポートになります。

ポート番号について詳しくなりたいなら、頑張ってググってください🖐️
ネットワークの基本の基本です。

やはり簡単な確認方法はWebサーバーですかね。以下のコマンドを叩いて実行してみましょう。

ポートフォワーディング
docker run -d -p 8080:80 nginx

NginxはWebサーバーをたてるためのアプリケーションです。これを使うことで、80番ポートでの通信が可能になります。
無事にコンテナが動き始めたら、以下のURLをクリックしてみましょう。

以下のような表示がされていれば、問題なく動いています。
image.png

これは、ホストの8080番ポートと、コンテナの中の80番ポートが繋がっているということです。URLのlocalhostは自身のPCを指していると思ってください。

ポートフォワーディングをするためのオプションは-pですのでお間違いなく。

Bridgeでコンテナ間通信をしてみよう

ではここからはコンテナ間通信をどうやって行うかをみていきましょう。
Webアプリが一番わかりやすい(自分が慣れている)ので、簡単なWebサーバーのコンテナと、データベースのコンテナを立ち上げて、その二つのコンテナ間で通信してみます。

この記事をどんな方が読むかわからないですが、今回はPython(記述量が比較的楽)で作成してみます。

Flask(Python)とMySQLのコンテナ間通信

Webサーバーとデータベースについて、ある程度理解している前提で進めさせていただきます。

MySQLのコンテナを作成

MySQLのコンテナを作成・起動
docker run --network my_network --name mysql_container \
    -e MYSQL_ROOT_PASSWORD=root \
    -e MYSQL_DATABASE=test_db \
    -e MYSQL_USER=user \
    -e MYSQL_PASSWORD=password \
    -d mysql:latest
コンテナの中のデータベースにアクセス
docker exec -it mysql_container mysql -u root -proot
テーブル一覧をみてみよう
SHOW DATABASES;

以下のように表示されていれば、test_dbのデータベースはできています。
image.png

ではテーブルを作っていきます。

使用するデータベースを選択する
USE test_db;

次にSQLを実行しましょう。今回は超シンプルなテーブルにします。

テーブルを作成するSQL
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

これでデータベースの準備は整いました。次はFlaskですね。

Flaskのコンテナを作成

コンテナを作成する前に、ローカルにディレクトリを作成して、そこにPythonのファイルを作成します。あとはrequirements.txtも必要ですね。ディレクトリはどの場所でも大丈夫です。ホームディレクトリに作るのはあまりおすすめしません。

作成方法
mkdir flask_app && cd flask_app && touch app.py requirements.txt

ディレクトリ構成は以下のようになっていればOKです。

コンテナにマウントするためのディレクトリ構成
.
└── flask_app
    ├── app.py
    └── requirements.txt

2 directories, 2 files

では次にapp.pyの中身を書いていきます。

app.pyの中身
from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)

db_config = {
    "host": "mysql_container",
    "user": "user",
    "password": "password",
    "database": "test_db"
}


@app.route('/add', methods=['POST'])
def add_data():
    data = request.json
    name = data.get("name")

    try:
        conn = mysql.connector.connect(**db_config)
        cursor = conn.cursor()
        cursor.execute("INSERT INTO users (name) VALUES(%s)", (name,))
        conn.commit()
        cursor.close()
        conn.close()
        return jsonify({"message": "success"})
    except mysql.connector.Error as err:
        return jsonify({"error": str(err)}), 500


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)

中身の簡単な説明をすると

  • 今回使うFlaskのライブラリ群をインポート
  • PythonでMySQLと接続するためのライブラリをインポート
  • http://localhost:5000/add 』というURLにPOSTリクエストでデータを送ると、そのデータをデータベースに登録する処理

でできています。

次にrequirements.txtの中身ですね。

requirements.txtの中身
Flask
mysql-connector-python

この二つができたら準備完了です。すでにMySQLのコンテナは動いているので、Flaskのコンテナも同じネットワークを指定して立ち上げます。

Flaskコンテナの起動
docker run --network my_network --name flask_container -v "$(pwd)/flask_app:/app" -w /app -p 5000:5000 python:3.9-slim sh -c "ls && pip install -r requirements.txt && python app.py"

以下のコマンドを叩くのはflask_appディレクトリのある場所です。
あとMacだと標準で5000番ポートが使われていたり、ローカルで動いているFlaskアプリとポートが競合する可能性があります。その際には5001:5000とか、5002:5000などポートの調整をするといいかもしれません。

無事サーバーが立ち上がったら、以下のようになるはずです。
image.png

curlコマンドでリクエストを送ってみる

もう一つターミナルを開いて(もしくはtmuxで分割して)、curlコマンドでPOSTリクエストを送ってみましょう。curlコマンドはWebサーバーにGETリクエストやPOSTリクエストを送ってレスポンスを受け取ることができるコマンドです。

curlコマンドで
curl -X POST -H "Content-Type: application/json" -d '{"name": "TestName"}' http://localhost:5000/add

ここも、5001や5002のポートにフォワーディングしているなら、そちらに合わせてください。

今回はTestNameという名前のデータをWebサーバーに送っています。これがデータベースに登録されているなら、二つのコンテナの通信はうまくいっています。

では実際に登録されているか確認してみます。

DBのコンテナにSQLを送ってみる
docker exec -it mysql_container mysql -u root -proot -e "SELECT * FROM test_db.users;"

これでテーブルが表示されていればOKです。
検証のため、私はいくつかデータを送ってみましたが、問題なく登録されていますね。
image.png

おわりに

Dockerのネットワークの話が終わったので、ようやくDockerfileの話に入れそうです。
正直、コマンドの記述量的に非効率すぎて大変なので、もっと簡略化するためにDockerfileを早く使いたかったです。ただ、ここは順番なのでここまでが基礎、ここからが応用的な話として割り切りっていきたいですね。

改めて、基礎は大事です。ただ基礎ばっかりやってるとつまらないのが難点。

次の記事👇

118
128
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
118
128

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?