🚀

Telepresenceをやめてmirrordに乗り換えた話

に公開

エスマットでは、コンテナ基盤としてAWS EKSを採用しています。開発者はマイクロサービスの開発・デバッグを行う際に開発用の共通クラスターにTelepresenceを使い開発中のサービスのみを入れ替えて動作検証をおこなっていました。

しかし、Telepresence v2.21以降、OSS版ではpersonal interceptorが削除されたため複数開発者が共通クラスターにTelepresenceで同時に接続することができなくなりました。そのため、代替方法を探す必要が発生しました。いくつかの候補を検討した結果、最終的にmirrordを採用することにしました。

この記事では、Telepresenceからmirrordに移行した経緯を解説します。また、mirrordを実際にどのような設定で運用しているかを紹介します。

Telepresenceとmirrordの比較

私たちのチームが直面していた課題は明確でした。Telepresence OSS版では複数開発者が同一クラスターで同時に開発できないという制限です。この課題を解決するには、以下の2つの選択肢がありました。

  1. Telepresence有償版(Blackbird)への移行
  2. mirrord有償版の採用

どちらも有償版が必要という条件は同じでしたが、最終的にmirrordを選択しました。

mirrordを選んだ3つの理由

  1. VPNを使わないことによる安定性と軽快さ

    • Telepresenceが採用するVPNベースの接続は、ネットワーク設定を書き換えるため他のVPNソフトと競合して動作が不安定になりやすかった
    • mirrordのシステムコール横取り方式はオーバーヘッドが少なく効率的
    • 実際の開発作業で、Telepresenceよりも安定していて、レスポンスも速いと体感
  2. 目的に特化したシンプルさ

    • Blackbirdはマイクロサービスの統合開発環境として設計されており、多機能
    • 私たちが必要としていた「開発中のサービスの部分的な置き換え」以外の機能も多く、調査時にノイズが多い
    • mirrordは必要な機能に特化しており、シンプルで分かりやすい
  3. 実際に動作した

    • Blackbirdは正式版がリリースされた直後で私たちの環境ではランタイムエラーが発生し、そもそも利用できない状態だった(2025年4月時点)
    • mirrordは実際にfrontend/BFFサービスで動作検証が完了できた

どうやって動くのか?

mirrordは、VPNを使わずにシステムコールを横取りする仕組みで動作します。ローカルプロセスがファイルを読もうとしたり、ネットワーク通信をしようとすると、その呼び出しをmirrordが捕まえて、Kubernetes上のPodに転送します。

mirrord-architecture
mirrord architecture

この仕組みにより、VPNもroot権限も不要で、まるでPod内で動いているかのようにローカルプロセスが振る舞います。

設定手順

mirrordのセットアップは、以下の2ステップになります。

  1. ローカルPCへのCLIのインストール
  2. Kubernetes クラスターへmirrod operatorをインストール

CLIのインストール

Mac OSを使っている場合、brewコマンドでインストールできます。

brew install metalbear-co/mirrord/mirrord

https://metalbear.co/mirrord/docs/overview/quick-start

mirrord operatorのインストール

公式のHelmからインストールする方法が簡単です。

helm repo add metalbear https://metalbear-co.github.io/charts
curl https://raw.githubusercontent.com/metalbear-co/charts/main/mirrord-operator/values.yaml --output values.yaml
helm install -f values.yaml mirrord-operator metalbear/mirrord-operator

https://metalbear.co/mirrord/docs/overview/quick-start#operator

動作確認

CLIとoperatorのインストールが完了したら、targetlessモードを使ってクラスタ内部のネットワークに接続できることを確認します。以下の例では、クラスター内部のAPIにcurlコマンドでアクセスを試みています。

$ mirrord exec curl -- -v http://my-service.default.svc.cluster.local:5000/healthcheck
New mirrord version available: 3.153.0. To update, run: `"curl -fsSL https://raw.githubusercontent.com/metalbear-co/mirrord/main/scripts/install.sh | bash"`.
To disable version checks, set env variable MIRRORD_CHECK_VERSION to 'false'.
* Running command: curl -v http://my-service.default.svc.cluster.local:5000/healthcheck
* mirrord will run without a target, no configuration file was loaded
* mirrord will run without the mirrord Operator
* env: all remote environment variables will be fetched
* fs: file operations will default to read from the remote
* incoming: incoming traffic will be be mirrored
* outgoing: forwarding is enabled on TCP and UDP
* dns: DNS will be resolved remotely
* internal proxy: logs will be written to /var/folders/v7/c267687s10sg2b95vj455kjc0000gp/T/mirrord-intproxy-1754140810-QSjAubE.log
⠚ mirrord exec
    ✓ update to 3.153.0 available
    ✓ ready to launch process
      ✓ layer extracted
      ✓ operator not found
      ✓ agent pod created
      ✓ pod is ready
      ✓ arm64 layer library extracted
    ✓ config summary                                                                                                                                                               * Host my-service.default.svc.cluster.local:5000 was resolved.
* IPv6: (none)
* IPv4: 10.100.55.190
*   Trying 10.100.55.190:5000...
* Connected to my-service.default.svc.cluster.local (10.100.55.190) port 5000
> GET /healthcheck HTTP/1.1
> Host: my-service.default.svc.cluster.local:5000
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Sat, 02 Aug 2025 13:20:26 GMT
< Content-Length: 2
<
* Connection #0 to host my-service.default.svc.cluster.local left intact
{}

このコマンドの実行で以下の確認ができます。

  • クラスタ内部のDNS解決が機能している(.cluster.localドメインが解決される)
  • Service経由でPodにアクセスできている
  • ローカルのcurlコマンドがクラスタ内部のネットワークで実行されている

例:複数開発者がフロントエンド開発をする場合

複数開発者がフロントエンド開発をする場合を例にmirrordの設定を説明します。この構成では、各開発者がBFFをmirrord経由で実行します。

BFFを起動するコマンドは以下の通りです。

mirrord exec -t deployment/bff -f ./mirrord.config.json npm run dev

この実行例では、クラスター上の deployment/bffnpm run dev で起動したプロセスによって置き換えられます。詳細な設定は mirrord.config.json に記載されています。

mirrordの詳細設定

mirrord.config.json の設定内容は以下の通りです。

{
  "feature": {
    "env": true,
    "network": {
      "dns": true,
      "outgoing": {
        "tcp": true,
        "udp": true
      },
      "incoming": {
        "mode": "steal",
        "http_filter": {
          "header_filter": "^X-Dev-User: {{ get_env(name=\"USER\", default=\"unknown\") }}$"
        }
      }
    }
  }
}

各設定の意味:

  • env: true: Pod の環境変数をローカルで使用
  • dns: true: クラスタ内の DNS 解決を有効化
  • mode: "steal": トラフィックを完全にローカルにリダイレクト
  • header_filter: 開発者ごとにトラフィックを分離

なぜheader_filterが必要なのか?

mode: "steal"を設定すると、BFFへのトラフィックがすべてローカルPCに転送されてしまいます。これでは複数の開発者が同時に作業できません。

そこでheader_filterを使います。この設定により、特定のHTTPヘッダー(X-Dev-User)を持つリクエストだけが自分のローカルPCに転送されるようになります。

例:

  • 開発者Aliceのリクエスト(X-Dev-User: alice)→ AliceのローカルPCへ
  • 開発者Bobのリクエスト(X-Dev-User: bob)→ BobのローカルPCへ
  • ヘッダーなしのリクエスト → クラスター内のBFFが処理

https://metalbear.co/mirrord/docs/using-mirrord/steal

フロントエンドでの設定

開発者を識別するヘッダを自動的に付与するようにします。

// 開発環境でのみ有効
if (process.env.NODE_ENV === 'development') {
  axios.defaults.headers.common['X-Dev-User'] = process.env.USER;
}

おわりに

Telepresenceからmirrordへの移行は、当初は「仕方なく」始めた作業でした。しかし、実際に使ってみると、mirrordの方が優れている点が多いことに気づきました。

移行後の成果

開発効率の向上

  • VPNの接続待ちやエラーに悩まされることがなくなった
  • レスポンスが速くなり、開発のリズムが良くなった

チーム開発の改善

  • 複数開発者が同時に作業しても競合しない
  • HTTPヘッダーによる明確なトラフィック分離

運用中の課題と今後の展望

現在、frontend/BFFだけでなくバックエンドサービスでもmirrordを活用しています。ただし、運用していく中で課題も見えてきました。

発生している課題

  • mirrord operatorがスタックして動作しなくなることがある
  • 現在はkubectl rollout restartで対応しているが、根本的な解決には至っていない
  • 今後のバージョンアップで安定性が向上することを期待

それでも、これらの課題を差し引いても、mirrordがもたらす開発効率の向上は大きく、現時点では最適な選択だと確信しています。Blackbirdが安定版になった際には再評価も検討する予定です。

もしTelepresence OSS版の制限で困っている方がいれば、ぜひmirrordを試してみてください。きっと期待以上の開発体験が得られるはずです。

参考リンク

GitHubで編集を提案
株式会社エスマット

Discussion