ネットワーキング
このページでは、隔離されたDockerデーモン内で実行されているサービスをインターネットからアクセス可能にする方法を説明します。リバースプロキシシステム、ルーティング用Dockerラベル、TLS証明書、DNS、TCP/UDPポートフォワーディングについて説明します。
サービスがループバックIPを取得する仕組みと.rediacc.jsonスロットシステムについては、サービスを参照してください。
仕組み
Rediaccは、外部トラフィックをコンテナにルーティングするために2コンポーネントのプロキシシステムを使用します:
- ルートサーバー — すべてのリポジトリDockerデーモンにわたって実行中のコンテナを検出するsystemdサービス。コンテナラベルを検査し、YAMLエンドポイントとして提供されるルーティング設定を生成します。
- Traefik — 5秒ごとにルートサーバーをポーリングし、検出されたルートを適用するリバースプロキシ。HTTP/HTTPSルーティング、TLS終端、TCP/UDPフォワーディングを処理します。
フローは以下の通りです:
インターネット → Traefik (ポート 80/443/TCP/UDP)
↓ 5秒ごとにポーリング
ルートサーバー (コンテナを検出)
↓ ラベルを検査
Dockerデーモン (/var/run/rediacc/docker-*.sock)
↓
コンテナ (127.x.x.x ループバックIPにバインド)
適切なラベルをコンテナに追加してrenet composeで起動すると、自動的にルーティング可能になります。手動のプロキシ設定は不要です。
Dockerラベル
ルーティングはDockerコンテナラベルで制御されます。2つのティアがあります:
ティア1:rediacc.*ラベル(自動)
これらのラベルは、サービス起動時にrenet composeによって自動的に注入されます。手動で追加する必要はありません。
| ラベル | 説明 | 例 |
|---|---|---|
rediacc.service_name | サービスID | myapp |
rediacc.service_ip | 割り当てられたループバックIP | 127.0.11.2 |
rediacc.network_id | リポジトリのデーモンID | 2816 |
コンテナがrediacc.*ラベルのみを持つ場合(traefik.enable=trueなし)、ルートサーバーは自動ルートを生成します:
{service}-{networkID}.{baseDomain}
例えば、ネットワークID 2816とベースドメインexample.comのリポジトリ内のmyappというサービスは以下を取得します:
myapp-2816.example.com
自動ルートは開発や内部アクセスに便利です。カスタムドメインを使用する本番サービスには、ティア2ラベルを使用してください。
ティア2:traefik.*ラベル(ユーザー定義)
カスタムドメインルーティング、TLS、特定のエントリポイントが必要な場合は、docker-compose.ymlにこれらのラベルを追加します。traefik.enable=trueを設定すると、ルートサーバーに自動ルートの代わりにカスタムルールを使用するよう指示します。
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=8080"
これらは標準のTraefik v3ラベル構文を使用します。
ヒント: 内部専用サービス(データベース、キャッシュ、メッセージキュー)には
traefik.enable=trueを設定しないでください。自動的に注入されるrediacc.*ラベルのみが必要です。
HTTP/HTTPSサービスの公開
前提条件
-
マシンにインフラストラクチャが設定されていること(マシンセットアップ — インフラストラクチャ設定):
rdc context set-infra server-1 \ --public-ipv4 203.0.113.50 \ --base-domain example.com \ --cert-email admin@example.com \ --cf-dns-token your-cloudflare-api-token rdc context push-infra server-1 -
ドメインのDNSレコードがサーバーのパブリックIPを指していること(下記のDNS設定を参照)。
ラベルの追加
公開したいサービスのdocker-compose.ymlにtraefik.*ラベルを追加します:
services:
myapp:
image: myapp:latest
network_mode: host
environment:
- LISTEN_ADDR=${MYAPP_IP}:8080
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=8080"
database:
image: postgres:17
network_mode: host
command: ["-c", "listen_addresses=${DATABASE_IP}"]
# traefikラベルなし — データベースは内部専用
| ラベル | 目的 |
|---|---|
traefik.enable=true | このコンテナのカスタムTraefikルーティングを有効化 |
traefik.http.routers.{name}.rule | ルーティングルール — 通常はHost(\domain`)` |
traefik.http.routers.{name}.entrypoints | リッスンするポート:websecure(HTTPS IPv4)、websecure-v6(HTTPS IPv6) |
traefik.http.routers.{name}.tls.certresolver | 証明書リゾルバ — 自動Let’s Encryptにはletsencryptを使用 |
traefik.http.services.{name}.loadbalancer.server.port | コンテナ内でアプリケーションがリッスンするポート |
ラベル内の{name}は任意の識別子です。関連するルーター/サービス/ミドルウェアラベル間で一貫している必要があります。
注意:
rediacc.*ラベル(rediacc.service_name、rediacc.service_ip、rediacc.network_id)はrenet composeによって自動的に注入されます。composeファイルに追加する必要はありません。
TLS証明書
TLS証明書はCloudflare DNS-01チャレンジを使用してLet’s Encrypt経由で自動的に取得されます。インフラストラクチャ設定時に一度だけ設定します:
rdc context set-infra server-1 \
--cert-email admin@example.com \
--cf-dns-token your-cloudflare-api-token
サービスにtraefik.http.routers.{name}.tls.certresolver=letsencryptが設定されている場合、Traefikは自動的に以下を行います:
- Let’s Encryptから証明書をリクエスト
- Cloudflare DNS経由でドメイン所有権を検証
- 証明書をローカルに保存
- 有効期限前に更新
Cloudflare DNS APIトークンには、保護したいドメインに対するZone:DNS:Edit権限が必要です。このアプローチはCloudflareで管理されるすべてのドメイン(ワイルドカード証明書を含む)に対応しています。
TCP/UDPポートフォワーディング
非HTTPプロトコル(メールサーバー、DNS、外部公開するデータベース)には、TCP/UDPポートフォワーディングを使用します。
ステップ1:ポートの登録
インフラストラクチャ設定時に必要なポートを追加します:
rdc context set-infra server-1 \
--tcp-ports 25,143,465,587,993 \
--udp-ports 53
rdc context push-infra server-1
これによりtcp-{port}とudp-{port}という名前のTraefikエントリポイントが作成されます。
ポートの追加または削除後は、プロキシ設定を更新するために常に
rdc context push-infraを再実行してください。
ステップ2:TCP/UDPラベルの追加
composeファイルでtraefik.tcp.*またはtraefik.udp.*ラベルを使用します:
services:
mail-server:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
network_mode: host
labels:
- "traefik.enable=true"
# SMTP (ポート 25)
- "traefik.tcp.routers.mail-smtp.entrypoints=tcp-25"
- "traefik.tcp.routers.mail-smtp.rule=HostSNI(`*`)"
- "traefik.tcp.routers.mail-smtp.service=mail-smtp"
- "traefik.tcp.services.mail-smtp.loadbalancer.server.port=25"
# IMAPS (ポート 993) — TLSパススルー
- "traefik.tcp.routers.mail-imaps.entrypoints=tcp-993"
- "traefik.tcp.routers.mail-imaps.rule=HostSNI(`mail.example.com`)"
- "traefik.tcp.routers.mail-imaps.tls.passthrough=true"
- "traefik.tcp.routers.mail-imaps.service=mail-imaps"
- "traefik.tcp.services.mail-imaps.loadbalancer.server.port=993"
主要な概念:
HostSNI(\*`)` は任意のホスト名にマッチ(プレーンSMTPなどSNIを送信しないプロトコル用)tls.passthrough=trueはTraefikが復号化せずに生のTLS接続を転送することを意味し、アプリケーション自体がTLSを処理- エントリポイント名は
tcp-{port}またはudp-{port}の規則に従う
事前設定済みポート
以下のTCP/UDPポートにはデフォルトでエントリポイントがあります(--tcp-portsで追加する必要なし):
| ポート | プロトコル | 一般的な用途 |
|---|---|---|
| 80 | HTTP | Web(HTTPSへ自動リダイレクト) |
| 443 | HTTPS | Web(TLS) |
| 3306 | TCP | MySQL/MariaDB |
| 5432 | TCP | PostgreSQL |
| 6379 | TCP | Redis |
| 27017 | TCP | MongoDB |
| 11211 | TCP | Memcached |
| 5672 | TCP | RabbitMQ |
| 9092 | TCP | Kafka |
| 53 | UDP | DNS |
| 10000-10010 | TCP | 動的範囲(自動割り当て) |
DNS設定
set-infraで設定したサーバーのパブリックIPアドレスにドメインを向けます:
個別サービスドメイン
各サービスにA(IPv4)およびAAAA(IPv6)レコードを作成します:
app.example.com A 203.0.113.50
app.example.com AAAA 2001:db8::1
gitlab.example.com A 203.0.113.50
mail.example.com A 203.0.113.50
自動ルート用ワイルドカード
自動ルート(ティア1)を使用する場合、ワイルドカードDNSレコードを作成します:
*.example.com A 203.0.113.50
*.example.com AAAA 2001:db8::1
これによりすべてのサブドメインがサーバーにルーティングされ、TraefikがHost()ルールまたは自動ルートホスト名に基づいて正しいサービスにマッチングします。
ミドルウェア
Traefikミドルウェアはリクエストとレスポンスを変更します。ラベル経由で適用します。
HSTS(HTTP Strict Transport Security)
labels:
- "traefik.http.middlewares.myapp-hsts.headers.stsSeconds=15768000"
- "traefik.http.middlewares.myapp-hsts.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.myapp-hsts.headers.stsPreload=true"
- "traefik.http.routers.myapp.middlewares=myapp-hsts"
大容量ファイルアップロードバッファリング
labels:
- "traefik.http.middlewares.myapp-buffering.buffering.maxRequestBodyBytes=536870912"
- "traefik.http.routers.myapp.middlewares=myapp-buffering"
複数のミドルウェア
カンマ区切りでミドルウェアをチェーンします:
labels:
- "traefik.http.routers.myapp.middlewares=myapp-hsts,myapp-buffering"
利用可能なミドルウェアの完全なリストについては、Traefikミドルウェアドキュメントを参照してください。
診断
サービスにアクセスできない場合、サーバーにSSHしてルートサーバーのエンドポイントを確認します:
ヘルスチェック
curl -s http://127.0.0.1:7111/health | python3 -m json.tool
全体的なステータス、検出されたルーターとサービスの数、自動ルートが有効かどうかを表示します。
検出されたルート
curl -s http://127.0.0.1:7111/routes.json | python3 -m json.tool
すべてのHTTP、TCP、UDPルーターとそのルール、エントリポイント、バックエンドサービスを一覧表示します。
ポート割り当て
curl -s http://127.0.0.1:7111/ports | python3 -m json.tool
動的に割り当てられたポートのTCPおよびUDPポートマッピングを表示します。
よくある問題
| 問題 | 原因 | 解決方法 |
|---|---|---|
| サービスがルートに表示されない | コンテナが実行されていない、またはラベルが不足 | リポジトリのデーモンでdocker psを確認、ラベルを確認 |
| 証明書が発行されない | DNSがサーバーを指していない、または無効なCloudflareトークン | DNS解決を確認、Cloudflare APIトークンの権限を確認 |
| 502 Bad Gateway | アプリケーションが宣言されたポートでリッスンしていない | アプリが{SERVICE}_IPにバインドし、ポートがloadbalancer.server.portと一致していることを確認 |
| TCPポートに到達できない | インフラストラクチャにポートが登録されていない | rdc context set-infra --tcp-ports ...とpush-infraを実行 |
完全な例
この例では、PostgreSQLデータベースを持つWebアプリケーションをデプロイします。アプリはapp.example.comでTLS付きで公開されます。データベースは内部専用です。
docker-compose.yml
services:
webapp:
image: myregistry/webapp:latest
network_mode: host
restart: unless-stopped
environment:
DATABASE_URL: postgresql://app:changeme@${POSTGRES_IP}:5432/webapp
LISTEN_ADDR: ${WEBAPP_IP}:3000
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure,websecure-v6"
- "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
# HSTS
- "traefik.http.middlewares.webapp-hsts.headers.stsSeconds=15768000"
- "traefik.http.middlewares.webapp-hsts.headers.stsIncludeSubdomains=true"
- "traefik.http.routers.webapp.middlewares=webapp-hsts"
postgres:
image: postgres:17
network_mode: host
restart: unless-stopped
environment:
POSTGRES_DB: webapp
POSTGRES_USER: app
POSTGRES_PASSWORD: changeme
command: -c listen_addresses=${POSTGRES_IP} -c port=5432
volumes:
- ./data/postgres:/var/lib/postgresql/data
# traefikラベルなし — 内部専用
Rediaccfile
#!/bin/bash
prep() {
mkdir -p data/postgres
renet compose -- pull
}
up() {
renet compose -- up -d
}
down() {
renet compose -- down
}
DNS
app.example.comをサーバーのパブリックIPに向けるAレコードを作成します:
app.example.com A 203.0.113.50
デプロイ
rdc repo up my-app -m server-1 --mount
数秒以内にルートサーバーがコンテナを検出し、Traefikがルートを取得してTLS証明書をリクエストし、https://app.example.comが公開されます。