Skip to content

Docker インフラ構築プロジェクト - システム設計・アーキテクチャ解説書

このドキュメントは、本プロジェクトにおけるシステム設計およびアーキテクチャを効果的に説明、実演するための概要書です。 各項目について「設定の説明」「実演(デモ)方法」「背景知識」をまとめています。

NOTE

ドメイン名について: 本ドキュメントでは例として local.dev と記述していますが、実際の環境に合わせて適宜読み替えてください。

1. TLSv1.2 / TLSv1.3 の実演確認

要件: NGINXコンテナはTLSv1.2またはTLSv1.3 のみ を使用する。

✅ 実演方法 (デモ)

  1. ブラウザでの確認(基本):

    • ブラウザで https://local.dev にアクセス。
    • アドレスバーの鍵アイコンをクリック -> 「この接続は保護されています」 -> 「詳細を表示」または「証明書」を確認。
    • プロトコルの欄に TLS 1.2 または TLS 1.3 と表示されていることを示す。
  2. コマンドラインでの厳密な確認:

    • 以下のコマンドを実行して、古いプロトコルで接続できないことを証明する。
    bash
    # TLS 1.0 で接続試行(接続拒否またはハンドシェイク失敗すること)
    openssl s_client -connect local.dev:443 -tls1
    # 期待される出力 (NGパターン):
    # 140366254589248:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl/record/rec_layer_s3.c:1543:SSL alert number 40
    # または "Secure Renegotiation IS NOT supported" など、接続が確立されないこと。
    
    # TLS 1.1 で接続試行(同様に失敗すること)
    openssl s_client -connect local.dev:443 -tls1_1
    
    # TLS 1.2/1.3 で成功すること
    openssl s_client -connect local.dev:443 -tls1_2
    openssl s_client -connect local.dev:443 -tls1_3
    
    # 期待される出力 (OKパターン):
    # New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
    # ...
    # SSL-Session:
    #     Protocol  : TLSv1.3
    # ...
  3. 証明書のドメイン名 (CN) の確認:

    • 以下のコマンドで、証明書の発行先ドメイン名 (CN) が正しく設定されているか確認できます。
    bash
    # コンテナ内の証明書情報を表示し、Subject(所有者情報)の行を抽出
    docker exec nginx openssl x509 -in /etc/nginx/ssl/inception.crt -text -noout | grep "Subject:"
    
    # 出力例:
    # Subject: C = JP, ST = Tokyo, L = Minato, O = MyOrganization, OU = Dev, CN = local.dev
    • CN = ... の部分が、設定したドメイン名になっていればOKです。

🔑 補足: 自己署名証明書作成コマンドの解説

Dockerfile で実行している openssl コマンドの各オプションの意味は以下の通りです。

bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 ...
  • req: 証明書署名要求 (CSR) の作成や処理を行うサブコマンド。
  • -x509: CSRではなく「自己署名証明書」を直接出力します。
  • -nodes: "No DES" の略。秘密鍵を暗号化しません(パスワードなし)。これを設定しないとNginx起動時にパスワード入力を求められ、自動起動できません。
  • -days 365: 有効期限を365日に設定します。
  • -newkey rsa:2048: 新しい2048ビットのRSA秘密鍵を作成します。
  • -keyout / -out: それぞれ秘密鍵と証明書の出力先パスです。
  • -subj: 証明書の所有者情報(Subject)をコマンドで指定します。
    • CN=... (Common Name) にドメイン名を設定することが最も重要です。詳しくは .envDOMAIN_NAME が反映されます。

📝 背景解説 (TLS)

  • 概要: TLS (Transport Layer Security) はインターネット通信を暗号化するプロトコル。SSLの後継。
  • 歴史と安全性: TLS 1.0/1.1 は脆弱性(POODLE, BEAST等)があるため現在非推奨。TLS 1.2/1.3 は安全性が高く、現在のウェブ標準。
  • 仕組み:
    • 非セキュア(HTTP): 平文で送信。盗聴・改ざんが可能。
    • セキュア(HTTPS/TLS): 「ハンドシェイク」で鍵交換を行い、共通鍵で通信内容を暗号化。サーバー証明書により「接続先が正当であること」を保証。

2. システム構成図 (C4モデル / UML)

要件: システム全体のアーキテクチャを図解で説明できること。

🖼 図解のポイント (ホワイトボードや画面で説明)

Docker Compose 構成図

  • 解説の流れ:
    1. Entrypoint: すべての外部トラフィックはNGINXだけが受け取る(ポート443のみ開放)。
    2. Isolation: WordPressやMariaDBは外部にポートを公開せず、内部ネットワーク inception 内でのみ通信する。
    3. Persistence: データの永続化のためにボリュームを使用。

3. WordPress & MariaDB の連携・動作実演

要件: 各コンテナが正しく動作し、連携していることを示す。

✅ 実演方法

  1. WordPress動作確認:
    • 記事の投稿、コメント、画像のアップロードを行い、正常に動作することを見せる。
    • 管理画面: wp-admin にアクセスし、ユーザー一覧を見せる(admin という名前が含まれていないこと)。
  2. DB連携の確認:
    • ターミナルからMariaDBコンテナに入る:
      bash
      docker exec -it mariadb mariadb -u user -p
      # パスワード入力
    • SQLを実行してWordPressのデータを確認:
      sql
      USE wordpress;
      SELECT user_login FROM wp_users;
    • ブラウザ上のユーザー名とDB内のデータが一致していることを示す。

📝 背景解説 (DBとWordPress)

  • 仕組み: WordPress (PHPプログラム) は、ページを表示するたびにMariaDB (データベース) にクエリを投げ、記事本文や設定を取得してHTMLを生成している。
  • PHP-FPM: NGINXは静的ファイルしか扱えないため、.php リクエストは FastCGI プロトコルで WordPress コンテナ(PHP-FPM)に転送し、実行結果を受け取る。

4. ネットワークと自動再起動 (Docker)

要件: ネットワークの分離、コンテナクラッシュ時の挙動。

✅ 実演方法

  1. ネットワーク分離の証明(Network: hostお断り):
    • ホストマシンから mysql -h 127.0.0.1 -P 3306 ... を実行し、接続できないことを示す(ポートが開いていないため)。
    • これにより「NGINX経由以外でアクセスできない=安全」であることを証明。
  2. 自動再起動 (Restart Policy):
    • 稼働中のMariaDBコンテナを強制終了させる(擬似クラッシュ):
      bash
      docker exec -it mariadb pkill mysqld
    • 直後に docker ps を連打し、STATUSが数秒で Up に戻る(または再起動中になる)様子を見せる。
    • Restart: always によりデーモン化されたコンテナが維持されていることを説明。

📝 背景解説

  • Docker Network: bridge モードを使用(デフォルト)。コンテナ同士はコンテナ名(wordpress, mariadb)で名前解決(DNS)して通信する。
  • 禁止事項: network: host はコンテナの隔離性を失うため禁止。--link は古い機能で非推奨のため禁止。

5. ボリュームとデータ永続化

要件: /home/login/data へのマウントと理由。

✅ 実演方法

  1. ファイル存在確認(自動設定):
    • docker-compose.yml${USER} 環境変数を使用しており、実行ユーザー(あなた)のホームディレクトリ下に自動的にディレクトリが割り当てられます。
    • ホスト側の /home/${USER}/data/wordpress にファイルがあることを ls -la で見せる。
  2. 永続化の証明:
    • make down でコンテナを削除。
    • make up で再構築。
    • 記事やDBデータが消えていないことをブラウザで確認。

📝 背景解説

  • 理由: コンテナは使い捨て(Ephemeral)。コンテナを消すと内部データも消えるため、重要なデータ(DBファイル、アップロード画像)はコンテナ外(ボリューム)に保存する必要がある。
  • 自動割り当て: docker-compose.yml 内の device: /home/${USER}/data/... 記述により、誰が実行してもそのユーザーのホーム配下にデータ領域が確保される仕組みになっている。
  • Dockerコンテナ vs VM: コンテナはOSカーネルをホストと共有し、プロセスとして隔離されている(軽量)。VMはハードウェアごと仮想化しOSを丸ごと動かす(重量)。

6. Dockerfile & Best Practices

要件: PID 1問題、latest禁止、Secrets。

📝 技術解説

  • PID 1 問題:
    • コンテナのメインプロセス(PID 1)はシグナル(Ctrl+Cなど)を受け取って子プロセスに伝播させる責任がある。
    • シェル形式(CMD echo hi)だと /bin/sh がPID 1になり、アプリにシグナルが届かず正常終了できない問題が起きる。
    • 対策: exec "$@" をスクリプトの最後で使うことで、メインプロセスをシェルから対象アプリ(nginx, mysqld等)に置き換えている。
  • latestタグ禁止:
    • debian:latest だと、いつビルドするかによってバージョンが変わってしまい、再現性がなくなる(壊れる可能性がある)。debian:bullseye など固定タグを使うべき。
  • 環境変数とSecrets:
    • パスワード等をDockerfileに書くのは危険(GitHubに残る)。
    • .env ファイルや Docker Secrets 機能を使って外部から注入するのがセキュア。

X. 校舎PC(sudo権限なし)でのレビュー対応

校舎のiMacなど、ホストOSの /etc/hosts を編集する権限がない環境で、「ブラウザでドメイン名アクセス」 の要件をどう証明するかのアプローチです。

アプローチA: 「IPアクセス+証明書確認」で代用する(推奨)

ブラウザのアドレスバーにドメイン名を入れることはできませんが、「このIPアドレスが正しいドメイン(証明書)を持っていること」 は証明できます。

  1. ホストOSのブラウザで、VMのIPアドレス(またはポート転送していれば localhost)にアクセス。 https://192.168.65.11 または https://localhost
  2. 「保護されていない通信」等の警告画面が出ます。
  3. 「詳細設定」→「証明書を表示(View Certificate)」 をクリック。
  4. 証明書の内容が表示されるので、Subject (CN) が local.dev になっていること を確認します。
  5. 同時に、curl コマンド(下記)を使って、「ドメイン名でアクセスした場合に正しくつながる」技術的裏付けを見せます。
    bash
    # ホストOSのターミナルで実行
    curl -v -k --resolve local.dev:443:192.168.65.11 https://local.dev

アプローチB: VM内にGUIを入れてブラウザを使う(最強の証明)

「どうしてもブラウザのアドレスバーにドメイン名を表示させたい」とレビュワーが譲らない場合の最終手段です。 ゲストOS(Debian VM)の中にデスクトップ環境とFirefoxをインストールし、ゲストOSの中でWebサイトを開きます。

bash
# ゲストOSで実行(インストールに数分〜十数分かかります)
sudo apt-get update
sudo apt-get install -y task-gnome-desktop firefox-esr
sudo reboot

再起動後、VMがグラフィカルモードで立ち上がるので、ログインしてFirefoxを開き https://local.dev にアクセスすれば、設定なしで繋がります(ゲストOSの /etc/hosts は設定済みのため)。

アプローチC: SSH SOCKSプロキシ(上級者向け・推奨)

「ホストのブラウザを使いたい」かつ「ホストの設定は変えられない」場合の最もスマートな解決策です。 SSHの「ダイナミックポートフォワード」機能を使って、ブラウザの通信をすべてVM経由にします。

  1. SSHトンネルの作成: ホストOSのターミナルで以下のコマンドを実行します。

    bash
    # -D 8080: ローカルの8080ポートをSOCKSプロキシとして開く
    # -N: シェルを実行せず転送のみ行う(フォアグラウンドで待機)
    ssh -D 8080 -N debian@192.168.65.11

    (パスワードを聞かれたら入力し、そのまま画面が止まった状態にします)

  2. ブラウザの設定 (Firefox推奨): Mac/Windowsの Firefox は、システム設定とは独立してプロキシ設定ができるため最適です。

    • Firefox設定 -> 一般 -> ネットワーク設定 -> 「接続設定...」
    • 「手動でプロキシを設定する」 を選択
    • SOCKS ホスト: localhost, ポート: 8080
    • SOCKS v5 を選択
    • 「SOCKS v5 使用時は DNS もプロキシする (Proxy DNS when using SOCKS v5)」 にチェックを入れる(最重要
    • 「OK」で保存
  3. 接続確認: ホストのFirefoxで https://local.dev にアクセスします。

    • ブラウザからのリクエストがSSHトンネルを通ってVMに届きます。
    • VM側で DNS解決が行われるため、VM内の /etc/hosts が適用されます。
    • 結果、きれいにサイトが表示されます。

補足: ゲストOS内でドメイン解決を確認するコマンド

「本当にドメインが通っているのか?」と聞かれた場合、以下のコマンドで設定状況を証明できます。

bash
# ドメイン名がどのIPに変換されるか確認
getent hosts local.dev
# 出力例: 192.168.65.11   local.dev

# ドメイン名で通信できるか確認
ping -c 3 local.dev

7. その他チェックリスト

  • [ ] ドメイン設定: ゲストOSの /etc/hosts127.0.0.1 local.dev が設定されていること。
  • [ ] ユーザー名: WordPress管理者ユーザー名に adminAdmin が含まれていないこと。
  • [ ] 解析ツール: ブラウザの開発者ツール (F12) > Networkタブで、HTTPヘッダ情報を見てServer情報等を確認するデモも有効。

8. Makefile コマンド解説

Makefileは、長く複雑なdockerコマンドを短いショートカットで実行するためのものです。開発時やレビュー時に頻繁に使用します。

コマンド説明・使用シーン実際の処理内容
make all【基本】システム起動
最初に環境を立ち上げる時や、停止後に再開する時に使います。必要なデータディレクトリも自動作成します。
1. /home/${USER}/data/ 配下にディレクトリ作成
2. docker compose up -d --build でビルドしてバックグラウンド起動
make downシステム停止
作業終了時や、一旦クリーンにしたい時に使います。コンテナとネットワークを削除しますが、ボリューム(データ)は残ります
docker compose down
make re再構築(リブート)
設定ファイルを書き換えた後に反映させたい時や、調子が悪い時に「電源オフ・オン」の感覚で使います。
make down してから make all を実行
make clean完全削除(データ以外)
コンテナ、ネットワークに加え、作成したDockerイメージやボリューム定義も削除します。※ホスト側のデータは消えません。
docker compose down --rmi all --volumes
make fclean初期化(全消去)
Dockerシステム上の未使用データを全て削除します。ディスク容量を空けたい時などに使います。
make clean 後に docker system prune -af

💡 レビュー時のポイント

  • 「どうやって起動しますか?」と聞かれたら、自信を持って make all で一発で起動します」 と答え、実演してください。
  • 「データを残したまま終了するには?」と聞かれたら make down です。データはホスト側のボリュームに残ります」 と答えます。

9. docker-composeを使うイメージと使わないイメージの違い

要件: 「docker-composeを使う場合と使わない場合で、Dockerイメージに違いはあるか?」という質問への回答。

📝 回答のポイント

「イメージ自体は同じですが、動く環境(コンテキスト)が異なります」 が正解です。

  1. イメージの共通性:

    • Dockerfile から作られるイメージそのものは、docker build で作ろうが docker compose build で作ろうが、中身(ファイルシステム、インストールされたアプリ)は同じです。
  2. 実行時の違い (Runtime Context):

    • docker-compose使用時:
      • ネットワーク: 自動的に専用のDNS名(サービス名)で通信できる(例: wordpress という名前で接続可能)。
      • 環境変数: .env ファイルや docker-compose.yml から自動注入される。
      • ボリューム: 宣言的に管理され、自動マウントされる。
    • docker-compose未使用時 (docker run):
      • これらを全て手動オプション(--network, --env, -v)で指定しないと、同じようには動かない。
      • 特に本プロジェクトのような「DBホスト名を mariadb と決め打ちしている」コンテナ構成は、--network設定なしの単独起動では名前解決できずにエラーになる。

具体的な説明例

「WordPressのイメージ自体は変わりませんが、Composeを使わない場合は docker run --network inception -e MYSQL_HOSTNAME=mariadb ... のように長いオプションを全部手動で書く必要があります。Composeはそれを『コード化』して自動セットアップしてくれるツールです。」

10. Docker Compose vs Docker CLI (非使用)

本プロジェクトでは docker-compose を採用していますが、「なぜ docker-compose を使うのか?」「docker コマンド単体ではダメなのか?」という疑問についての解説です。

🐢 Docker CLI (Compose非使用)

docker run コマンドでコンテナを1つずつ起動する方法です。

  • 特徴:
    • コンテナ単体の細かい制御や、一時的な検証に向いています。
    • 依存関係(DBが立ち上がってからWordPressを起動など)を人間が管理する必要があります。
  • デメリット:
    • コマンドが複雑化する: ネットワーク、ボリューム、環境変数をすべてオプションで指定する必要があります。
      bash
      # 例: ネットワーク接続とボリュームマウントの手動実行
      docker run -d --name mariadb --network inception -v db_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=... mariadb:bullseye
    • 再現性が低い: 長いコマンドを打ち間違えたり、オプションを忘れたりしやすく、チーム開発での再現が困難です。
    • 自動化が手間: シェルスクリプト (.sh) で自動化することも可能ですが、保守性に欠けます。

🐙 Docker Compose (Compose使用)

複数のコンテナ定義を docker-compose.yml という1つのファイルにまとめて管理する方法です。

  • 特徴:
    • Infrastructure as Code (IaC): インフラ構成をコード(YAML)として保存・バージョン管理できます。誰が実行しても同じ環境が立ち上がります。
    • オーケストレーション: 複数のコンテナの起動順序、依存関係、ネットワーク接続を一括で管理できます。
  • メリット (本プロジェクトでの採用理由):
    • 一括操作: docker compose up だけで全サービス(NGINX, WordPress, MariaDB)が正しい順序と設定で立ち上がります。終了も down 一発です。
    • 自動ネットワーキング: 明示的に docker network create しなくても、プロジェクト専用のネットワークを作成し、サービス名(mariadbなど)で名前解決できるようにしてくれます。
    • 保守性: 設定変更は YAML ファイルを書き換えるだけ。コマンドオプションを極力減らすことができます。

結論: 複雑な連携が必要な本プロジェクトの Web サービスにおいて、設定ミスを防ぎ、一貫した環境を即座に構築するために Docker Compose は不可欠です。

参考リソース

Released under the MIT License.