ネットワーキング
このページでは、隔離されたDockerデーモン内で実行されているサービスをインターネットからアクセス可能にする方法を説明します。リバースプロキシシステム、ルーティング用Dockerラベル、TLS証明書、DNS、TCP/UDPポートフォワーディングについて説明します。
| Route server running old version | Binary was updated but service not restarted | Happens automatically on provisioning; manual: sudo systemctl restart rediacc-router |
| STUN/TURN relay not reachable | Relay addresses cached at startup | Recreate the service after DNS or IP changes so it picks up the new network config |
サービスがループバック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で起動すると、自動的にルーティング可能になります。手動のプロキシ設定は不要です。
The route server binary is kept in sync with your CLI version. When the CLI updates the renet binary on a machine, the route server is automatically restarted (~1–2 seconds). This causes no downtime, Traefik continues serving traffic with its last known configuration during the restart and picks up the new config on the next poll. Existing client connections are not affected. Your application containers are not touched.
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.repo_name | Repository name | marketing |
rediacc.tcp_ports | TCP ports the service listens on | 8080,8443 |
rediacc.udp_ports | UDP ports the service listens on | 53 |
コンテナがrediacc.*ラベルのみを持つ場合(traefik.enable=trueなし)、ルートサーバーはリポジトリ名とマシンのサブドメインを使用して自動ルートを生成します:
{service}.{repoName}.{machineName}.{baseDomain}
例えば、マシンserver-1上のmarketingというリポジトリ内でベースドメインexample.comのmyappというサービスは以下を取得します:
myapp.marketing.server-1.example.com
各リポジトリは独自のサブドメインレベルを持つため、フォークや異なるリポジトリが衝突することはありません。リポジトリをフォークする場合(例:marketing-staging)、フォークは自動的に異なるルートを取得します。カスタムドメインを使用するサービスには、ティア2ラベルまたはrediacc.domainラベルを使用してください。
rediacc.domainによるカスタムドメイン
docker-compose.ymlのrediacc.domainラベルを使用して、サービスにカスタムドメインを設定できます。短縮名と完全なドメインの両方がサポートされています:
labels:
# 短縮名, マシンのbaseDomainを使用してcloud.example.comに解決
- "rediacc.domain=cloud"
# 完全なドメイン, そのまま使用
- "rediacc.domain=cloud.example.com"
ドットを含まない値は短縮名として扱われ、マシンのbaseDomainが自動的に追加されます。ドットを含む値は完全なドメインとして使用されます。
machineNameが設定されている場合、カスタムドメインサービスは2つのルートを取得します:ベースドメイン上のルート(cloud.example.com)とマシンサブドメイン上のルート(cloud.server-1.example.com)。
ティア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サービスの公開
前提条件
-
マシンにインフラストラクチャが設定されていること(マシンセットアップ, インフラストラクチャ設定):
# 共有資格情報(configごとに一度、すべてのマシンに適用) rdc config infra set -m server-1 \ --cert-email admin@example.com \ --cf-dns-token your-cloudflare-api-token # マシン固有の設定 rdc config infra set -m server-1 \ --public-ipv4 203.0.113.50 \ --base-domain example.com rdc config infra push -m server-1 -
ドメインのDNSレコードがサーバーのパブリックIPを指していること(下記のDNS設定を参照)。
ラベルの追加
公開したいサービスのdocker-compose.ymlにtraefik.*ラベルを追加します:
services:
myapp:
image: myapp:latest
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
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経由で自動的に取得されます。資格情報はconfigごとに一度設定します(すべてのマシンで共有):
rdc config infra set -m server-1 \
--cert-email admin@example.com \
--cf-dns-token your-cloudflare-api-token
自動ルートはサービスごとの証明書の代わりにリポジトリサブドメインレベルのワイルドカード証明書(*.marketing.server-1.example.com)を使用します。これによりLet’s Encryptのレート制限を回避し、起動を高速化します。カスタムドメインルートはマシンレベルのワイルドカード(*.server-1.example.com)を使用します。
traefik.http.routers.{name}.tls.certresolver=letsencryptを持つティア2ルートでは、ルートのホスト名に基づいてワイルドカードドメインSANが自動的に注入されます。
Cloudflare DNS APIトークンには、保護したいドメインに対するZone:DNS:Edit権限が必要です。
TCP/UDPポートフォワーディング
非HTTPプロトコル(メールサーバー、DNS、外部公開するデータベース)には、TCP/UDPポートフォワーディングを使用します。
ステップ1:ポートの登録
インフラストラクチャ設定時に必要なポートを追加します:
rdc config infra set -m server-1 \
--tcp-ports 25,143,465,587,993 \
--udp-ports 53
rdc config infra push -m server-1
これによりtcp-{port}とudp-{port}という名前のTraefikエントリポイントが作成されます。
Plain TCP Example (Database)
To expose a database externally without TLS passthrough (Traefik forwards raw TCP):
services:
postgres:
image: postgres:17
command: -c listen_addresses=${POSTGRES_IP} -c port=5432
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.mydb.entrypoints=tcp-5432"
- "traefik.tcp.routers.mydb.rule=HostSNI(`*`)"
- "traefik.tcp.services.mydb.loadbalancer.server.port=5432"
Port 5432 is pre-configured (see below), so no --tcp-ports setup is needed.
Security note: Exposing a database to the internet is a risk. Use this only when remote clients need direct access. For most setups, keep the database internal and connect through your application.
ポートの追加または削除後は、プロキシ設定を更新するために常に
rdc config infra pushを再実行してください。
ステップ2:TCP/UDPラベルの追加
composeファイルでtraefik.tcp.*またはtraefik.udp.*ラベルを使用します:
services:
mail-server:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
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で追加する必要なし)。エントリポイントは設定されたアドレスファミリーに対してのみ生成されます, IPv4エントリポイントには--public-ipv4が、IPv6エントリポイントには--public-ipv6が必要です:
| ポート | プロトコル | 一般的な用途 |
|---|---|---|
| 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設定
自動DNS(Cloudflare)
--cf-dns-tokenが設定されている場合、rdc config infra pushはCloudflareに必要なDNSレコードを自動的に作成します:
| レコード | タイプ | 内容 | 作成元 |
|---|---|---|---|
server-1.example.com | A / AAAA | マシンのパブリックIP | push-infra |
*.server-1.example.com | A / AAAA | マシンのパブリックIP | push-infra |
*.marketing.server-1.example.com | A / AAAA | マシンのパブリックIP | repo up |
マシンレベルのレコードはpush-infraによって作成され、カスタムドメインルート(rediacc.domain)をカバーします。リポジトリごとのワイルドカードレコードはrepo upによって自動的に作成され、そのリポジトリの自動ルートをカバーします。
これは冪等です, IPが変更された場合は既存のレコードが更新され、既に正しい場合はそのまま維持されます。
ベースドメインのワイルドカード(*.example.com)は、rediacc.domain=erpのようなカスタムドメインラベルを使用する場合、手動で作成する必要があります。
手動DNS
Cloudflareを使用しない場合やDNSを手動で管理する場合は、A(IPv4)および/またはAAAA(IPv6)レコードを作成します:
# マシンサブドメイン(rediacc.domain=erpのようなカスタムドメインルート用)
server-1.example.com A 203.0.113.50
*.server-1.example.com A 203.0.113.50
*.server-1.example.com AAAA 2001:db8::1
# リポジトリごとのワイルドカード(myapp.marketing.server-1.example.comのような自動ルート用)
*.marketing.server-1.example.com A 203.0.113.50
*.marketing.server-1.example.com AAAA 2001:db8::1
# ベースドメインワイルドカード(rediacc.domain=erpのようなカスタムドメインサービス用)
*.example.com A 203.0.113.50
Cloudflare DNSが設定されている場合、リポジトリごとのワイルドカードレコードはrepo upによって自動的に作成されます。複数のマシンがある場合、各マシンはそれぞれのIPを指す独自のDNSレコードを取得します。
ミドルウェア
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 config infra set --tcp-ports ...とpush-infraを実行 |
完全な例
この例では、PostgreSQLデータベースを持つWebアプリケーションをデプロイします。アプリはapp.example.comでTLS付きで公開されます。データベースは内部専用です。
docker-compose.yml
services:
webapp:
image: myregistry/webapp:latest
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
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
up() {
mkdir -p data/postgres
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 --name my-app -m server-1 --mount
数秒以内にルートサーバーがコンテナを検出し、Traefikがルートを取得してTLS証明書をリクエストし、https://app.example.comが公開されます。