Skip to content

caretaker とクライアント側機能

Cornus には、リモートサーバーやクラスター上で動くワークロードを、開発者のすぐ隣で動いているかのように扱える機能がいくつかあります。たとえば、呼び出し元のマシンからバインドマウントするディレクトリ、呼び出し元のネットワークから送信するアウトバウンド通信、呼び出し元側で発行する資格情報です。Kubernetes では、これらを Pod ごとに正確に 1 つだけ注入するサイドカー、すなわち caretaker が実現します。ホストバックエンドでは、同等のホスト側またはコンパニオンコンテナの仕組みで実現します。

クライアントローカルバインドマウント

ステートレスなデプロイでは、マウントソースはデプロイホスト上のパスだと仮定します。しかし、呼び出し元が リモートサーバーへデプロイしつつ、呼び出し元のマシンにあるディレクトリをバインドマウントしたい場合、この前提は崩れます。Cornus はビルド転送経路を再利用してこれを解決します。長寿命の WebSocket deploy-attach セッションがデプロイを運び、呼び出し元は名前付きの各ローカルディレクトリを 9P で提供します。リモートビルドとまったく同じく、呼び出し元が 9P サーバーです。cornus deploy --server <url> --local-mount SRC:DST[:ro] で利用します。

サーバー側での実現方法はバックエンドによって異なります。

  • dockerhost - サーバーは各バッキングをデータディレクトリの下に kernel-9p でマウントし、バックエンドを呼び出す前にマウントソースをそのマウントポイントへ書き換えます。バックエンドはそれを通常のホストパスと同じようにバインドマウントします。
  • kubernetes - マウントはノードホスト上ではなく、常に Pod の内部で実現されるため、Pod はどこにでもスケジュールできます。バックエンドはマウントごとに、共有 emptyDirBidirectional 伝播付きでそれを kernel-9p マウントする特権ネイティブサイドカーのマウントエージェント、そして対象位置のアプリケーションコンテナ用 volumeMount を注入します。サイドカーの起動プローブは、マウントが有効になるまでアプリケーションコンテナを待機させます。

カーネル 9P マウントのルートはディレクトリでなければなりません。単一ファイルの場合、dockerhost は親ディレクトリをエクスポートし、ベース名をサブパスとしてバインドします。Kubernetes の共有サイドカーマウントは任意の rootfs の対象位置へ単一ファイルだけを投影できないため、単一ファイルのソースを拒否します。ディレクトリマウントは引き続き利用できます。containerd バックエンドは現在、クライアントローカルのデプロイマウントをサポートしていません。

マウントは呼び出し元から提供されるため、デプロイメントの寿命は呼び出し元が接続し続けている時間と正確に一致します。セッションが切断されると、ハンドラーはまずコンテナを削除し、それから 9P のバッキングをアンマウントします。これは意図的に、この機能を永続的な本番ワークロードではなく開発用の内側の反復作業に限定しています。読み書き可能なマウントでは、書き込み可能で閉じ込められたエクスポートを使うため、コンテナからの書き込みは呼び出し元のローカルディレクトリへ反映されます。

Pod は NAT の内側にいる呼び出し元へ直接到達できないため、サーバーが接続を仲介します。サーバーは各 attach セッションを ID で登録し、Pod の caretaker は Pod ごとの接続を 1 本張って、マウントごとに 1 ストリームを開きます。サーバーはそれを呼び出し元への新しいストリームに中継します。

1 つのサイドカー、複数の役割

caretaker は、適用時に Kubernetes バックエンドが組み立てた単一の役割設定を読み、Pod に必要なすべての役割を 1 プロセスで実行します。そのため、ワークロードが複数の Cornus サイドカーを持つことはありません。

役割サーバーと通信するか役割
mountyes各 9P マウントをサーバー経由で呼び出し元へ中継します。
credentialyesクライアントが発行した資格情報を、サーバー中継経由で必要時に取得します。
proxynoアプリケーションコンテナのエグレスを傍受し、Compose ネットワークポリシーに従ってピアサービスへ転送します。
egressyesアプリケーションのアウトバウンドトラフィックをクライアント側の観測地点経由で経路します (後述)。
dnsno127.0.0.1:53 で app コンテナに対して提供し、未知の名前は upstream へ転送します。
hubyeshosted サービスを登録し、hub 経由で peer に到達します。
dockeryes (クライアント API)pod loopback 上で Docker エンジン API プロキシを実行し、DOCKER_HOST で知らせます (後述)。
otelnoPod の loopback でアプリケーションの OTLP を受信し、設定済みバックエンドへエクスポートする組み込み OpenTelemetry Collector を実行します (オブザーバビリティを参照)。

サーバーに接続する役割は 1 本の接続を共有します。 mountcredentialegresshub はすべて、Pod 単位で常時接続されるサーバーへの 1 本の接続に乗り、ストリームとして多重化されます。セッション ID は各ストリームの中を流れ、推測不能なケイパビリティとして残ります。proxydns 役割はアプリケーションコンテナとクラスターの間で完結するデータプレーンの役割であり、サーバーには触れません。

Docker エンドポイント

docker 役割はワークロードに Cornus 管理スタックへのループバックアクセス を与えます。caretaker は、cornus daemon docker を支えるものと同じ Docker エンジン API プロキシを Pod のループバックエンドポイント上で実行し、バックエンドはアプリケーションコンテナに DOCKER_HOST を注入します。すると Pod 内の標準 docker / docker compose は、Pod 自身のスタックを管理しているそのサーバーをそのまま操作できます。兄弟ワークロードのデプロイ、Compose の実行、exec などを、Pod 内に本物の Docker デーモンなしで行えます。これは DeploySpec.Docker による明示的な有効化です (Kubernetes のみ)。

他の server-bound 役割は scoped caretaker 資格情報で認証しますが、Docker プロキシは完全な クライアント デプロイ API を操作します。この API は設計上、caretaker の scoped トークンを拒否します。そのため、この役割は運用者が用意する専用シークレット (CORNUS_CLIENT_TOKEN_SECRET) から取得した、独自の client-scoped bearer トークンを持ちます。これは実質的にワークロードへ deploy-engine access を与えるため、この役割はそのトークンが設定されている場合にのみ有効化されます。また enforcing プロキシ役割と同じ pod では使えません (エンドポイント自身の接続が redirect されてしまうためです)。

クライアント側エグレス

ワークロードの outbound トラフィックは通常、ランタイムが存在する場所から出ていきます。これは air-gapped クラスター (開発者のマシンだけが internet に到達できる) や、VPN / corporate-proxy / SASE ネットワーク (認可されたエグレスパスがクライアント側にある) では問題になります。クライアント側エグレスは、リモートコンテナの outbound トラフィックをクライアント側の vantage point 経由で経路します。透明性が低い順に env (呼び出し元のプロキシ変数を伝搬)、proxy (caretaker が loopback 上で本物の HTTP + SOCKS5 プロキシを実行)、transparent (app のすべての TCP を nftables redirect で捕捉) の 3 モードがあります。モード、経路、PAC の使い方は エグレス を参照してください。アーキテクチャ上で重要なのは中継の形と保証です。

  • Reverse 中継。 caretaker は各接続の宛先をルーティングポリシーと照合します。relayed 経路では pod scoped サーバー接続上にストリームを開き、サーバーはそれを クライアント の deploy-attach セッションへ bridge します。クライアントは、自分で解決したプロキシ (corporate HTTP/SOCKS プロキシや SASE gateway、NO_PROXY を尊重) 経由で宛先に接続します。byte は物理的に、クライアント自身の通信と同じようにクライアントから出ていきます。
  • ポリシーは hop ごとに再評価されます。 サーバーは defense in depth としてポリシーを再チェックします (侵害された pod が自分でルーティングを昇格できないようにするため)。クライアントも最後の guard として再チェックします。宛先の既定は cluster 経路なので、エグレスを有効にしてもクラスター内トラフィックが黙って逸らされることはありません。PAC スクリプトは deadline 付きの sandboxed JS エンジンで評価され、失敗時は deny に fail-closed します。
  • 2 つの終端。 client 経路には稼働中セッションが必要です (開発ループ)。gateway 経路ではクライアントは不要です。サーバー自身がエグレスノードになるため、--detach ワークロードは誰も接続していなくてもエグレスを継続します。これは運用者 opt-in の CORNUS_EGRESS_GATEWAY と任意のポリシー ceiling で gate されるため、pod の要求が運用者の許可範囲を超えることはありません。

ホストバックエンドでは、proxy / transparent モードはワークロードのネットワーク名前空間を共有する companion caretaker コンテナとして動きます。

関連ページ

Released under the Apache-2.0 License.