ポート管理から解放されよう:TraefikとLet’s EncryptでDockerトラフィックを自動化する

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

80番ポートの競合:Docker環境がいつか壁にぶつかる理由

誰もが経験することです。1つのDockerコンテナから始め、ポート8080を80にマッピングすれば、すべてがうまくいきます。しかし、2つ目のプロジェクトや3つ目のサービス、あるいはプライベートな分析ダッシュボードを追加すると、途端に行き詰まります。1つのIPアドレスで2つのコンテナをポート80にマッピングすることはできません。結局、自作ツールにアクセスするためだけに、your-ip:8081your-ip:8082といった奇妙なURLを暗記する羽目になります。

さらに、SSLの悪夢がやってきます。5つの異なるコンテナに対して、Certbotとcronジョブを使って手動でLet’s Encryptの証明書を管理するのは、トラブルの元です。設定ファイルのわずかな構文ミスに気づかず、証明書が失効してしまい、何時間も睡眠時間を削られた経験が私にもあります。この手動作業こそが、ホームラボや本番環境をスケールさせる上での最大の障害です。

課題:動的なコンテナの世界における静的な設定

問題は単純です。動的な環境に対して静的なツールを使っていることです。NginxやHAProxyのような従来のプロキシは、IPアドレスが何年も変わらない「ペット」のようなサーバーの時代に作られました。Dockerにおいて、コンテナは一時的なものです。アップデートのたびに起動し、破棄され、内部IPアドレスが変わります。

従来のプロキシを使い続けるなら、新しいサービスをデプロイするたびに設定ファイルを手動で編集しなければなりません。新しいアプリがどこにあるのか(例:172.18.0.5)をプロキシに正確に伝える必要があります。この手動ステップこそがデプロイの遅延や設定の乖離(Configuration Drift)を招きます。5分で終わるはずのタスクが、30分のトラブルシューティングに変わってしまうのです。

ソリューションの比較:Nginx vs. Traefik

この混乱から抜け出す方法を探すと、通常3つの主要な選択肢が浮上します:

  • 手動のNginx/HAProxy: これらは非常に高性能ですが、設定の再読み込みやSSL用の外部サイドカーを手動で管理する必要があります。これらは安定性のために設計されており、変化の速いコンテナの世界向けではありません。
  • Nginx Proxy Manager: 直感的なWebインターフェースを提供します。初心者には最適ですが、新しいサービスを追加するたびに手動でクリック操作が必要です。バージョン管理(GitOps)による管理は困難です。
  • Traefik Proxy: 「クラウドネイティブ」なプロキシです。バックエンドの静的なリストを持つ代わりに、Dockerソケットを監視します。コンテナが起動すると、Traefikは即座にそれを検知します。コンテナに適切なラベルが付いていれば、Traefikはユーザーが何もしなくてもルートを作成し、SSL証明書を取得します。

より良い方法:Traefikによるサービスディスカバリ

TraefikがDockerにとって論理的な選択である理由は、設定をメタデータとして扱うからです。実際、docker-compose.ymlに6〜7行追加するだけで、完全に保護された本番レベルのWebサービスをデプロイできます。複雑な設定をプロキシ側から切り離し、アプリケーションのデプロイ自体に組み込むことができます。

ステップ1:インフラの準備

まず、プロキシがアプリと通信するための共有ネットワークが必要です。また、SSLキーを保存するための、権限を厳格に制限した専用ファイルも必要です。

# 共有プロキシネットワークを作成
docker network create proxy-net

# SSL保存用ファイルを作成し、パーミッションを制限する
touch acme.json
chmod 600 acme.json

ステップ2:Traefikコアの起動

このDocker Composeファイルは、ルーティングの「頭脳」をセットアップします。ポート80と443を開放し、Traefikがコンテナを監視できるようにDockerソケットへの読み取り専用アクセスを許可します。

version: "3.8"

services:
  traefik:
    image: traefik:v2.10
    container_name: traefik
    restart: always
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy-net
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.myresolver.acme.email=admin@yourdomain.com"
      - "--certificatesresolvers.myresolver.acme.storage=/acme.json"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.tls.certresolver=myresolver"

メールアドレスとドメインのプレースホルダーを実際の情報に書き換えてください。これが実行されると、TraefikはHTTP-01チャレンジを通じてLet’s Encryptのハンドシェイクを自動的に処理します。

ステップ3:手動設定なしでアプリをデプロイする

ここからが面白くなるところです。HTTPS対応の新しいアプリをオンラインにする際、Traefikを触る必要はありません。アプリケーションにラベルを貼るだけです。例として、シンプルな「Whoami」サービスを挙げます。

services:
  webapp:
    image: traefik/whoami
    container_name: web-app
    networks:
      - proxy-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.yourdomain.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure"
      - "traefik.http.routers.webapp.tls.certresolver=myresolver"

docker-compose up -dを実行すると、Traefikは新しいコンテナを検出します。app.yourdomain.comのルールを確認し、証明書をリクエストして、トラフィックのルーティングを開始します。これらは通常10秒以内に完了します。

ミドルウェアによる制御の追加

Traefikは単にトラフィックを流すだけではありません。動的に変更を加えることも可能です。ミドルウェアを使用すると、アプリケーションのコードを一行も変えることなく、Basic認証やレート制限などの機能を追加できます。例えば、機密性の高いダッシュボードをパスワードで保護するには、以下のラベルを追加します。

# htpasswdを使用してハッシュを生成
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..."
- "traefik.http.routers.dashboard.middlewares=auth"

これは、ログイン機能が組み込まれていない内部ツールに、素早くセキュリティレイヤーを追加するのに最適です。

メンテナンスとベストプラクティス

Traefikの設定は専用のディレクトリに保管してください。Traefikを/opt/traefikに、他のアプリをそれぞれのフォルダに配置する構成をお勧めします。このように隔離することで、一つのアプリのcomposeファイルにあるタイポが原因でプロキシ全体がダウンするのを防げます。

よくある間違いは、クラウドのファイアウォール(AWS의セキュリティグループやUFWなど)でポート80と443を開放し忘れることです。ポート80がブロックされていると、Let’s Encryptはドメインを確認できず、SSL証明書は生成されません。新しいサービスを立ち上げる前に、必ずDNSのAレコードを再確認してください。

新しいワークフロー

  1. グローバルなproxy-netネットワークを起動する。
  2. Traefikを一度実行し、Dockerソケットを監視させる。
  3. 必要な時にいつでも、traefik.enable=trueラベルを付けてアプリをデプロイする。
  4. TraefikがSSLとルーティングを処理する間、他の作業に取り掛かる。

このセットアップにより、インフラは脆弱なファイルの集まりから、自己修復システムへと変貌します。デバッグの時間を節約し、起動したすべてのサービスが公開された瞬間からデフォルトで安全であることを保証します。

Share: