Elido
4分で読了エンジニアリング
コア記事

k3s上でElidoをセルフホストする - 完全なプレイブック

k3sクラスター上でElidoの完全なスタックをデプロイするためのステップバイステップガイド:Helmブートストラップ、14のサービス、StatefulSetsとしてのデータプレーン、Caddyオンデマンドとは、バックアップ、およびアップグレード戦略。

Marius Voß
DevRel · edge infra
Architecture diagram of Elido on k3s: edge-redirect and api-core Deployments in front, StatefulSets for Postgres, Redis, ClickHouse, Redpanda, MinIO, and Meilisearch behind, Caddy Ingress handling on-demand TLS at the top

Elidoのマネージドバージョンは、プライバシーをデフォルトとした設定でEUリージョンのインフラ上で動作しています。ほとんどのユーザーにとって、それで十分です。しかし、そうでない場合もあります。

短縮リンクの転送先データとクリックイベントが特定のデータセンターから外に出ないことをセキュリティチームが要求している場合、監査ポリシーがデータベースサーバーの完全な制御を求めている場合、あるいはElidoをエアギャップで動作させる必要がある内部プラットフォームに組み込んでいる場合、セルフホストの方法がまさにそのために存在しています。

このガイドでは、k3s - 単一のVMまたは小規模なHAクラスター上で快適に動作する本番グレードの最小限のKubernetesディストリビューション - 上にElidoをデプロイする手順を説明します。完了時には、すべてのサービスが動作し、TLSがプロビジョニングされ、バックアップが設定され、繰り返し可能なアップグレードパスが用意されます。このガイドは、動作するシステムが欲しいのであってKubernetesの概念のチュートリアルではないことを前提としています。説明は簡潔に保ち、運用ステップは明確にします。

なぜセルフホストするのか#

プレイブックに入る前に、トレードオフについて正確に述べておく価値があります。セルフホストは自動的に優れているわけではありません。運用上のリスクをベンダーから自分のチームに移します。

データレジデンシーとコンプライアンス。 コンプライアンスフレームワーク(ISO 27001のスコープ、内部のデータ分類ポリシー、または契約上のデータレジデンシー条項)がリンクメタデータと分析イベントを直接管理するインフラ上に保持することを要求している場合、物理的にどこで動作していても、マネージドSaaSはその要件を満たすことができません。自分が所有するEUリージョンのVM上のセルフホストデプロイメントは満たすことができます。Elidoのアーキテクチャが一般的なフレームワークにどのようにマッピングされるかの詳細についてはコンプライアンス概要を参照してください。

スケール時のコスト予測可能性。 マネージドプランはアクティブなリンク数とクリック量で価格が設定されます。特定の閾値を超えると - 通常は月間数百万クリック以上のどこかで - マネージドプランのイベントあたりのコストが同等のStatefulSetワークロードを自分で運用するインフラコストを超えます。クロスオーバーポイントはトラフィックの形状によって異なりますが、存在します。

監査制御。 一部の組織では、証拠のパッケージング、リーガルホールド、またはSIEM統合のために生のPostgresテーブルとClickHouseクリックイベントデータへのアクセスが必要です。Elido APIは監査ログエンドポイントと証拠エクスポートを公開していますが、直接のデータベースアクセスはセルフホストデプロイメントでのみ利用可能です。

トレードオフ。 k3sはアップグレード、ノードの健全性、バックアップの検証、インシデント対応を所有する誰かを必要とします。チームにKubernetesの運用経験がない場合、コンプライアントなホスティング場所でのマネージドバージョンがほぼ確実に正しい答えです。セルフホストが誤った選択である場合のより直接的な説明については、この記事の最後のセクションを参照してください。

前提条件#

  • k3sクラスター。4 vCPUと8 GBのRAMを持つ単一ノードが軽いワークロードを処理できます。HAの場合、3つのコントロールプレーンノードと2つ以上のワーカーノードが最小推奨トポロジーです。k3sの内蔵etcdがコントロールプレーンのHAをカバーし、データプレーンのHAはHelmチャート内のPatroni(Postgres)が処理します。
  • クラスターを指すコンテキストで設定された kubectl
  • Helm 3.14以降。
  • DNSレコードを作成する機能を持つ管理下のドメイン。Let's Encrypt ACMEチャレンジを成功させるためには、k3sのイングレスIPがインターネットからポート80および443でアクセス可能である必要があります。
  • コンプライアンス上の理由がある場合は、EUリージョンのVM。Hetzner(Falkenstein、Helsinki、Nuremberg)とOVH(Gravelines、Roubaix)は、Elido自身のエッジインフラが使用する2つのプロバイダーです。

Ubuntu 24.04を実行する新鮮なHetzner CX32(4 vCPU / 8 GB)では、k3sのインストールは約30秒で完了します:

curl -sfL https://get.k3s.io | sh -
# Copy the kubeconfig to your local machine:
scp root@<your-vm>:/etc/rancher/k3s/k3s.yaml ~/.kube/elido-self-host.yaml
export KUBECONFIG=~/.kube/elido-self-host.yaml
kubectl get nodes  # should show Ready

HelmチャートはElidoリポジトリに含まれています(チャートはリポジトリの deploy/helm/elido/ にあります - 別のパブリックHelmリポジトリはありません):

git clone https://github.com/elidoapp/elido.git
cd elido

クイックスタート#

セルフホストプリセット(deploy/helm/elido/values-selfhost.yaml)は、単一ノードのk3sデプロイメントの推奨出発点です。最初にシークレットをブートストラップし、次にインストールします:

# 1. Mint all required Kubernetes Secrets in one shot (idempotent)
./scripts/bootstrap-secrets.sh elido

# 2. Install using the self-host preset
helm -n elido upgrade --install elido ./deploy/helm/elido \
  -f ./deploy/helm/elido/values-selfhost.yaml \
  --set ingress.hosts.redirect[0]=r.example.com \
  --set ingress.hosts.api=api.example.com \
  --set ingress.hosts.dashboard=app.example.com \
  --set image.tag=$(git rev-parse --short HEAD) \
  --create-namespace \
  --wait --timeout 10m

カスタムオーバーライド(本番のレプリカ数、管理された外部サービスなど)には、values-selfhost.yaml をローカルの my-values.yaml にコピーし、編集して -f で渡します。主なトップレベルのvaluesセクションは ingress.hosts.*(ホスト名)、image.registry/image.tag、およびサービスごとの resources ブロックです。global.domain は使用しないでください - チャートはドメイン設定に ingress.hosts.* を使用します。

--wait フラグはすべてのDeploymentとStatefulSetが準備完了状態になるまでブロックします。キャッシュされたイメージのない新鮮なノードでは、1 Gbpsのリンクで5〜8分かかります。

すべてが起動したことを確認します:

kubectl -n elido get pods
kubectl -n elido get svc

helm show values ./deploy/helm/elido でチャートのvaluesリファレンスを参照して、完全なパラメータを確認できます。リポジトリの deploy/helm/elido/README.md が特定のフィールド名とブートストラップスクリプトの使用法の権威あるソースです。

Elido の Helm デプロイフロー:bootstrap-secrets が Kubernetes Secrets を作成し、helm upgrade install がセルフホスト用の values でチャートをレンダリングし、マニフェストが k3s API サーバーに適用され、クラスターが 14 の Deployment と 6 の StatefulSet を調整しながら各ポッドが起動時に migrate up を実行し、helm wait がすべてのポッドが Ready になるまでブロックする

デプロイするアーキテクチャ#

Elidoのアーキテクチャはレイテンシーバジェットで分割されています。その分割を理解することで、情報に基づいたリソース割り当ての決定ができます。

Elido の k3s クラスタートポロジー:上部に Caddy イングレス、その下に edge-redirect ホットパス Deployment とウォームパス API Deployment、横に コールドパスのワーカー Deployment、最下部に StatefulSet データプレーン(Postgres、Redis、ClickHouse、Redpanda、MinIO、Meilisearch)

ホットパス:edge-redirect#

edge-redirect はリダイレクトリクエストの同期パス上の唯一のサービスです。Go + fasthttpで書かれており、厳しいレイテンシーバジェットがあります:キャッシュヒット時のp50は5ms、p95は15msです。サービスは2層キャッシュを維持します:Redis Cluster(L2)でバックアップされたインプロセスLRU(L1)。キャッシュミスの場合は、api-core へのgRPC呼び出しに落ちます。クリックイベントはRedpandaにファイア・アンド・フォーゲットで送出されます - リダイレクトレスポンスはイベント書き込みの完了を待ちません。

HelmチャートはHorizontalPodAutoscalerを持つDeploymentとして edge-redirect をデプロイします。単一リージョンのセルフホストセットアップでは、2つのレプリカが合理的な出発点です。L2 Redisキャッシュはレプリカ間で共有されるため、ローリングアップデート後のキャッシュウォームアップは高速です。

ウォームパス:APIサーフェス#

5つのサービスが同期APIとビジネスロジックの作業を処理します:

  • api-core - Go + chi、RESTおよびgRPC。リンク、ワークスペース、メンバーシップ、カスタムドメイン、監査イベントの信頼できる情報源。
  • api-bff - WebダッシュボードとモバイルクライアントのためのNode/Hono BFFレイヤー。api-coreanalytics-api を集約します。
  • analytics-api - Go、ClickHouseクエリ。分析ダッシュボードを提供します。
  • billing - Go + chi + sqlc。EU VAT エンジン、LiqPay決済統合、請求書生成。
  • search - Go、リンク検索クエリをMeilisearchにプロキシします。

認証はOry Kratos(アイデンティティ、セッション、メール認証)とOry Hydra(サードパーティ統合とブラウザ拡張機能のためのOAuth2/OIDCトークン)が処理します。どちらもチャートでDeploymentとしてデプロイされます。

コールドパス:非同期ワーカー#

6つのサービスがRedpandaトピックからイベントを消費し、レスポンスタイムのバジェットを持ちません:

  • click-ingester - クリックイベントを消費し、ClickHouseに書き込みます。
  • webhook-dispatcher - 署名されたWebhookペイロードを顧客エンドポイントにファンアウトします。
  • notification - メールとアプリ内通知(アカウントイベント、リンクアラート)。
  • url-scanner - Google Safe Browsing、PhishTank、SURBLに対して転送先URLのスキャンを実行します。
  • metadata-fetcher - リンクプレビューのためのOpen Graphメタデータを取得します。
  • domain-manager - DNS検証とカスタムドメインのCaddyオンデマンドTLSプロビジョニング。

データプレーン:StatefulSets#

6つのステートフルシステムが上記のサービスをバックアップします:

システム役割チャートリソース
Postgres (Patroni)リンク、ユーザー、課金の信頼できる情報源StatefulSet、HAモードで3レプリカ
Redis ClusterホットパスリンクキャッシュStatefulSet
ClickHouseクリックイベントの保存と分析クエリStatefulSet
Redpandaサービス間のイベントバスStatefulSet
MinIOユーザーアップロードアセット(QRイメージ、エクスポート)StatefulSet
Meilisearchアプリ内リンク検索StatefulSet

単一ノードデプロイメントでは、各StatefulSetは1つのレプリカで動作します。HAモード(valuesで ha.enabled: true を設定することで有効)では、PostgresはPatroniの下で3つのレプリカにスケールし、Redisは6つ(3つのプライマリ、3つのレプリカ)にスケールし、Redpandaは3つのブローカーにスケールします。

セルフホスト Elido のデータプレーン配線:edge-redirect が L2 Redis キャッシュを読み取り、api-core が Postgres を信頼できる情報源として使用して Redpanda にイベントを送出し、click-ingester が Redpanda を消費して ClickHouse に書き込み、analytics-api が ClickHouse をクエリし、search が Meilisearch をクエリし、api-core がアセットを MinIO に保存する

Caddyイングレス#

Caddyはテナントのカスタムドメインに対してTLS終端とオンデマンドTLSを処理します。ワークスペースオペレーターがダッシュボード(またはAPI)を通じてカスタムドメインを追加すると、domain-manager がDNSの所有権を確認し、ホスト名を許可済みとして登録し、そのホスト名への最初のHTTPリクエスト時にCaddyがLet's Encryptの証明書をプロビジョニングします。チャートはCaddyを elido.app/ingress=true というラベルが付いたノードにDaemonSetとして、またはデフォルトの単一ノードセットアップではDeploymentとしてデプロイします。

テナントのカスタムドメイン go.company.com のフロー:

  1. オペレーターがCNAMEを作成します:go.company.com → <your-k3s-ingress-ip>(または直接を指すAレコード)。
  2. オペレーターが POST /v1/workspaces/{id}/domains を呼び出すか、ダッシュボードで「ドメインを追加」をクリックします。
  3. domain-manager がDNSをクエリして、CNAMEがイングレスIPに解決することを確認します。
  4. Caddyが最初のHTTPSリクエストを受信し、Elido発行の許可リストを確認し、ACME HTTP-01経由でLet's Encryptから証明書を要求します。
  5. 証明書はCaddyの状態ボリュームに保存され、自動的に更新されます。

初回実行のブートストラップ#

helm install が完了すると、管理者APIは利用可能ですが、ユーザーアカウントは存在しません。

管理者ユーザーのブートストラップ#

# Port-forward to the api-core admin interface (not exposed by default)
kubectl -n elido port-forward svc/api-core 8081:8081 &

# Create the first admin account
curl -X POST http://localhost:8081/internal/admin/bootstrap \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "password": "your-secure-password"
  }'

ブートストラップエンドポイントはクラスターネットワーク内からのみ呼び出し可能で、最初の成功した呼び出しの後に無効化されます。管理者アカウントが作成されたら、設定したドメインのダッシュボードからログインします。

最初のワークスペースの作成#

ログイン後、ダッシュボードは初回使用時にワークスペースの作成を促します。または、APIを使用して:

curl -X POST https://links.example.com/v1/workspaces \
  -H "Authorization: Bearer <your-session-token>" \
  -H 'Content-Type: application/json' \
  -d '{"name": "My Workspace", "slug": "my-workspace"}'

カスタムドメインの追加#

ワークスペース設定から、Domainsに移動してショートリンクドメインを追加します。「確認」をクリックする前にDNSレコード(CNAMEまたはA)を設定してください - domain-manager はDNSをすぐに確認し、レコードがまだ伝播していない場合はエラーを返します。検証に合格すると、そのドメインへの最初のリダイレクトリクエスト時にCaddyが証明書をプロビジョニングします。証明書の発行は通常、最初のリクエストから10〜30秒かかります。

TLSが動作していることを確認します:

curl -I https://go.company.com/healthz
# Expect: HTTP/2 200

運用上の考慮事項#

バックアップ#

Postgres。 チャートには設定可能なスケジュール(デフォルト:毎日02:00 UTC)で pg_dump を実行し、圧縮されたダンプをvaluesで設定されたMinIOバケットにアップロードする CronJob が付属しています。HAデプロイメントでは、プライマリへの影響を避けるためにレプリカに対して pg_dump を実行します。valuesで有効化します:

backups:
  postgres:
    enabled: true
    schedule: "0 2 * * *"
    retentionDays: 30
    s3Bucket: "elido-backups"

ポイントインタイムリカバリのために、WALアーカイブ(valuesの postgres.walArchive.enabled: true)を有効にします。これはWALセグメントをMinIOに継続的に送信します。日次の pg_dump とWALアーカイブを組み合わせることで、RPOを5分以内にできます。

ClickHouse。 ClickHouseはクリックイベントを保存します。これらは追記専用であり、リテンションが許す限りRedpandaから再生できます。チャートにはClickHouseのネイティブバックアップインターフェースを使用してMinIOに BACKUP TABLE SQLを実行する CronJob が含まれています。backups.clickhouse.enabled: true で有効化します。

Redpanda。 Redpandaはデータベースではなくストリーミングバスです。リテンションは時間ベース(デフォルト:7日間)でvaluesの redpanda.retention で設定されます。click-ingesterがリテンションウィンドウを超えて遅延した場合、イベントは失われます。コンシューマーグループのラグを監視してください - チャートにはコンシューマーグループが100Kメッセージ以上遅延している場合に発火するPrometheusアラート(ElidoRedpandaConsumerLag)が付属しています。

バックアップの検証。 一度もテストされたことのないバックアップは信頼できないバックアップです。少なくとも四半期に一度、別のネームスペースへのリストアドリルを実行してください:

kubectl -n elido-restore create ns elido-restore || true
helm install elido-restore ./deploy/helm/elido \
  --namespace elido-restore \
  --values ./my-values.yaml \
  --set restore.fromBackup=true \
  --set restore.backupDate="2026-05-01"

モニタリング#

チャートには、Prometheus Operator CRDがクラスターに存在する場合、各サービスの ServiceMonitor が含まれています。アラートを設定すべき主要なメトリクス:

monitoring:
  prometheus:
    enabled: true # requires prometheus-operator in cluster
  grafana:
    enabled: true # deploys bundled dashboards
    adminPassword: "change-me"

バンドルされたGrafanaダッシュボードは以下をカバーします:

  • edge-redirect のp50/p95レイテンシー、キャッシュヒット率、クリックボリューム
  • api-core のリクエストレート、エラーレート、gRPCレイテンシー
  • click-ingester のRedpandaパーティションごとのコンシューマーラグ
  • Postgresのプライマリ/レプリカのレプリケーションラグ(Patroni)
  • Redisのエビクションレートとメモリプレッシャー

クラスターにすでにPrometheusスタックがある場合は、monitoring.prometheus.install: false を設定して、既存のスタックをServiceMonitorに向けてください。

PostgresのPatroni HA#

HAモードでは、Patroniがリーダー選出とフェイルオーバーを管理します。チャートはKubernetesの分散設定ストア(Kubernetes ConfigMapsを使用、別のetcdは不要)でPatroniを設定します。フェイルオーバーは通常15〜30秒で完了します。フェイルオーバー中、api-corebilling は短い書き込みエラーを経験します。どちらのサービスも指数バックオフで 5xx 時にリトライします。

Patroniクラスターの状態を確認するには:

kubectl -n elido exec -it postgres-0 -- patronictl -c /etc/patroni/config.yml list

アップグレードフロー#

Elidoはセマンティックバージョニングに従います。パッチリリースにはバグフィックスが含まれ、手動の移行ステップは不要です。マイナーおよびメジャーリリースにはデータベーススキーマの移行が含まれる場合があり、サービスバイナリに埋め込まれ、移行ランナーによってポッドの起動時に自動的に実行されます。

推奨されるアップグレードパス:

# 1. Pull the latest chart (git pull in your cloned repo)
git pull origin main

# 2. Review the upgrade notes
helm show chart ./deploy/helm/elido | grep -A10 'version\|appVersion'

# 3. Diff the values changes (requires helm-diff plugin)
helm diff upgrade elido ./deploy/helm/elido \
  --namespace elido \
  --values ./my-values.yaml

# 4. Upgrade
helm upgrade elido ./deploy/helm/elido \
  --namespace elido \
  --values ./my-values.yaml \
  --wait --timeout 10m

移行の処理。 各Goサービスバイナリには、スキーママイグレーション(埋め込み移行ディレクトリに対して golang-migrate を使用)が含まれています。ポッドの起動時に、バイナリはリクエストを処理する前に migrate up を実行します。ローリングアップデートでは、新しいポッドが古いポッドが終了する前に保留中の移行を適用します。移行は前のマイナーバージョンと後方互換性がある必要があります - v1.5で追加された新しい列は、ロールアウトウィンドウ中に一緒に動作するv1.4バイナリがエラーを起こさないようにNullableであるかデフォルト値を持つ必要があります。

メジャーアップグレードのブルー/グリーン。 スキーマ変更が後方互換性のないメジャーバージョンアップグレードの場合は、ブルー/グリーン戦略を使用します。ステージングネームスペースで別のHelmリリース名の下に新しいバージョンをインストールし、本番データベースのスナップショットを移行し、スモークテストを行い、その後イングレスレベルでDNSカットオーバーを実行します。グリーンスタックを検証した後、ブルーリリースを削除します。

# Install green stack
helm install elido-green ./deploy/helm/elido \
  --namespace elido-green \
  --create-namespace \
  --values ./green-values.yaml

# After validation, cut over DNS at your registrar
# Then decommission blue
helm uninstall elido --namespace elido

セルフホストしない方がよい場合#

セルフホストは限られた状況で正しい選択です。予想より多くのケースで、誤った選択です。

ワークロードが小さい。 月間100K未満のリンクを作成し、厳しいデータレジデンシー要件がない場合、マネージドElidoはk3sを運用するよりもコストと運用時間の両面で安くなります。ホストされたティアには、バックアップ、アップグレード、そして自分が所有することになるインフラのオンコールが含まれています。

Kubernetesの運用経験がない。 k3sは最小限ですが、Kubernetesは単純ではありません。チームの誰もStatefulSetsを運用したことがなく、etcdのバックアップ/リストアを処理したことがなく、午前2時にPatroniのCrashLoopBackOffをデバッグしたことがない場合、セルフホストはインフラコストの節約では相殺できない運用リスクのカテゴリを追加します。

コンプライアンス要件がEUデータレジデンシーであって特定のテナンシーではない。 EUデータレジデンシーとは、EUで保存・処理されるデータを意味します。ElidoのマネージドインフラはHetzner FRAとOVH GRAで動作しており、どちらもGDPR第44条要件を越境転送なしで満たしています。コンプライアンスチームの実際の要件が「EUのデータ」である場合、マネージドプロダクトはセルフホストデプロイメントなしで既にそれを満たしています - 各プランで利用可能なコンプライアンス機能についてはpricing ページを参照してください。

マルチリージョンのエッジパフォーマンスが欲しい。 マネージドサービスはFrankfurt、Ashburn、Singaporeにエッジポップを運用しており、ホットパスの edge-redirect が各地点にデプロイされています。単一リージョンのセルフホストk3sクラスターのリダイレクトレイテンシーは、VMのエンドユーザーからの地理的距離によって制限されます。マルチリージョンのセルフホストは可能ですが、運用面が大幅に増加します - このガイドがカバーする内容とは異なる取り組みです。


Helmチャートのvalues、特定のトラフィックボリュームに対するStatefulSetのリソース要件、または特定のバージョンのアップグレードパスに関する質問は、セルフホストエディションのGitHub Discussionsボードに投稿してください。コンプライアンス関連の質問 - 特にセルフホスト設定がEUレジデンシーを超えて提供するもの - については、コンプライアンスページで監査ログ、証拠エクスポート、RBACコントロールの詳細をカバーしています。

ブログの関連記事#

Elidoを試す

URLを貼り付けて短縮リンクを取得

登録不要。リンクは30日間有効。永久に保存するには登録してください。

Free、登録不要 · 1日あたり2件

Elidoを試す

EUホスティングのURL短縮サービス。カスタムドメイン、詳細な分析、オープンAPI付き。無料プラン - クレジットカード不要。

タグ
self hosted url shortener
k3s
kubernetes url shortener
helm
self host elido
url shortener kubernetes
data residency
eu compliance

続きを読む