Skip to content

設定 ​

設定はすべてリポジトリルートの kobune.toml に記述します。このファイルは リポジトリで管理し、すべての worktree が同じ内容を参照します。マシンごと、 クローンごとに設定を変えたい場合は、さらに 2 つのファイルがこの上に重なります。 残りの 2 つの層 で説明します。

キーの一覧は kobune.toml リファレンス にあります。 このページでは、各設定の背景にある考え方を説明します。

最小構成 ​

toml
[project]
name = "myapp"

[services.web]
image = "node:22"
port = 3000
command = "npm run dev"

プロジェクト名はすべての URL に含まれるため、1 つの daemon が管理する プロジェクト間で一意である必要があります。Kobune は、URL を衝突させるよりも 先に、同名のプロジェクトの登録を拒否します。

複数のサービス ​

toml
[services.web]
image = "node:22"
port = 3000
command = "npm run dev"
depends_on = ["api"]

[services.api]
image = "node:22"
port = 8080
command = "npm run api"
depends_on = ["db"]

[services.db]
image = "postgres:16"
port = 5432
scope = "project"
expose = false
volumes = ["pgdata:/var/lib/postgresql/data"]
env = { POSTGRES_PASSWORD = "postgres" }

depends_on は起動順序を決めます。各サービスは、依存先が起動するだけでなく ready になるのを待ってから起動します。待ち時間は 15 秒で打ち切って先へ進む ため、それより起動の遅い依存先については保証がなくなります。ready に意味を 持たせるのは、後述するヘルスチェックです。

scope: worktree ごとか、共有か ​

設定のなかで最も重要な選択です。

toml
scope = "workspace"   # 既定値。worktree ごとに 1 インスタンス
scope = "project"     # 全 worktree で 1 インスタンスを共有

worktree ごとにデータベースを立てると、それぞれに初期データの投入が必要になり、 リソースもその分消費します。共有すればすべてのブランチが同じデータを参照 します。開発中はこちらが適していることが多い一方、ブランチごとに異なる マイグレーションを持つ場合には問題になります。

Kobune はマイグレーションの競合を解決しません。共有データベースに対して 互換性のないマイグレーションを適用するブランチが複数あれば、衝突します。 そうした場合は scope = "workspace" を選び、初期データ投入のコストを 受け入れてください。

公開の制御 ​

toml
expose = false

expose = false を指定したサービスには、URL もルーティングも作成されません。 他のサービスからは内部的にアクセスできますが、環境の外側からは到達できません。 データベースやキャッシュには、ほぼ必ず指定します。

port が設定されている場合の既定値は true です。

ヘルスチェック ​

toml
health = "http://localhost:3000/healthz"
health = "tcp://localhost:5432"

サービスが「起動した」だけでなく「リクエストを受け付けられる」状態になったか を判定する方法です。指定がない場合の判定は TCP 接続の可否のみとなり、HTTP サービスでは応答可能になるより前に成立してしまいます。

2 点、注意があります。

  • http:// で使われるのはパスのみです。設定に記述するのはコンテナ内から 見たアドレスですが、Kobune が実際に接続するのはランタイムが割り当てた アドレスであるため、ホスト名とポート番号は無視されます。
  • cmd: はコンテナ内で実行されます。health = "cmd:pg_isready -U postgres" のように書きます。接続を受け付ける 状態と、クエリに応答できる状態を区別できるのはこの形式だけです。postgres は 初期化が完了するかなり前から listen を始めます。コマンドはシェルと同様に 分割されますが、シェル自体は介さないため、パイプを使う場合は sh -c で 包んでください。

scale-to-zero によって停止中のサービスが起動する際も、この判定の完了を待ち ます。適切なヘルスチェックを設定しておくと、最初のリクエストの応答が速く、 確実になります。

アイドルタイムアウト ​

toml
idle_timeout = "30m"

リクエストが来ない状態が続いたとき、自動停止するまでの時間です。既定値は 30 分です。起動に時間がかかるサービスには長めに、worktree を頻繁に作成する 場合は短めに設定してください。

計測の起点はプロキシを経由した最後のリクエストです。コンテナ間の通信は カウントされません。

URL を持たないサービス、たとえば expose = false を指定したデータベースには、 計測の対象となるリクエストがそもそもありません。この場合は、depends_on で そのサービスを指定している公開サービスの状態に従います。 すべての依存元がアイドルになった時点で停止し、いずれかがリクエストで起動 する際には、先に起動されます。

そのため depends_on には必ず指定してください。 どこからも指定されて いないサービスは、停止を判断する材料も復帰する経路も持たないため、daemon が 動いている間はずっと起動したままになります。

ボリューム ​

toml
volumes = [
  "pgdata:/var/lib/postgresql/data",                 # 名前付き。プロジェクトに 1 つ
  "node-modules@workspace:/workspace/node_modules",  # 名前付き。worktree ごとに 1 つ
  "./seed:/seed",                                    # ホストのパス。worktree からの相対パス
  "/etc/ssl/certs:/certs:ro",                        # 絶対パス、読み取り専用
]

スラッシュを含まない指定は、ランタイムが管理する領域を意味します。この領域は プロジェクト単位のため、worktree 間で共有されます。/、./、~/ で始まる 指定はホストのパスとして扱われます。

名前に @workspace を付けると、worktree ごとに別の領域になります。node_modules はこれを使う場面です。worktree 間で共有すると、あるブランチの lockfile で入れたものを別のブランチが上書きし続けます。worktree ごとに分けれ ば、インストールはブランチごとに 1 回ずつかかりますが、内容は正しくなります。

環境変数 ​

値が小さく秘匿する必要のないものは、ここに記述できます。

toml
[services.web]
env = { NODE_ENV = "development" }

それ以外、つまりマシンや worktree ごとに異なる値や、秘匿すべき値は、層構造を 持つ環境変数として管理してください。環境変数 を 参照してください。

ランタイムの選択 ​

toml
[runtime]
default = "docker"   # または "apple"

プロジェクト単位の設定のため、リポジトリごとに異なるバックエンドを使用できます。 切り替えによる違いは ランタイム を参照してください。クローンした マシンによって答えが変わる場合は マシンごとに使い分ける を参照してください。

URL の接尾辞 ​

toml
[project]
name = "myapp"
domain = "myapp.localhost"   # 既定値。name から導出される

domain を上書きすると、別のドメイン配下で配信できます。ただし指定した ドメインは 127.0.0.1 に解決される必要があり、.localhost 以外の場合は /etc/resolver の設定を追加してください。

独自イメージをビルドする ​

image を指定する代わりに、build にコンテキストを指定します。

toml
[services.web]
build = "."
port = 3000
command = "npm run dev"

コンテキストはその worktree から取得するため、Dockerfile を変更したブランチ には、その Dockerfile が示すイメージが渡ります。ビルドには docker build 自身が使うのと同じ BuildKit を使います。コマンドラインで通る Dockerfile は そのまま通り、キャッシュマウントも利用できます。ビルドコンテキストの ルートに置いた .dockerignore は適用され、そこに書いたものは送信されません。

それ以外はすべて送信され、その量は送信しながら表示されます。512 MB を超える と Kobune が知らせます。その大きさのコンテキストは、意図したものというより .dockerignore の書き漏らしであることがほとんどだからです。ビルド出力の ディレクトリ、キャッシュ、あるいはこの中に入れ子になった別の worktree などが それにあたります。

イメージには Dockerfile と build_args から算出した fingerprint がタグとして 付きます。そのため、内容が同一の worktree 同士は 1 つのイメージを共有し、 同じイメージが既にある場合はビルドをスキップします。停止中のサービスの起動が 速いままなのは、このスキップによるものです。

fingerprint は Dockerfile が COPY するファイルまでは見ないため、 package.json だけの変更では再ビルドされません。kobune up --build で 強制できます。

可能であれば既製イメージを使うほうが有利です。node:22 にソースを マウントするほうがビルドより起動が速く、環境が動くまでの手数も少なくて 済みます。build が必要になるのは、システムパッケージや、既製イメージに 含まれないツールチェーンが要る場合です。

残りの 2 つの層 ​

kobune.toml は 3 つのファイルの真ん中です。残る 2 つは、たいていの チェックアウトには存在しません。~/.kobune/config.toml は kobune.toml より 先に読まれ、プロジェクトではなくそのマシンについて言えることを書く場所です。 Apple Container を使う Mac に [runtime] default = "apple" と書いておけば、 どのプロジェクトもその存在を知らないままで済みます。kobune.toml の隣に置く kobune.local.toml は後から読まれ、クローン 1 つについて同じ役割を果たします。

テーブルは統合し、それ以外は置き換えます。そのためどちらの層でも、隣にある image を書き直さずに [services.web] の port だけを指定できます。統合した 結果は開けるファイルとしてはどこにも無いため、 kobune config show で確認します。

全体は 層 にあります。

Released under the Apache License 2.0.

nightly ビルドです。リリース版ではなく、まだ安定していません。 詳しく