k8s(raspberry pi)のpodのログをチャットで観れるか実験してみました。
この後、エラーがログに出てないかも聞いてみました
最新の M4 Max搭載 Mac Studio を導入しました。この圧倒的なパワーをローカルLLMの実行だけに使うのはもったいない。そこで、長年運用している 自作のラズパイ・クラスター(3台構成) を、VS CodeのAIエージェント「Roo Code」から直接操作・管理できる環境を構築することにしました。
AIに「インフラの目と手」を与えるための架け橋として、GoogleやAnthropicが推進する Model Context Protocol (MCP) を活用します。
Client: Roo Code (VS Code Extension)
Protocol: Model Context Protocol (MCP)
Runtime: Node.js
Infrastructure: Kubernetes (Raspberry Pi Cluster), kubectl
[構成図]
AIとKubernetesを繋ぐ既成のMCPサーバーが見当たらなかったため、Node.jsで簡易ブリッジ k8s-bridge.js を自作しました。
ターミナルでは動くのに、Roo Code経由だと kubectl が見つからない問題が発生。VS Codeから起動されるMCPプロセスには、普段のシェル(.zshrc等)の PATH が引き継がれないのが原因でした。
対策: * kubectl をフルパス(/opt/homebrew/bin/kubectl)で指定。
mcp_settings.json の env セクションにも明示的に PATH を記述。
Roo Codeの設定画面でランプが「黄色(再試行中)」から変わらず、接続に苦労しました。
MCPは標準入出力を介した JSON-RPC 通信です。AIからの initialize リクエストに対し、仕様に沿ったレスポンスを即座に返さないと、AIは接続先が生きていると認識してくれません。
対策: 最小限の initialize 応答と tools/list 応答を実装。ついにランプが 「緑(Connected)」 へ変わり、AIがクラスターを認識しました。
当初は「ノード一覧を取得するだけ」のReadOnlyなツールでしたが、これではPodの生成ができません。そこで、引数を自由に渡せる汎用ツール run_kubectl へ刷新しました。
Node.jsの spawn を使い、stdout(標準出力)と stderr(標準エラー)の両方をバッファリングしてAIに返すロジックを実装しました。これにより、AIが「自分でYAMLを書き、自分でapplyし、エラーが出れば自分で修正する」という自律的なループが可能になりました。
実験指示: 「NginxのPodを作って」 結果: AIが run_kubectl を使って default namespaceに my-web Podを生成。
感動ポイント: get pods -A を実行した際、自分が長年運用してきた Argo CD や Cilium と並んで、AIが生成した my-web が Running になっている のを見た瞬間、インフラ運用の新しい時代を感じました。
M4 Maxのパワーがあれば、ローカルでAIを回しながら、物理インフラの運用(ログ解析、トラブルシュート、デプロイ)を対話形式で自動化できます。
インフラエンジニアにとってのMCPは、単なる便利ツールではありません。「自分の長年の経験とスキルを、AIという強力な相棒に移植するためのプラグ」 なのだと確信しました。
k8s-bridge.js標準モジュールのみで構成しているため、npm install 不要で動作します。
#!/usr/bin/env node
const { spawn } = require('child_process');
// ※各自の環境に合わせて kubectl の絶対パスを確認してください
const KUBECTL_PATH = '/opt/homebrew/bin/kubectl';
let buffer = '';
process.stdin.on('data', (chunk) => {
buffer += chunk.toString();
let lines = buffer.split('\n');
buffer = lines.pop();
for (let line of lines) {
if (!line.trim()) continue;
try {
handleMessage(JSON.parse(line));
} catch (e) {
console.error("JSON Parse Error:", e);
}
}
});
function handleMessage(message) {
const respond = (result) => {
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: message.id, result }) + '\n');
};
if (message.method === 'initialize') {
respond({
protocolVersion: "2024-11-05",
capabilities: { tools: {} },
serverInfo: { name: "k8s-universal-bridge", version: "1.1.1" }
});
} else if (message.method === 'tools/list') {
respond({
tools: [{
name: "run_kubectl",
description: "任意の kubectl コマンドを実行し結果を返します",
inputSchema: {
type: "object",
properties: {
args: { type: "array", items: { type: "string" } }
},
required: ["args"]
}
}]
});
} else if (message.method === 'tools/call' && message.params.name === 'run_kubectl') {
const k8s = spawn(KUBECTL_PATH, message.params.arguments.args);
let output = '';
k8s.stdout.on('data', (d) => { output += d.toString(); });
k8s.stderr.on('data', (d) => { output += d.toString(); });
k8s.on('close', (code) => {
respond({ content: [{ type: "text", text: output.trim() || `Code: ${code}` }] });
});
}
}
mcp_settings.json設定ファイルの場所: ~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json
{
"mcpServers": {
"kubernetes": {
"command": "node",
"args": ["/Users/hidenari/src/k8s-bridge.js"],
"env": {
"KUBECONFIG": "/Users/hidenari/.kube/config",
"PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
}
}
}
}
[用途]
ルール対象外のマニフェストをデプロイさせないための
防止策で利用するイメージになる
[検証]
以下のコマンドを投入する
kubectl label ns default pod-security.kubernetes.io/warn=baseline
[各種コマンドの意味]
1. kubectl label ns default
今更ながら感は、ありますがAIエージェントとローカルLLMで
MCPの設定を行ってみたいと思います。
1)ローカルLLMを使う上で、Ollamaと qwen2.5-coder:14bをいれました。
3)MCPを動かす上で、以下の導入を行います。
①nodeのインストール:
brew install node
②uvx / uvのインストール:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
③Vs-Codedの拡張でCLINEを入れます。
4)MCP serverの設定を行います。
Configure > Configure MCP Serversを選択
5)jsonファイルの記載を以下にします。
記載が終わったら、Doneを押す
以下の質問をしてみました。
「この URL を読んで、最新の Terraform の S3 命名規則を教えて:
結果:
同時に、ブラウザ上で、以下の内容も表示されることを確認
過去に作成済みのソースコードに対してファイル単位ではなく
広範囲で(上位のフォルダー)質問をしてみる
質問内容:
searchツールを使って、現在のワークスペースにある setup_raspberry.sh の内容を確認して。その上で、このスクリプトで設定しているOSの状態を前提とした、main.tf への追加リソース(例:監視用のPrometheusなど)を提案して。僕の過去の書き方を真似して、コレジャナイ感がないようにしてね。
AI側の調査:
AI側で調査するのに権限の付与が必要になるので
以下の確認表示がでるので、Allowにして、進める
AI側の回答:
1. ブート順序の変更 (EEPROM)
• `sudo raspi-config` を実行
• `Advanced Options` > `Boot Order` > `NVMe/USB Boot` を選択
• 再起動して設定を反映
2. SSD起動時の重要パス
• 設定ファイルの場所が従来と異なるので注意
• 正解: `/boot/firmware/cmdline.txt`
• ※`/boot/cmdline.txt` を書き換えても反映されない場合が多い
3. NVMe Gen3 の有効化 (Pi 5限定)
`/boot/firmware/config.txt` に以下を追記して高速化:
```
dtparam=pciex1_gen=3
```
4. 構築のヒント
• SSD起動にするとディスクI/Oが劇的に速くなり、K8sの動作が安定する
• 2026年現在の最新ファームウェアでは、`/boot/firmware/` 配下の管理がより厳格化されているため、パスの確認は必須。
Kubernetesクラスター構築!cgroupの罠と解決策
1. はじめに(今回の環境)
• ハードウェア: Raspberry Pi 5 (3台構成)
• ストレージ: SSD起動(NVMe/USB)
• OS: Raspberry Pi OS (Debian 13 Trixieベース)
• K8sバージョン: v1.31 (最新)
2. 直面した3つの大きな壁
1. SSD起動特有の「パス」問題
• 従来の /boot/cmdline.txt はもはや古い。
• 最新のSSD起動環境では /boot/firmware/cmdline.txt を書き換えないと、設定が一切反映されない。
2. cgroup v2 への完全移行
• 最新OSでは cgroup 管理が厳格化。
• cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 の追記が必須。
• これを忘れると、kubeadm は進めてもノードが永遠に NotReady になる。
3. 2026年リポジトリ署名期限問題
• Kubernetesのインストール用リポジトリの署名が変わっており、古い手順のままだと apt update でエラーが出る。
3. 解決の決め手となったスクリプトのポイント
• パスの自動判別: /boot/firmware/cmdline.txt があればそちらを優先して書き換える。
• 冪等性(べきとうせい)の確保: 同じ設定を二重に書き込まないスマートな追記。
• 最新の署名回避: [trusted=yes] を活用して、2026年のリポジトリ変更を突破。
4. 構築結果
• kubectl get nodes で、Master/Node1/Node2 すべてが Ready に!
• SSD起動の爆速環境で、ネットワーク(Flannel)も正常稼働。
5. まとめ(教訓)
• 「去年動いた手順」は、最新OS(Trixie)とSSD起動の前では通用しない。
• cg
k8s(raspberry pi)のpodのログをチャットで観れるか実験してみました。 この後、エラーがログに出てないかも聞いてみました