mirrordを使いローカルプロセスをOrbStack k8s環境で実行
今回はmirrordというツールが興味深かったので個人のPCでサクッと試せる環境を作ります。具体的にはローカルでOrbStack k8s環境を作りmirrordを適用します。
mirrordとは?
mirrordはクラウド環境でローカルのプロセスを実行できるようにするツールです。
mirrordのユースケースは?
ローカル環境にあるプログラムの変更を即座にクラウド環境へ適用できます。例えばローカルの変更をmirrodを使ってステージング環境に適用することでCI/CDの待ち時間なしに動作確認をすることができます。
似たようなツールとの違いは?
クラウド環境でコードを実行できるツールは他にもあります。他のツールはVPNやシステムファイルを編集することでクラウド環境での実行を行いますがmirrordはプロセスレベルでローカル/リモートの切り替えができます。なので細かい設定が可能になります。
mirrordの仕組み
-
https://metalbear.co/blog/mirrord-internals-hooking-libc-functions-in-rust-and-fixing-bugs/
- process単位でlibcをhookします。記事中ではdetour(迂回路)という用語で説明しておりこれはhookと同等の意味です
-
https://metalbear.co/blog/carcinisation-of-mirrord-or-why-we-use-rust/
- mirrordはRustを使っています。なぜRustを選択したのかを書いています
mirrordの公式情報
ローカルにk8s環境を用意する
minikubeを使おうとしましたがorbstackでk8s環境を作成できるみたいなのでorbstackを使います。
OrbStackとは?
コンテナ、Linux環境管理ツールです。Docker Desktopより高速です。
kubectlのインストール
brew install kubectl
- install方法はいくつかあるのでドキュメントを参考にしてください
clusterを有効化
- GUIメニューから「Turn On」
- settingからチェックボックスにチェックを入れてもよいです
cluster起動の確認
╰─$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:26443
CoreDNS is running at https://127.0.0.1:26443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Node.jsアプリケーションを作る
基本ファイルの作成
package.json
{
"name": "nodejs-k8s-demo",
"version": "1.0.0",
"description": "Simple NodeJS app for Kubernetes demo",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {}
}
service.js
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from OrbStack Kubernetes!\n');
});
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY server.js .
EXPOSE 8080
CMD ["node", "server.js"]
- nodejs versionは22にした。他のバージョンにしても動くはずです。
docker imageのビルド
docker build -t nodejs-k8s-demo:v1 .
k8sファイルの設定
development.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs-app
spec:
replicas: 2
selector:
matchLabels:
app: nodejs-app
template:
metadata:
labels:
app: nodejs-app
spec:
containers:
- name: nodejs-app
image: nodejs-k8s-demo:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
- 一旦replicaを2に設定
service.yaml
apiVersion: v1
kind: Service
metadata:
name: nodejs-app-service
spec:
selector:
app: nodejs-app
ports:
- port: 80
targetPort: 8080
type: NodePort
Kubernetesリソースのデプロイ
OrbStackのKubernetesクラスタにリソースをデプロイします。
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Podが正常に起動しているか確認。
╰─$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nodejs-app-5dd85958c6-dkhcd 1/1 Running 0 44s
nodejs-app-5dd85958c6-kxqr9 1/1 Running 0 44s
Serviceが作成されたか確認。
╰─$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 192.168.194.129 <none> 443/TCP 78m
nodejs-app-service NodePort 192.168.194.247 <none> 80:32597/TCP 42s
アプリケーションへのアクセス
NodePortのポート番号を確認してアクセス:
╰─$ kubectl get service nodejs-app-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nodejs-app-service NodePort 192.168.194.247 <none> 80:32597/TCP 88s
にアクセスすると下記が表示
Hello from OrbStack Kubernetes!
service.jsを更新する手順(mirrordなし)
service.jsを更新
レスポンスの文字列の末尾に「changed」を追加。
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from OrbStack Kubernetes! changed\n');
});
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Dockerイメージの再ビルド
docker build -t nodejs-k8s-demo:v1 .
Deploymentの更新
╰─$ kubectl rollout restart deployment nodejs-app
deployment.apps/nodejs-app restarted
変更の確認
╰─$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nodejs-app-5dd85958c6-dkhcd 1/1 Terminating 0 18m
nodejs-app-5dd85958c6-kxqr9 1/1 Terminating 0 18m
nodejs-app-7ff5cc5f8-gkxg4 1/1 Running 0 26s
nodejs-app-7ff5cc5f8-j27k5 1/1 Running 0 24s
にアクセスすると下記が表示
Hello from OrbStack Kubernetes! changed
mirrordの環境構築
mirrordのinstall
brew install metalbear-co/mirrord/mirrord
xcodeのエラーが出た
brew install中に下記のエラーが出た。
Error: Xcode alone is not sufficient on Sonoma.
Install the Command Line Tools:
xcode-select --install
↓下記のコマンドを実行して解決。
xcode-select --install
deployment更新
わかりやすくするためにレプリカを1つにする
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs-app
spec:
replicas: 1
selector:
matchLabels:
app: nodejs-app
template:
metadata:
labels:
app: nodejs-app
spec:
containers:
- name: nodejs-app
image: nodejs-k8s-demo:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
変更したファイルを適用
kubectl apply -f deployment.yaml
service.jsを更新する手順(mirrordを使用)
レスポンスの文字列の末尾に「from local」を追加。
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from OrbStack Kubernetes! from local\n');
});
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
npm packageが存在する場合はnpm installしておきましょう。
npm install
mirrordのconfiguration
mirrord.jsonに設定を記述。一旦remoteに到達する全てのtrafficをローカルプロセスにリダイレクトさせるためにstealに設定。
{
"feature": {
"network": {
"incoming": "steal"
}
}
}
mirrord実行
mirrordを使ってローカルコードを実行。
mirrord exec --target pod/nodejs-app-7ff5cc5f8-j27k5 -f mirrord.json node server.js
反映を確認
╰─$ curl http://localhost:32597/
Hello from OrbStack Kubernetes! from local
k8s serviceのurlであるが、ローカルのservice.jsの変更が反映されました。
dockerのイメージ再ビルドをすることなくローカルの変更が反映されました。
おわりに
今回はtrafficのstealしか設定しませんでしたがドキュメントには様々な設定方法が書かれています。細かい設定を試してみたい方はドキュメントもぜひ参考にしてみてください。
Discussion