kubectl execをAPIゲートウェイ代わりに使う — エンタープライズKubernetesでの実践パターン
はじめに
エンタープライズ環境のKubernetesクラスタでは、外部からのAPI公開が制限されていることがあります。Kafka、Elasticsearch、内部REST APIなどに外部からアクセスできない場合、kubectl execでPod内に入ってcurlやkafka-console-producerを実行するというパターンが有効です。
「ハック的」に聞こえるかもしれませんが、実際にはセキュリティ上の利点もあります。本記事では、このパターンをTypeScriptのBuilderクラスで保守しやすくした方法を紹介します。
前提・環境
- Kubernetes(kubectl execが使える環境)
- Node.js + TypeScript
- SSH経由でリモートサーバーに接続し、そこからkubectl execを実行
なぜkubectl execを使うのか
エンタープライズKubernetesでは以下のような制約があります。
- 内部APIにIngress/LoadBalancerが設定されていない
- Kafkaブローカーがクラスタ内ネットワークのみでアクセス可能
- Elasticsearchが外部公開されていない
- VPNを使ってもService IPに直接到達できない
この場合、クラスタ内のPodからcurlやkafka-console-producerを実行するのが最も確実なアクセス方法です。

Kafkaへのイベント送信
Kafkaブローカーはクラスタ内部からのみアクセス可能です。Pod内でkafka-console-producerを実行してイベントを送信します。
class Kafka {
private podName?: string;
public async runEvent(config: EventConfig): Promise<void> {
await this.checkPodname();
const events = this.getEvents(config);
for (const event of events) {
const eventString = JSON.stringify(event).replace(/"/g, '\\"');
const cmd = [
`kubectl exec`,
`${this.podName}`,
`-- sh -c "unset KAFKA_JMX_OPTS`, // JMX競合を回避
`&&`,
`echo '${eventString}'`,
`|`,
`kafka-console-producer.sh`,
`--topic YOUR_TOPIC_NAME`,
`--broker-list kafka-broker-0:9092"`,
].join(" ");
await Remote.execRemote(cmd);
}
}
unset KAFKA_JMX_OPTSはPod内でJMXポートの競合を避けるための回避策です。Pod内にすでにKafkaブローカーが動いている場合、同じJMX設定でプロデューサーを起動しようとすると競合します。
MySQLへのクエリ
内部データベースへのクエリもkubectl exec経由です。
class MySQL {
public async checkUser(userName: string): Promise<void> {
const podName = (await Pod.getPodMySQL())[0] ?? "";
const query = `USE mydb; SELECT id FROM records WHERE userName='${userName}';`;
const cmd = [
`kubectl exec -i`, // -itではなく-i(非対話モード)
`${podName}`,
`-n ${this.namespace()}`,
`-- mysqlsh`,
`--user='${credentials.MYSQL_USERNAME}'`,
`--password='${credentials.MYSQL_PASSWORD}'`,
`-h ${podName}`,
`-P ${ports.MYSQL_PORT}`,
`--sql -e "${query}"`,
].join(" ");
const result = await Remote.execRemote(cmd);
// テキスト出力をパースしてテーブル表示
const resultArray = result.split("\n").filter(Boolean);
const key = resultArray[0] || "id";
const values = resultArray.slice(1);
console.table(values.map((value) => ({ [key]: value })));
}
}
注意点:
kubectl exec -it(対話モード)ではなく-iを使用。自動化ではtty割り当て不要で、-itだとエラーになる場合があるmysqlshのテキスト出力をパースしているが、--result-format=jsonを使う方が堅牢
このパターンのトレードオフ
利点:
- 外部公開なしでクラスタ内のあらゆるサービスにアクセスできる
- 追加のIngressやポートフォワーディング設定が不要
- RBAC(kubectl exec権限)で制御できる
欠点:
- コマンド結果のパースが脆い(テキスト出力に依存)
- シェルエスケープが複雑でバグの温床になりやすい
- Pod名が動的に変わるため、事前にPod名の取得が必要
まとめ
kubectl execをAPIゲートウェイ代わりに使うパターンを紹介しました。
- CommandBuilderでコマンド組み立てとエスケープを一元管理
- Kafka、MySQLなどクラスタ内サービスへのアクセスに活用
- 入力のサニタイズとコマンドインジェクション対策が必須
「正式な方法」ではないかもしれませんが、エンタープライズKubernetesの現実的な制約の中では有効なアプローチです。








