3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

欲しかったのコレかも!Limaで作るアプリ開発者向けローカルKubernetes環境

Last updated at Posted at 2025-12-12

この投稿では、Lima と k3s を使って、ホットリロードに対応したローカル Kubernetes 開発環境を構築する方法を解説します。port-forward なしでホストマシンから直接アクセスでき、コード変更が即座に反映される快適な開発体験を実現します。

ローカルのTypeScriptファイルを編集したら、Kubernetes上のBunサーバーにホットリロードで反映される様子を動画にしたのでご覧ください↓。BunがPodの中で動いているとは思えないような、快適な開発体験になってます。

この投稿で学べること

  • Lima と k3s を使った Kubernetes 環境の構築手順
  • ホストマシンのディレクトリを VM にマウントする方法
  • LoadBalancer 経由でホストから直接アクセスする設定
  • ホットリロードを有効にした開発ワークフローの構築

Lima と k3s とは

Lima(Linux virtual machines)は、macOS 上で Linux VM を手軽に動かすためのツールです。特に、ファイルシステムの共有やネットワーク設定が柔軟に行える点が特徴です。

k3s は、Rancher 社が開発した軽量な Kubernetes ディストリビューションです。リソース消費が少なく、ローカル開発環境に適しています。Lima には k3s のテンプレートが用意されており、コマンド一発で Kubernetes 環境を立ち上げることができます。

環境構築の手順

Lima のインストールと k3s の起動

まず、Homebrew で Lima をインストールします。

brew install lima

次に、k3s テンプレートを使ってインスタンスを起動します。

limactl start template://k3s

プロンプトが表示されたら「Proceed with the current configuration」を選択します。インスタンス名は k3s になります。

kubeconfig の設定

ホストマシンから kubectl を使えるようにするため、kubeconfig を設定します。

export KUBECONFIG="/Users/suin/.lima/k3s/copied-from-guest/kubeconfig.yaml"

設定が正しく反映されているか確認します。

kubectl get nodes -o wide

ノード情報が表示されれば成功です。

ホストディレクトリのマウント設定

ここが今回の構成で最も重要なポイントです。k3s テンプレートはデフォルトで mounts: [] となっており、ホストディレクトリのマウントが無効になっています。ホットリロードを実現するには、書き込み可能なマウントを追加する必要があります。

まず、k3s インスタンスを停止して設定を編集します。

limactl stop k3s
limactl edit k3s

以下の設定を追加します。

# macOS 13+ なら virtiofs が使える(vmType: vz のとき)
mountType: "virtiofs"
# watch/hot を効かせたいので inotify 伝搬をON(writable必須)
mountInotify: true
mounts:
  - location: "~/codes/github.com"   # macOS側
    writable: true
# Apple公式の Virtualization.framework を使う方式
vmType: vz
# ホスト(mac)とVM(k3s)間のネットワークを NAT で繋ぐ
networks:
  - vzNAT: true

各設定項目について補足します。mountType: "virtiofs" は、macOS 13 以降で利用可能な高速なファイル共有方式です。mountInotify: true は、ホスト側のファイル変更イベントを VM に伝搬するための設定です。vmType: vz は Apple の Virtualization.framework を使用する設定で、vzNAT: true はホストと VM 間のネットワークを NAT で接続します。

mountInotify の制限について

Lima の mountInotify: true は experimental な機能であり、いくつかの制限があります。 実装上、特定のイベントタイプ(ATTRIB)のみしか発生せず、実際のファイル内容変更を表す MODIFY / CLOSE_WRITE / DELETE が来ないケースがあります。

この制限により、Bun / Vite / nodemon 等の hot-reload / watch 機能が期待通りに動作しないことがあります。そのため、watch を使う場合は polling ベースの方法を推奨します。この投稿では、nodemon の --legacy-watch オプションを使用してこの問題を回避しています。

設定を保存したら、k3s を再起動します。

limactl start k3s

マウントが正しく設定されているか確認します。

limactl shell k3s -- ls ~/codes/github.com/

アプリケーションの作成

サンプルとして、Bun を使ったシンプルな HTTP サーバーを作成します。

bun init

index.ts を以下の内容で作成します。

// ~/codes/github.com/suinplayground/lima-k3s/index.ts
import { serve } from "bun";

serve({
  port: 4003,
  fetch(request) {
    return new Response("Sup");
  },
});

console.log("Server is running on port 4003");

Kubernetes マニフェストの作成

dev.yaml を作成します。このマニフェストには、Namespace、Deployment、Service の定義が含まれています。

apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels: { app: myapp }
  template:
    metadata:
      labels: { app: myapp }
    spec:
      containers:
        - name: app
          image: oven/bun:latest
          workingDir: /app
          command: ["bash", "-lc"]
          args:
            - |
              bun install
              bunx nodemon --legacy-watch --watch /app --ext ts,tsx,js,jsx,json --exec "bun index.ts"
          ports:
            - containerPort: 4003
          volumeMounts:
            - name: src
              mountPath: /app
            # Linux用の node_modules を Pod 内で作る(macのnode_modulesは混ぜない)
            - name: node-modules
              mountPath: /app/node_modules
      volumes:
        - name: src
          hostPath:
            path: /Users/suin/codes/github.com/suinplayground/lima-k3s
            type: Directory
        - name: node-modules
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: dev
spec:
  selector: { app: myapp }
  type: LoadBalancer
  ports:
    - name: http
      port: 4003
      targetPort: 4003

いくつかのポイントを解説します。

nodemon に --legacy-watch オプションを指定しているのは、前述の inotify の制限を回避するためです。このオプションを使うと、ファイルシステムイベントではなく polling ベースでファイル変更を検知します。

node_modulesemptyDir としてマウントしているのは、macOS 側の node_modules と Linux 側の node_modules を分離するためです。ネイティブモジュールの互換性問題を避けることができます。

Service の type: LoadBalancer を指定することで、k3s に組み込まれている ServiceLB(旧 Klipper)が外部 IP を割り当ててくれます。

デプロイと動作確認

マニフェストを適用します。

kubectl apply -f dev.yaml

Pod が起動しているか確認します。

kubectl get pods -n dev

まず、port-forward で動作確認を行います。

kubectl -n dev port-forward svc/myapp 4003:4003

別のターミナルで以下を実行します。

curl http://localhost:4003

"Sup" が表示されれば成功です。

LoadBalancer 経由でのアクセス

port-forward を使わずに、LoadBalancer の外部 IP 経由でアクセスすることもできます。

kubectl get svc myapp -o wide -n dev
NAME    TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)          AGE   SELECTOR
myapp   LoadBalancer   10.43.197.89   192.168.64.3   4003:30948/TCP   69m   app=myapp

EXTERNAL-IP の値(この例では 192.168.64.3)を使ってアクセスします。

curl http://192.168.64.3:4003

"Sup" が表示されれば成功です。これで、port-forward なしでホストマシンから直接アクセスできるようになりました。

EXTERNAL-IPでアクセスしてもいいですが、k3sのロードバランサーがNodePortを開いてくれるのと、limaがホストマシンの4003ポートをVMに自動ポートフォーワードしてくれるおかげで、localhostでもアクセスできます。

curl http://localhost:4003

ホットリロードの確認

最後に、ホットリロードが機能しているか確認します。

index.ts を以下のように修正して保存します。

// ~/codes/github.com/suinplayground/lima-k3s/index.ts
import { serve } from "bun";

serve({
  port: 4003,
  fetch(request) {
    return new Response("Hello"); // ここを修正
  },
});

console.log("Server is running on port 4003");

保存後、数秒待ってからリクエストを送ります。

curl http://localhost:4003

"Hello" が表示されれば、ホットリロードが正しく機能しています。

所感

Lima と k3s の組み合わせは、ローカルでの Kubernetes 開発環境として非常に優秀です。特に、LoadBalancer が標準で使えること、ホストディレクトリのマウントが柔軟に設定できることが大きな利点です。

inotify の制限は少し残念ですが、nodemon の --legacy-watch を使えば十分実用的なホットリロード環境が構築できます。Kubernetes ベースのアプリケーション開発を行う方は、ぜひ試してみてください。

最後までお読みくださりありがとうございました。Twitterでは、Qiitaに書かない技術ネタなどもツイートしているので、よかったらフォローしてもらえると嬉しいです:relieved:Twitter@suin

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?