コンテンツにスキップ
公式サイト →

まとめて読む

はじめに


ドキュメントガイド

このドキュメントは、Keelson を使ってアプリをデプロイ・運用するための情報をまとめたものです。

Keelson のサービス概要、料金、セキュリティについては 公式サイト を参照してください。

Keelson の対応ランタイムや制約は Keelson Deploy Spec に1ページでまとまっています。以下の URL を AI エージェントに渡すことで、自分が作ったアプリが Keelson にデプロイできるかを確認してもらうことができます。

https://keelson.dev/ja/docs/reference/deploy-spec.txt

クイックスタート

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

このガイドでは、サンプルのWebアプリケーションをKeelsonにデプロイし、ブラウザでアクセスできることと、ログイン保護がデフォルトで有効になること を確認します。

このガイドを始める前に、次のものを用意してください。

  • Node.js と npm — ターミナルで node -vnpm -v を実行し、バージョンが表示されればOKです。インストールが必要な場合は Node.js公式サイト から推奨版(LTS)をダウンロードしてください。
  • Keelson のアカウント — まだの方は keelson.dev からサインアップしてください。
  • Claude Code や Codex など、Agent Skill を利用できるAIエージェント

インストール後、以下のコマンドで確認してください。

Terminal window
keelson --version

あなたのマシンをKeelsonのアカウントと紐付けます。以下のコマンドを実行してください。

Terminal window
keelson auth login

ブラウザが開き、ログイン画面が表示されます。ログインが完了すると、ターミナルに戻って操作を続けられます。

Keelsonでは、デプロイやデプロイ状態の確認(ログの確認)をAIエージェントに任せることができます。AIエージェントがKeelsonを操作するための Skill を、以下のコマンドでインストールしてください。

Terminal window
npx skills add https://github.com/keelsonhq/agent-skills --skill xxxxxx

デプロイのテスト用に、シンプルなPython (FastAPI) アプリを用意しました。このサンプルアプリには、認証やセキュリティに関するコードは一切含まれていません。

  1. sample-web (GitHub) からZIPファイルをダウンロードし、デスクトップなどに展開します。
  2. 展開したフォルダを、普段お使いのAIエージェント(Claude Codeなど)で開きます。

6. AIエージェントにデプロイを指示する

Section titled “6. AIエージェントにデプロイを指示する”

ここがKeelsonの醍醐味です。複雑なコマンドを打つ必要はありません。AIエージェントのチャット欄に、一言こう指示してください。

指示の例: 「Skillを使って、このアプリをKeelsonにデプロイして」

AIエージェントが keelson.yaml を読み取り、自動的にビルドとデプロイを開始します。デプロイには通常1〜2分かかります。その間、AIがサーバーの構築やセキュリティ設定をすべて代行しています。成功すると、AIが以下のような公開URLを教えてくれます。

https://your-app-name.keelson.run/

デプロイされたURLをブラウザで開いてみましょう。

  • ログイン済みブラウザ: アプリが表示されます。
  • シークレットウィンドウ: URLを開くと、Keelsonのログイン画面が表示されます。

これが Security by Default です。アプリのコードに認証処理を書かなくても、Keelson がデフォルトでログイン保護を適用します。

Keelson 認証画面(アテ画像)

基本コンセプト

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson は、社内やチームで共有するアプリを安全に公開するための実行基盤です。

ユーザーはアプリそのものの開発に集中し、公開・認証・共有に必要な仕組みは Keelson が引き受けます。このページでは、その考え方を説明します。

リクエストはどのようにアプリへ届くのか

Section titled “リクエストはどのようにアプリへ届くのか”

Keelson にデプロイされたアプリには、ユーザーのブラウザから直接アクセスが届くわけではありません。すべてのリクエストは、まず Keelson Proxy を通ります。

プロキシ構成図(アテ画像)

ユーザーが Keelson にデプロイされたアプリの URL を開くと、リクエストは次の順序で処理されます。

  1. 公開URLから、どのアプリへのアクセスかを特定する
  2. Keelson Proxy がログイン状態を確認する
  3. アプリへのアクセス権限を確認する
  4. 許可された場合のみ、リクエストをアプリへ転送する
  5. アプリのレスポンスをユーザーに返す

重要なのは、認証とアクセス制御の判断がアプリ本体の外側で行われることです。そのため、アプリ開発者は認証画面やセッション管理を毎回自前で実装しなくても、共有前提のアプリを安全に公開できます。

Keelson では、認証とアクセス制御の責務をアプリ本体の外側に分離しています。アプリは業務ロジックに集中しつつ、共有時のセキュリティはプラットフォーム側で一貫して扱えます。

なぜ認証をアプリに書かなくてよいのか

Section titled “なぜ認証をアプリに書かなくてよいのか”

Keelson では、アプリをデプロイした瞬間からログイン保護が有効になります。これを Security by Default と呼んでいます。

  • セキュリティは後付けではなく、最初から組み込まれている
  • 「動いた後に認証を足す」のではなく、「公開した時点で安全」
  • Quickstart で体験した、シークレットウィンドウでのログイン画面がこの仕組みの結果

Keelson が単なるホスティングではなく、社内アプリのための実行基盤である理由がここにあります。

Keelson はアプリの入口でログイン保護とアクセス制御を提供します。アプリ内部の業務ルールに基づく制御が必要な場合は、アプリ側で追加の実装を行います。

責任分界: アプリが担うこと / Keelson が担うこと

Section titled “責任分界: アプリが担うこと / Keelson が担うこと”

Keelson を使うとき、開発者が関わる範囲と Keelson が引き受ける範囲は明確に分かれています。

アプリが担うことKeelson が担うこと
UIデプロイ先の用意
業務ロジック公開URL
APIログイン保護
データ処理アプリへのアクセス制御
実行環境の管理

この分担があるため、アプリの開発者はインフラやセキュリティの構築に時間を割く必要がありません。

なぜ Keelson は社内・チーム共有に向いているのか

Section titled “なぜ Keelson は社内・チーム共有に向いているのか”

Keelson は、ローカルで一人だけが使うアプリのための基盤ではありません。チームや社内で安全に共有することを前提に設計されています。

そのため、以下の機能がプラットフォームに組み込まれています。

  • 公開URL — デプロイするだけでチームに共有できるURLが発行される
  • ログイン保護 — 許可されたメンバーだけがアクセスできる
  • メンバー管理 — 誰がどのアプリにアクセスできるかを制御できる

これらの詳細は、以下のページで説明しています。

まずアプリを動かし、細かい設定はあとから足す

Section titled “まずアプリを動かし、細かい設定はあとから足す”

最初はアプリを載せて動かすことに集中すれば十分です。

Keelson の設定は段階的に進められます。クイックスタート で触れた体験は最小構成の入り口であり、必要に応じて以下のような設定をあとから追加できます。

アプリを作る


対応アプリ種類

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson は、社内やチームで共有する Web アプリ・API・定期実行ジョブを安全にデプロイ・公開するための実行基盤です。

AI(ChatGPT、Claude、Manus など)で生成した小〜中規模の業務アプリに特に向いています。

想定しているアプリの例:

  • 社内ツール — 顧客管理、案件管理、在庫管理など
  • 管理画面 — データの閲覧・編集用ダッシュボード
  • 連携アプリ — Slack / Notion / Google Sheets との自動連携
  • 軽量な自動化処理 — CSV取込、定期集計、通知バッチ
  • バックオフィス向けアプリ — 承認申請、日報・レポート生成

フォーム+一覧表示+SQLite。CRUD 操作が中心の典型的な業務アプリで、Keelson のデータ永続化(/data)がそのまま使えます。

テキスト検索 UI+バックエンド API。社内ナレッジを検索・閲覧するためのアプリで、認証付きで安全に社内公開できます。

ファイルアップロード+加工処理+ダウンロード。定型業務の自動化に最適で、Keelson なら非エンジニアにも URL を共有するだけで使ってもらえます。

フォーム送信+ステータス管理+通知。ワークフロー系の小さなアプリで、チーム内のメンバー管理と組み合わせてアクセス制御できます。

入力フォーム+テンプレート出力。日次・週次の報告を定型化するアプリで、定期実行ジョブ(cron)と組み合わせて自動集計も可能です。

Webhook 受信+API 呼び出し。外部サービスとのデータ連携を行うアプリで、Web アプリ+定期ジョブの組み合わせで構成できます。

cron ジョブのみで動く構成。売上集計、ログ解析、通知送信など、UI なしで定期実行だけを行うケースにも対応しています。

チャット UI+LLM API 呼び出し。社内向けの AI アシスタントを、認証付きで安全にチームに提供できます。


対応ランタイム / フレームワークの考え方

Section titled “対応ランタイム / フレームワークの考え方”

Keelson は特定のフレームワーク専用の PaaS ではありません。HTTP サーバーとして起動する標準的な構成のアプリであれば、フレームワークを問わず動かせます。

ランタイム用途
python-slim軽量な Python アプリ(API、テキスト処理など)
python-mediaメディア処理向け Python(画像・動画ライブラリ含む)
node-slim軽量な Node.js アプリ
node-mediaメディア処理向け Node.js
go-slim軽量な Go アプリ
go-mediaメディア処理向け Go
  • Web アプリ — HTTP サーバーとして起動し、ブラウザからアクセスするもの
  • API サーバー — JSON API を提供するバックエンド
  • 定期実行ジョブ(cron) — スケジュールに従って定期的にコマンドを実行するもの
  • ワーカープロセス — Web アプリと並行して動くバックグラウンド処理

フレームワークの例: FastAPI、Flask、Express、Next.js、Hono、Gin など。keelson.yamlcommand で起動できるものであれば動作します。


以下に当てはまるなら、Keelson が適しています。

  • 社内利用が前提 — チームや社内のメンバーに限定して公開したい
  • 認証をかけて安全に公開したい — ログイン保護をアプリに実装せずに済ませたい
  • 小さなアプリを複数動かしたい — 1つのワークスペースで複数アプリを管理できる
  • SQLite やファイル保存を使いたい/data への永続化がプラットフォーム標準で使える
  • AI に作らせたアプリをまず動かしたい — Dockerfile 不要、keelson.yaml だけでデプロイできる
  • 開発者以外にも見せたい — URL を共有するだけで、非エンジニアもブラウザからアクセスできる

以下のようなケースには、Keelson は最適ではありません。

  • 超高トラフィックな一般公開サービス — 大規模なコンシューマー向けサービスは想定外
  • 厳しい低レイテンシが必要な edge 寄りの用途 — CDN エッジでの実行には非対応
  • 複雑な分散システム — マイクロサービス間の高度なオーケストレーションには向かない
  • GPU 前提の重い推論基盤 — GPU インスタンスは提供していない
  • 特殊なミドルウェア前提の構成 — Redis、PostgreSQL(外部)、Kafka などを自前で構成する必要がある場合
  • 厳密なネットワーク制御や専有インフラが必須 — VPC ピアリング、専用ノードなどが初期要件の場合

判断チャート: あなたのアプリは Keelson 向きか

Section titled “判断チャート: あなたのアプリは Keelson 向きか”

以下の質問に順番に答えてください。3分で判断できます。

1. 利用者は社内・チームメンバーが中心ですか? → いいえ → 不特定多数への公開サービスには向いていません

2. アプリは Web UI または API を提供しますか? → いいえ → 定期実行ジョブ(cron)だけの構成でも対応可能です。それ以外の形態は対象外です

3. Node.js / Python / Go のいずれかで動きますか? → いいえ → 現時点ではこの3つのランタイムに対応しています

4. GPU や特殊なミドルウェア(Redis、Kafka など)は必要ですか? → はい → 現時点では対応していません

5. 専有インフラや厳密なネットワーク制御は初期要件ですか? → はい → Enterprise プランでの対応を検討中です。お問い合わせください

すべてクリアした場合 → Keelson で動かせます。


もっとも単純な構成でデプロイする例を示します。

ディレクトリ構成:

my-app/
├── keelson.yaml
├── requirements.txt
└── app.py

keelson.yaml:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"

app.py:

from fastapi import FastAPI
import uvicorn, os
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello from Keelson"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

ディレクトリ構成:

my-app/
├── keelson.yaml
├── package.json
└── index.js

keelson.yaml:

slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
NODE_ENV: production

index.js:

const express = require("express");
const app = express();
const port = process.env.PORT || 8080;
app.get("/", (req, res) => {
res.json({ message: "Hello from Keelson" });
});
app.listen(port, "0.0.0.0", () => {
console.log(`Listening on port ${port}`);
});

デプロイが完了すると、https://my-app.keelson.run/ のような URL が発行されます。この URL にアクセスすると、ログイン済みのメンバーだけがアプリを利用できます。


不要です。keelson.yaml でランタイムと起動コマンドを指定するだけでデプロイできます。Keelson がビルドと実行環境の構築を行います。

フロントエンド単体(静的サイト)も置けますか?

Section titled “フロントエンド単体(静的サイト)も置けますか?”

はい。keelson.yamlassets を設定すれば、ビルド済みの静的ファイルをホストできます。

はい。UI を持たない JSON API サーバーも問題なくデプロイできます。

ビルドとランタイム

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson にアプリをデプロイすると、以下の流れで公開されます。

ソースコード → CLI / AI エージェントが送信 → Keelson がビルド → コンテナとして起動 → 公開 URL 発行
認証・アクセス制御が前段で適用
  1. ソースコードを送る — CLI(keelson deploy)または AI エージェントの Skill がソースコードと keelson.yaml を Keelson に送信します
  2. Keelson がビルドする — 指定されたランタイムに基づいて、依存関係のインストールと実行環境の構築が自動で行われます
  3. コンテナとして起動する — ビルドされたアプリが keelson.yamlcommand に従って起動します
  4. 公開 URL が発行されるhttps://<slug>.keelson.run/ の URL が払い出されます
  5. 認証・アクセス制御が適用される — すべてのリクエストは認証プロキシを経由し、ログイン済みの許可されたメンバーだけがアクセスできます

開発者がビルドやインフラの設定を行う必要はありません。keelson.yaml に必要な情報を記述すれば、あとは Keelson が処理します。


Keelson では、1つのアプリが1つの実行単位になります。アプリの種類に応じて、以下の形態で動作します。

HTTP サーバーとして起動し、リクエストを受け付け続けます。ブラウザからアクセスする UI や、JSON API を返すバックエンドがこの形態です。

スケジュールに従って定期的にコマンドを実行します。集計処理、通知送信、データ同期などに使います。Web アプリとは独立して定義でき、Web アプリを持たない cron だけの構成も可能です。

Web アプリと並行して動くバックグラウンド処理です。キュー処理やデータの非同期処理に使います。Web アプリが存在する場合にのみ追加できます。

これらは組み合わせて使えます。

構成説明
Web アプリのみもっとも一般的な構成
Web アプリ + cronアプリに加えて定期処理を実行
Web アプリ + ワーカーアプリに加えてバックグラウンド処理を実行
cron のみUI なしで定期実行だけを行う

アプリには3つの状態があります。

  • running — 実行中。Active Apps 枠を消費
  • sleep — 自動スリープ。アクセス時に自動起動
  • stop — 手動停止。ダッシュボードから手動で起動

再デプロイすると、新しいコードでアプリが置き換えられます。/data に保存されたデータは再デプロイ後も保持されます。


対応している言語・ランタイム

Section titled “対応している言語・ランタイム”

現時点で以下のランタイムに対応しています。

ランタイム言語用途
python-slimPython軽量(API、テキスト処理、自動化など)
python-mediaPythonメディア処理向け(画像・動画・PDF ライブラリを含む)
node-slimNode.js軽量(Web アプリ、API など)
node-mediaNode.jsメディア処理向け(画像・PDF 処理ライブラリを含む)
go-slimGo軽量
go-mediaGoメディア処理向け

keelson.yamlruntime フィールドで指定します。

runtime: python-slim

依存関係は command 内でインストールします。

Python:

command: "pip install --user -r requirements.txt && python app.py"

Node.js:

command: "npm install && npm start"

Go:

# Keelson 側で deploy 時に `./app` がビルドされます。
command: "./app"

keelson.yamlcommand で起動コマンドを指定します。

# 文字列形式(/bin/sh -c で実行)
command: "python app.py"
# リスト形式(exec で直接実行)
command:
- python
- app.py

Web アプリは環境変数 PORT で指定されたポートで HTTP リクエストを待ち受けてください。keelson.yamlenv で設定します。

env:
PORT: "8080"

アプリ側のコード例:

import os
port = int(os.environ.get("PORT", 8080))
const port = process.env.PORT || 8080;

HTTP サーバーは必ず 0.0.0.0 で listen してください。127.0.0.1localhost ではリクエストが届きません。

uvicorn.run(app, host="0.0.0.0", port=port)
app.listen(port, "0.0.0.0");

Keelson のデプロイには2つのフェーズがあります。

ビルド時実行時
何が起きるかソースコードの取得、依存関係のインストール、実行環境の構築アプリの起動、リクエストの処理
環境変数keelson.yamlenv で定義した値が利用可能同じ env の値に加え、Keelson が設定するシステム環境変数が利用可能
ネットワーク外部パッケージレジストリ(npm, PyPI など)への通信が可能外部 API への通信が可能
データ永続化/data はまだ利用できない/data に書き込んだデータは永続化される
  • ビルドログ — 依存関係のインストールやビルド処理の出力。ビルドが失敗した場合の原因特定に使います
  • 実行ログ — アプリの標準出力・標準エラー出力。実行中のエラーやリクエスト処理の確認に使います

いずれもダッシュボードから確認できます。


  • CPU とメモリはプランの Compute Class に応じて割り当てられます
  • リソースはワークスペース内の全アプリに共通の性能帯が適用されます(アプリごとの個別設定ではありません)
  • root 権限は使えません — アプリは非 root ユーザーとして実行されます
  • systemd やデーモン管理は使えません — プロセス管理は command で起動した単一プロセスが基本です
  • コンテナ外への永続書き込みはできません — データを永続化するには /data ディレクトリを使ってください。それ以外のパスへの書き込みは再デプロイ時に失われます
  • HTTP リクエストには一般的なタイムアウトが適用されます
  • 定期実行ジョブ(cron)の timeout は 1〜3,600 秒で設定可能です(デフォルト: 300 秒)
  • アプリから外部の API やサービスへの通信(Egress)はデフォルトで可能です
  • Business プラン以上では、通信先をホスト名単位で制限できます

多くのフレームワークはデフォルトで 127.0.0.1(localhost)で listen します。Keelson ではリクエストがコンテナ外から届くため、0.0.0.0 を明示する必要があります。

# NG
uvicorn.run(app, host="127.0.0.1", port=port)
# OK
uvicorn.run(app, host="0.0.0.0", port=port)

ポートがハードコードされている

Section titled “ポートがハードコードされている”

ポート番号をコードに直接書くと、Keelson の環境で一致しない場合があります。環境変数 PORT から読み取ってください。

// NG
app.listen(3000);
// OK
app.listen(process.env.PORT || 8080);

依存関係がインストールされていない

Section titled “依存関係がインストールされていない”

command に依存関係のインストールを含め忘れると、実行時にモジュールが見つからずエラーになります。

# NG
command: "python app.py"
# OK
command: "pip install --user -r requirements.txt && python app.py"

エントリポイントのファイル名やパスが間違っていると、アプリが起動しません。ローカルで同じコマンドを実行して動作を確認してください。

ローカルでは動くが Keelson では落ちる

Section titled “ローカルでは動くが Keelson では落ちる”

よくある原因:

  • ローカルにだけ存在するファイルやディレクトリに依存している
  • 環境変数が設定されていない
  • localhost 前提の外部サービス接続(ローカル DB など)
  1. ビルドログを確認する — ダッシュボードでビルドの出力を確認し、依存関係のインストールが成功しているか確認
  2. 実行ログを確認する — アプリの起動時エラーやランタイムエラーがないか確認
  3. keelson.yaml を確認するruntimecommandenv の設定が正しいか見直す

サンプル: Node / Python の最小構成

Section titled “サンプル: Node / Python の最小構成”

必要ファイル:

my-api/
├── keelson.yaml
├── requirements.txt
└── app.py

keelson.yaml:

slug: my-api
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"

requirements.txt:

fastapi
uvicorn

app.py:

from fastapi import FastAPI
import uvicorn, os
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello from Keelson"}
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
uvicorn.run(app, host="0.0.0.0", port=port)

必要ファイル:

my-app/
├── keelson.yaml
├── package.json
└── index.js

keelson.yaml:

slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
NODE_ENV: production

package.json:

{
"name": "my-app",
"scripts": { "start": "node index.js" },
"dependencies": { "express": "^4" }
}

index.js:

const express = require("express");
const app = express();
const port = process.env.PORT || 8080;
app.get("/", (req, res) => {
res.json({ message: "Hello from Keelson" });
});
app.listen(port, "0.0.0.0", () => {
console.log(`Listening on port ${port}`);
});

デプロイが完了すると https://my-app.keelson.run/ のような URL が発行されます。ブラウザでアクセスし、{"message": "Hello from Keelson"} が表示されれば成功です。


AI に依頼するときのプロンプト例

Section titled “AI に依頼するときのプロンプト例”

Keelson は AI で生成したアプリをそのままデプロイできるように設計されています。以下のようなプロンプトを AI に渡すと、Keelson 互換のアプリを生成しやすくなります。

Keelson で動く FastAPI アプリを作ってください。環境変数 PORT で指定されたポートで 0.0.0.0 を listen してください。

SQLite データベースを /data/main.db に保存してください。/data は永続化されるディレクトリです。

毎日午前3時にデータを集計するバッチ処理を追加してください。メインの Web アプリとは別に cron ジョブとして実行します。

keelson.yaml の生成を依頼する場合

Section titled “keelson.yaml の生成を依頼する場合”

このアプリ用の keelson.yaml を作成してください。ランタイムは python-slim、起動コマンドは pip install --user -r requirements.txt && python app.py です。

AI にアプリを生成させるとき、以下の3点を伝えるとスムーズです。

  1. ポートPORT 環境変数から読み取り、0.0.0.0 で listen する
  2. データ保存先 — ファイルや SQLite は /data ディレクトリに置く
  3. 起動方法 — 単一のコマンドで起動できるようにする

Keelson のビルド・ランタイムが向いているケース

Section titled “Keelson のビルド・ランタイムが向いているケース”
  • 標準的な Node.js / Python / Go アプリ — 特殊なビルドツールチェーンが不要
  • AI で生成したアプリをすぐに動かしたい — Dockerfile を書かずにデプロイできる
  • 依存関係が pip / npm / go mod で管理されている — command 内でインストールするだけ
  • HTTP サーバーとして起動するアプリ — ポートを listen するだけで公開される
  • Dockerfile による細かいビルド制御が必要 — Keelson は独自の Dockerfile を使えません
  • システムパッケージの追加インストールが必要apt-get 等で追加するパッケージが多い場合は media ランタイムで対応できるか確認してください
  • root 権限やデーモンプロセスが前提 — アプリは非 root で動作し、systemd は使えません
  • ビルド成果物を細かくキャッシュしたい — ビルドキャッシュの制御は Keelson に委ねる形です

使えません。Keelson はランタイムを選択し、command で起動する方式です。Dockerfile の代わりに keelson.yaml でランタイムと起動コマンドを指定します。

ビルドにかかる時間はどのくらいですか?

Section titled “ビルドにかかる時間はどのくらいですか?”

依存関係の量によりますが、一般的な小〜中規模のアプリであれば1〜2分程度です。

外部の API やサービスに接続できますか?

Section titled “外部の API やサービスに接続できますか?”

はい。アプリから外部への通信(Egress)はデフォルトで可能です。Business プラン以上では通信先をホスト名単位で制限することもできます。

ビルドが失敗したらどうすればいいですか?

Section titled “ビルドが失敗したらどうすればいいですか?”

ダッシュボードでビルドログを確認してください。AI エージェントにログを渡して「このビルドエラーを修正して」と依頼するのも有効です。

ストレージとデータ

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson のアプリには、2種類のファイルシステム領域があります。

領域再デプロイ時用途
アプリディレクトリ(ソースコード等)置き換わるアプリのコード、依存パッケージ
/data残るデータベース、アップロードファイル、永続データ

永続化したいものは /data に置いてください。 それ以外の場所に書き込んだデータは、再デプロイ時に失われます。

/data はアプリごとに分離されており、他のアプリからはアクセスできません。ワークスペース単位で容量が管理され、データは東京リージョンに保存されます。


/data には、アプリが必要とするあらゆるファイルを保存できます。

  • SQLite データベース — 顧客管理、案件管理、ログなどのアプリデータ
  • アップロードファイル — ユーザーがフォームから送信した画像、PDF、CSV など
  • 生成済みレポート — 集計結果やエクスポートファイル
  • キャッシュデータ — 外部 API のレスポンスや計算結果の再利用
  • 設定ファイル — アプリが実行時に生成する設定やステートファイル

社内ツールでよくある使い方:

/data/main.db # アプリのメインデータベース
/data/uploads/ # ユーザーがアップロードしたファイル
/data/reports/ # 日次・週次で生成したレポート

/data に保存しない方がよいもの

Section titled “/data に保存しない方がよいもの”

以下は /data 以外の方法を検討してください。

  • 巨大なバイナリファイル — 動画ファイルや大容量のデータセットはストレージ容量を圧迫します。外部のオブジェクトストレージ(S3 互換サービスなど)を検討してください
  • 一時ファイル — 処理中だけ必要なファイルは /tmp を使い、処理後に削除してください
  • 再生成可能なキャッシュ — npm の node_modules やビルド成果物は /data に置く必要はありません
  • 大規模ログの長期保存 — アプリログは Keelson のログ機能で閲覧できます。独自の大量ログを /data に蓄積するとストレージを消費します
  • 高い可搬性が求められるデータ — 他のシステムとの頻繁なデータ連携が必要な場合は、外部データベースが適しています

SQLite は Keelson でもっとも推奨されるデータベースです。外部の DB サーバーを用意する必要がなく、/data にファイルを置くだけで使えます。

  • セットアップ不要 — DB サーバーの構築・接続設定が不要
  • AI 生成との相性 — ChatGPT や Claude が生成するアプリの多くは SQLite を使う構成になる
  • 永続化が自動/data に置けば再デプロイ後もデータが残る
  • バックアップ対象 — 日次スナップショットの対象に含まれる
databases:
- name: main
type: sqlite
path: /data/main.db

複数のデータベースを使うこともできます。

databases:
- name: customers
type: sqlite
path: /data/customers.db
- name: logs
type: sqlite
path: /data/logs.db
  • 単一インスタンス前提 — Keelson のアプリは1つのインスタンスで動作します。複数インスタンスからの同時書き込みを考慮する必要はありません
  • 書き込みが非常に多い場合 — 秒間数百回以上の書き込みが発生するようなケースでは、外部データベース(PostgreSQL など)を検討してください
  • データ量が大きい場合 — 数 GB を超える SQLite ファイルはパフォーマンスに影響する可能性があります。データ量が大きくなる見込みがある場合は、早めに外部 DB への移行を計画してください

ユーザーがアップロードしたファイルは /data 配下に保存します。

/data/uploads/
├── 2026-03/
│ ├── a1b2c3d4-report.pdf
│ └── e5f6g7h8-photo.jpg
└── 2026-04/
└── i9j0k1l2-invoice.csv

ユーザーがアップロードしたファイル名をそのまま使うと、同名ファイルが上書きされます。UUID やタイムスタンプをプレフィックスに付けてください。

import uuid, os
def save_upload(file, upload_dir="/data/uploads"):
filename = f"{uuid.uuid4().hex}_{file.filename}"
path = os.path.join(upload_dir, filename)
with open(path, "wb") as f:
f.write(file.read())
return path

ストレージ容量はプランによって異なります(Starter: 10 GB 〜 Business: 100 GB)。この容量には /data のデータ、スナップショット、ログの合計が含まれます。

不要になったファイルは定期的に削除する仕組みを入れておくと安心です。定期実行ジョブ(cron)で古いファイルを自動削除するのも有効です。

  • アップロードされたファイルの拡張子やサイズを検証してください
  • ユーザーが指定したファイル名をそのままパスに使わないでください(ディレクトリトラバーサルの防止)
  • Keelson の認証プロキシにより、アプリ自体へのアクセスは保護されていますが、アプリ内でのファイルアクセス制御はアプリ側の責務です

Keelson は /data のスナップショットを毎日自動で取得します。保持日数はプランによって異なります。

プランスナップショット保持
Starter1日分
Plus3日分
Team7日分
Business14日分

手動スナップショットは、SQLite 管理画面から任意のタイミングで取得できます(全プラン)。

対象バックアップされるか
/data 配下のファイル(SQLite、アップロードファイルなど)される
アプリのソースコードされない(デプロイ時に毎回送信される)
環境変数されない(ダッシュボードで管理)

アプリのコードは Git などのバージョン管理で保持し、データは Keelson のスナップショットで保護されます。

スナップショットからの復元が必要な場合は、ダッシュボードから操作できます。復元はアプリ単位で行われ、他のアプリのデータには影響しません。


外部データベースや外部ストレージを使うべき場合

Section titled “外部データベースや外部ストレージを使うべき場合”

/data + SQLite は多くの社内アプリに十分ですが、以下のケースでは外部サービスの利用を検討してください。

ケース理由選択肢
データ量が数 GB を超えるSQLite のパフォーマンスが低下する可能性PostgreSQL(アドオンで専用 DB を利用可能)
同時書き込みが非常に多いSQLite はライター1つの制約があるPostgreSQL、MySQL
BI や基幹系と直接連携するデータを外部システムから参照する必要がある共有の PostgreSQL、データウェアハウス
厳密な運用要件があるポイントインタイムリカバリや複雑なレプリケーションが必要マネージド PostgreSQL
大容量ファイルを大量に扱うストレージ容量を超える可能性S3 互換オブジェクトストレージ

顧客管理や在庫管理など。SQLite にデータを保存し、アップロードファイルも /data に配置。

databases:
- name: main
type: sqlite
path: /data/main.db
/data/
├── main.db
└── uploads/

CSV の取込・加工を行うアプリ。入力と出力を分離して管理。

/data/
├── inbox/ # 取込対象の CSV
├── outbox/ # 加工済みの出力
└── processed/ # 処理済みの入力(アーカイブ)

社内 RAG や AI チャットのバックエンド。ナレッジベースのデータや添付資料を /data に配置。

/data/
├── knowledge.db # ナレッジのメタデータ
├── documents/ # 参照ドキュメント
└── embeddings.cache # 前処理済みの埋め込みキャッシュ

定期実行ジョブで集計し、結果を /data に保存。Web UI から閲覧。

/data/
├── stats.db
└── reports/
├── 2026-03-01.json
├── 2026-03-02.json
└── ...

/tmp やアプリディレクトリに保存して消える

Section titled “/tmp やアプリディレクトリに保存して消える”

/tmp やアプリのソースコードと同じディレクトリに書き込んだデータは、再デプロイ時に失われます。永続化したいデータは必ず /data に置いてください。

# NG — 再デプロイで消える
db_path = "./data.db"
db_path = "/tmp/data.db"
# OK — 再デプロイ後も残る
db_path = "/data/main.db"

再デプロイで初期化される場所に DB を置く

Section titled “再デプロイで初期化される場所に DB を置く”

SQLite のパスを /data 以外に設定すると、デプロイのたびにデータが消えます。keelson.yamldatabases[].path/data/ で始まっていることを確認してください。

バックアップの仕組みを誤解する

Section titled “バックアップの仕組みを誤解する”

スナップショットは日次で自動取得されますが、保持日数はプランによって異なります。重要なデータを扱う場合は、プランの保持日数を確認し、必要に応じてアプリ側でもエクスポート機能を用意してください。

不要になったファイルを削除せずに放置すると、ストレージ容量を圧迫します。ストレージ容量にはスナップショットやログも含まれるため、アプリデータだけで上限いっぱいにならないよう注意してください。

ローカルのパスをハードコードする

Section titled “ローカルのパスをハードコードする”

/Users/tanaka/Desktop/data.db のようなローカルパスがコードに残っていると、Keelson 上では動作しません。環境変数または /data への相対的なパスを使ってください。

import os
# OK — 環境変数から読む
db_path = os.environ.get("DB_PATH", "/data/main.db")

Python: SQLite でデータを保存する

Section titled “Python: SQLite でデータを保存する”
import sqlite3, os
DB_PATH = os.environ.get("DB_PATH", "/data/main.db")
def get_db():
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
return conn
# データの追加
conn = get_db()
conn.execute("INSERT INTO items (name) VALUES (?)", ("サンプルアイテム",))
conn.commit()
conn.close()

keelson.yaml:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
DB_PATH: "/data/main.db"
databases:
- name: main
type: sqlite
path: /data/main.db

Node.js: SQLite でデータを保存する

Section titled “Node.js: SQLite でデータを保存する”
const Database = require("better-sqlite3");
const path = process.env.DB_PATH || "/data/main.db";
const db = new Database(path);
db.exec(`
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// データの追加
db.prepare("INSERT INTO items (name) VALUES (?)").run("サンプルアイテム");

Python: ファイルアップロードを保存する

Section titled “Python: ファイルアップロードを保存する”
from fastapi import FastAPI, UploadFile
import uuid, os
app = FastAPI()
UPLOAD_DIR = os.environ.get("UPLOAD_DIR", "/data/uploads")
os.makedirs(UPLOAD_DIR, exist_ok=True)
@app.post("/upload")
async def upload(file: UploadFile):
filename = f"{uuid.uuid4().hex}_{file.filename}"
filepath = os.path.join(UPLOAD_DIR, filename)
with open(filepath, "wb") as f:
content = await file.read()
f.write(content)
return {"filename": filename, "path": filepath}

Node.js: ファイルアップロードを保存する

Section titled “Node.js: ファイルアップロードを保存する”
const express = require("express");
const multer = require("multer");
const crypto = require("crypto");
const path = require("path");
const fs = require("fs");
const app = express();
const uploadDir = process.env.UPLOAD_DIR || "/data/uploads";
fs.mkdirSync(uploadDir, { recursive: true });
const storage = multer.diskStorage({
destination: uploadDir,
filename: (req, file, cb) => {
const prefix = crypto.randomBytes(8).toString("hex");
cb(null, `${prefix}_${file.originalname}`);
},
});
app.post("/upload", multer({ storage }).single("file"), (req, res) => {
res.json({ filename: req.file.filename, path: req.file.path });
});

  • 社内アプリの業務データ — 顧客情報、案件、在庫など、SQLite で十分な規模
  • ユーザーがアップロードするファイル — PDF、CSV、画像など
  • AI で生成したアプリをすぐに動かしたい — 外部 DB の設定なしでデータ永続化が使える
  • 小さなアプリを複数動かしたい — アプリごとに /data が分離されている
  • データ量が数十 GB を超える — ストレージ容量とパフォーマンスの両面で外部 DB を検討
  • 複数システムからの同時アクセスが必要/data はアプリ内からのみアクセス可能
  • ポイントインタイムリカバリが必須 — スナップショットは日次のため、より細かい復元が必要ならマネージド DB を検討
  • BI ツールや基幹システムとの直接連携 — 外部からクエリできるデータベースが必要

/data の容量上限はどのくらいですか?

Section titled “/data の容量上限はどのくらいですか?”

プランによって異なります(Starter: 10 GB 〜 Business: 100 GB)。この容量には /data のデータ、スナップショット、ログの合計が含まれます。追加ストレージはアドオンで購入できます。

再デプロイするとデータは消えますか?

Section titled “再デプロイするとデータは消えますか?”

/data に保存したデータは消えません。アプリのソースコード領域は置き換わりますが、/data は再デプロイ後もそのまま残ります。

SQLite 以外のデータベースは使えますか?

Section titled “SQLite 以外のデータベースは使えますか?”

アプリ内で完結するデータベース(SQLite など)はそのまま使えます。外部の PostgreSQL や MySQL に接続することも可能です。アドオンで専用 PostgreSQL を利用することもできます。

他のアプリから /data にアクセスできますか?

Section titled “他のアプリから /data にアクセスできますか?”

できません。/data はアプリごとに完全に分離されています。アプリ間でデータを共有する必要がある場合は、API 経由でやり取りしてください。

バックアップからの復元にかかる時間はどのくらいですか?

Section titled “バックアップからの復元にかかる時間はどのくらいですか?”

データ量によりますが、一般的な社内アプリの規模であれば数分で完了します。


「データベースは SQLite を使い、/data/main.db に保存してください」

「アップロードされたファイルは /data/uploads/ に UUID 付きのファイル名で保存してください」

「環境変数 DB_PATH からデータベースのパスを読み取るようにしてください。デフォルトは /data/main.db です」

定期実行ジョブ(Scheduled Jobs)

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリの公開だけでなく、コードを定期的に自動実行できます。Web アプリと同じコードベース・同じ keelson.yaml でジョブを管理でき、社内業務の自動化に使えます。

代表的なユースケース:

  • 毎朝のレポート生成 — 売上や KPI を集計して /data に保存
  • 毎時間の API 同期 — 外部サービスからデータを取得して DB を更新
  • 毎日の Slack 通知 — 期限切れタスクや承認待ちのリマインド
  • 夜間の CSV 取込 — アップロードされた CSV を一括処理
  • 定期的なデータクリーンアップ — 古いログや一時ファイルの削除

Scheduled Jobs は Active Apps の枠を消費しません。Web アプリとは独立してカウントされます。


  1. keelson.yamlcrons にジョブを定義する
  2. デプロイすると、Keelson が定期実行ジョブとして登録する
  3. 指定したスケジュールに従って、コマンドが自動で実行される
  4. 実行ごとにログが記録される

ジョブの動作は、Web アプリの有無によって異なります。

構成動作
cron のみ(command なし)ジョブごとに独立して実行される
Web アプリ + cron(command あり)Web アプリと同じ実行環境内でジョブが動く

どちらの構成でも、ジョブの定義方法は同じです。

  • 実行結果(成功・失敗)はダッシュボードで確認できます
  • 標準出力・標準エラーがログとして記録されます
  • 実行回数は成功・失敗・リトライ・手動実行をすべて含みます

keelson.yamlcrons セクションでジョブを定義します。

slug: my-app
runtime: python-slim
crons:
- name: daily-report
schedule: "0 9 * * *"
command: "python report.py"
timeout: 120
フィールド必須デフォルト説明
nameはいジョブ名。小文字英数字とハイフン、1〜63 文字
scheduleはいcron 式(5フィールド)
commandはい実行するコマンド
timeoutいいえ300 秒タイムアウト。1〜3,600 秒

1つのアプリに最大10個のジョブを定義できます。

crons:
- name: hourly-sync
schedule: "0 * * * *"
command: "python sync.py"
- name: daily-cleanup
schedule: "0 3 * * *"
command: "python cleanup.py"
timeout: 60
- name: weekly-report
schedule: "0 9 * * 1"
command: "python weekly_report.py"
timeout: 600

トップレベルの env で定義した環境変数は、ジョブの実行時にも利用できます。

env:
DB_PATH: "/data/main.db"
SLACK_WEBHOOK_URL: "https://hooks.slack.com/..."
crons:
- name: notify
schedule: "0 9 * * *"
command: "python notify.py"

スケジュールは5フィールドの cron 式で指定します。

┌───────────── 分(0-59)
│ ┌─────────── 時(0-23)
│ │ ┌───────── 日(1-31)
│ │ │ ┌─────── 月(1-12)
│ │ │ │ ┌───── 曜日(0-6、0=日曜)
│ │ │ │ │
* * * * *
やりたいことcron 式説明
毎日 9:000 9 * * *毎日午前9時に実行
30分ごと*/30 * * * *毎時0分と30分に実行
毎時間0 * * * *毎時0分に実行
10分ごと*/10 * * * *10分間隔で実行
平日のみ 9:000 9 * * 1-5月〜金の午前9時に実行
毎月1日 0:000 0 1 * *月初に実行
毎日深夜 3:000 3 * * *夜間バッチ向き
毎分* * * * *テスト・デバッグ用

  • 入力: /data/sales/ 配下の CSV ファイル
  • 処理: 当日分を集計し、合計・件数を計算
  • 出力: /data/reports/daily-sales-YYYY-MM-DD.json に保存
crons:
- name: daily-sales
schedule: "0 8 * * *"
command: "python aggregate_sales.py"
timeout: 120

毎時間、外部 API からデータ同期

Section titled “毎時間、外部 API からデータ同期”
  • 入力: 外部サービスの REST API
  • 処理: 最新データを取得し、差分を SQLite に反映
  • 出力: /data/main.db の該当テーブルが更新される
crons:
- name: hourly-sync
schedule: "0 * * * *"
command: "python sync_from_api.py"
timeout: 180
  • 入力: SQLite のレコード
  • 処理: expired_at が過去のレコードを削除
  • 出力: 削除件数をログに出力
crons:
- name: cleanup-expired
schedule: "0 2 * * *"
command: "python cleanup_expired.py"
timeout: 60
  • 入力: SQLite の週次データ
  • 処理: テンプレートからレポートを生成
  • 出力: /data/reports/weekly-YYYY-WXX.pdf に保存
crons:
- name: weekly-report
schedule: "0 9 * * 1"
command: "python generate_weekly_report.py"
timeout: 300

ジョブは同じスケジュールで繰り返し実行されます。途中で失敗して再実行されても、データが二重に作成されないように設計してください。

# NG — 毎回 INSERT すると重複する
db.execute("INSERT INTO reports (date, total) VALUES (?, ?)", (today, total))
# OK — UPSERT で既存データを上書き
db.execute("""
INSERT INTO reports (date, total) VALUES (?, ?)
ON CONFLICT(date) DO UPDATE SET total = excluded.total
""", (today, total))

デフォルトのタイムアウトは 300 秒(5分)です。処理に時間がかかる場合は timeout を明示的に設定してください。最大 3,600 秒(1時間)まで指定できます。

ジョブが失敗しても自動リトライは行われません。冪等に設計しておけば、次のスケジュールで自然にリカバリされます。重要なジョブでは、失敗時に Slack 通知を送るなどの仕組みを入れておくと安心です。

外部 API を呼び出すジョブでは、レート制限に注意してください。短い間隔(毎分など)で外部 API を叩くと、制限に引っかかる場合があります。

SQLite への書き込みを伴うジョブが、Web アプリと同じデータベースを使う場合、書き込みのタイミングが重なる可能性があります。SQLite は単一ライターの制約があるため、短時間の待ちが発生することがあります。通常の社内ツール規模であれば問題になりませんが、書き込み頻度が高い場合は注意してください。


ジョブの標準出力(printconsole.log)と標準エラーはすべてログとして記録されます。ダッシュボードからジョブ単位で確認できます。

デバッグ時は、処理の進捗やデータの状態を print で出力しておくと原因特定がしやすくなります。

import datetime
print(f"[{datetime.datetime.now()}] ジョブ開始")
# ... 処理 ...
print(f"処理件数: {count}")
print(f"[{datetime.datetime.now()}] ジョブ完了")
  1. 実行ログを見る — エラーメッセージやスタックトレースを確認
  2. 環境変数を確認する — API キーやデータベースパスが正しいか
  3. タイムアウトを確認する — 処理が timeout の秒数内に終わっているか
  4. 手元で再現する — 同じコマンドをローカルで実行してみる

Keelson のジョブログをそのまま AI エージェントに渡せば、エラーの原因特定と修正を依頼できます。

「このジョブのエラーログを確認して、原因を特定して修正してください」

AI エージェントがログを読み、コードの修正と再デプロイまで一連で対応できます。


Web アプリとジョブを組み合わせる

Section titled “Web アプリとジョブを組み合わせる”

Keelson の強みは、Web アプリ・定期ジョブ・永続データを1つのアプリ内で組み合わせられることです。

パターン: 管理画面 + 夜間バッチ

Section titled “パターン: 管理画面 + 夜間バッチ”

Web アプリで設定やデータを入力し、重い処理は夜間ジョブに任せる構成です。

slug: sales-tool
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
DB_PATH: "/data/sales.db"
databases:
- name: sales
type: sqlite
path: /data/sales.db
crons:
- name: nightly-aggregate
schedule: "0 2 * * *"
command: "python aggregate.py"
timeout: 300
  • 日中: 管理画面から売上データを入力
  • 深夜: ジョブが集計処理を実行し、レポートデータを更新
  • 翌朝: 管理画面で集計結果を閲覧

パターン: アップロード CSV の定期処理

Section titled “パターン: アップロード CSV の定期処理”

ユーザーが Web UI から CSV をアップロードし、ジョブが定期的に処理する構成です。

crons:
- name: process-csv
schedule: "*/30 * * * *"
command: "python process_inbox.py"
timeout: 180
  • Web アプリ: CSV を /data/inbox/ にアップロード
  • ジョブ(30分ごと): /data/inbox/ の未処理ファイルを処理し、結果を /data/outbox/ に保存
  • Web アプリ: 処理結果を一覧表示・ダウンロード

ジョブが毎朝データを要約し、Web アプリで閲覧する構成です。

crons:
- name: daily-summary
schedule: "0 7 * * *"
command: "python generate_summary.py"
timeout: 600
  • ジョブ(毎朝 7:00): 前日のデータを AI API で要約し、結果を SQLite に保存
  • Web アプリ: 要約を日付別に閲覧

cron 式のフィールド順(分・時・日・月・曜日)を間違えやすいです。「9時に実行したい」場合は 0 9 * * * です。9 0 * * * とすると毎日 0:09 に実行されます。

# NG — 毎日 0:09 に実行される
schedule: "9 0 * * *"
# OK — 毎日 9:00 に実行される
schedule: "0 9 * * *"

一時ファイルと永続ファイルを混同する

Section titled “一時ファイルと永続ファイルを混同する”

ジョブの出力を /tmp に保存すると、次回の実行時には消えている場合があります。結果を残したい場合は /data に保存してください。

ローカルでは動くが本番で認証情報が足りない

Section titled “ローカルでは動くが本番で認証情報が足りない”

外部 API を呼び出すジョブで、API キーをローカルの環境変数にだけ設定していると、Keelson 上では認証エラーになります。keelson.yamlenv またはダッシュボードで環境変数を設定してください。

外部 API のレート制限に引っかかる

Section titled “外部 API のレート制限に引っかかる”

毎分実行のジョブで外部 API を大量に呼ぶと、レート制限で失敗します。実行間隔を広げるか、ジョブ内でリクエスト数を制御してください。

Scheduled Jobs にはプランごとに月間の実行回数上限があります(Starter: 3,000回 〜 Business: 80,000回)。上限に達すると、当月の残りの実行はスキップされます。毎分実行(* * * * *)は月間約43,200回になるため、テスト以外では避けてください。


Web アプリなしで、ジョブだけを動かす最小構成です。

slug: my-cron
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
crons:
- name: heartbeat
schedule: "* * * * *"
command: "python heartbeat.py"
timeout: 30

heartbeat.py:

import datetime
print(f"OK: {datetime.datetime.now()}")

Python: 売上データを集計して保存する

Section titled “Python: 売上データを集計して保存する”
import sqlite3, json, os, datetime
DB_PATH = os.environ.get("DB_PATH", "/data/main.db")
REPORT_DIR = "/data/reports"
os.makedirs(REPORT_DIR, exist_ok=True)
conn = sqlite3.connect(DB_PATH)
today = datetime.date.today().isoformat()
row = conn.execute(
"SELECT COUNT(*), SUM(amount) FROM sales WHERE date = ?", (today,)
).fetchone()
report = {"date": today, "count": row[0], "total": row[1] or 0}
report_path = os.path.join(REPORT_DIR, f"daily-{today}.json")
with open(report_path, "w") as f:
json.dump(report, f, ensure_ascii=False)
print(f"集計完了: {report}")
conn.close()

Node.js: 外部 API からデータを同期する

Section titled “Node.js: 外部 API からデータを同期する”
const Database = require("better-sqlite3");
const DB_PATH = process.env.DB_PATH || "/data/main.db";
const API_URL = process.env.SYNC_API_URL;
async function sync() {
const res = await fetch(API_URL);
const items = await res.json();
const db = new Database(DB_PATH);
db.exec(`
CREATE TABLE IF NOT EXISTS synced_items (
id TEXT PRIMARY KEY,
data TEXT,
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
const stmt = db.prepare(`
INSERT INTO synced_items (id, data) VALUES (?, ?)
ON CONFLICT(id) DO UPDATE SET data = excluded.data, synced_at = CURRENT_TIMESTAMP
`);
for (const item of items) {
stmt.run(item.id, JSON.stringify(item));
}
console.log(`同期完了: ${items.length} 件`);
db.close();
}
sync().catch((err) => {
console.error("同期失敗:", err);
process.exit(1);
});
import os, json, urllib.request, datetime
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
message = {
"text": f"日次レポート準備完了: {datetime.date.today()}"
}
req = urllib.request.Request(
SLACK_WEBHOOK,
data=json.dumps(message).encode(),
headers={"Content-Type": "application/json"},
)
urllib.request.urlopen(req)
print("Slack 通知送信完了")

keelson.yaml:

slug: daily-notifier
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
SLACK_WEBHOOK_URL: "https://hooks.slack.com/services/..."
crons:
- name: daily-notify
schedule: "0 9 * * 1-5"
command: "python notify.py"
timeout: 30

定期実行ジョブが向いているケース

Section titled “定期実行ジョブが向いているケース”
  • 定型業務の自動化 — 毎日・毎時間の集計、通知、データ同期
  • Web アプリと組み合わせた業務フロー — 日中は入力、夜間にバッチ処理
  • 外部サービスとの定期的なデータ連携 — API からの取得や Webhook 送信
  • 社内データの定期メンテナンス — 古いデータの削除、レポート生成
  • リアルタイム処理 — イベント駆動で即座に反応する必要がある場合は、Web アプリ内で処理してください
  • 1時間を超える長時間処理 — タイムアウトの上限は 3,600 秒です
  • 複雑なジョブチェーン — ジョブ間の依存関係やワークフロー制御が必要な場合は、専用のワークフローエンジンを検討してください
  • 秒単位の精度が必要 — cron 式は分単位の指定です

ジョブが失敗したら自動でリトライされますか?

Section titled “ジョブが失敗したら自動でリトライされますか?”

されません。次のスケジュールで再実行されます。ジョブを冪等に設計しておけば、自然にリカバリされます。

Web アプリなしでジョブだけ動かせますか?

Section titled “Web アプリなしでジョブだけ動かせますか?”

はい。keelson.yamlcommand を省略し、crons だけを定義すれば、ジョブ専用のアプリとしてデプロイできます。

ジョブの実行結果をどこで確認できますか?

Section titled “ジョブの実行結果をどこで確認できますか?”

ダッシュボードから、ジョブごとの実行履歴・成功/失敗のステータス・ログを確認できます。

月間実行回数の上限に達したらどうなりますか?

Section titled “月間実行回数の上限に達したらどうなりますか?”

当月の残りの実行はスキップされます。翌月にリセットされます。上限はプランによって異なります(Starter: 3,000回 〜 Business: 80,000回)。

タイムゾーンはどうなっていますか?

Section titled “タイムゾーンはどうなっていますか?”

cron 式の時刻はサーバーのタイムゾーンに従います。


「毎朝9時に売上データを集計するジョブを追加してください。keelson.yaml の crons に定義してください」

「30分ごとに外部 API からデータを取得して SQLite に同期するバッチ処理を作ってください」

「このアプリに、毎日深夜3時に古いデータを削除するクリーンアップジョブを追加してください」

keelson.yaml の設定

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

keelson.yaml は、Keelson がアプリをどのようにビルドし、起動し、公開するかを判断するための設定ファイルです。

このページでは、keelson.yaml が何のためにあるのか、何を書けばよいのか、どう使われるのかを説明します。各フィールドの完全な定義については keelson.yaml リファレンス を参照してください。

ただし、keelson.yaml は Keelson の Agent Skill 機能を使えば AI エージェントが自動生成してくれるため、通常は自分で作成する必要はありません。

keelson.yaml は、アプリごとに用意する設定ファイルです。プロジェクトのルートディレクトリに配置します。

Keelson はこのファイルを読み取り、次のことを判断します。

  • アプリの識別子(URL の一部になる)
  • どのランタイムで動かすか
  • どのように起動するか
  • 永続ストレージやデータベースを使うか
  • 定期実行ジョブやバックグラウンドワーカーがあるか
  • 静的アセット配信を行うか

keelson.yaml は、アプリのコードそのものではなく、そのアプリを Keelson 上で動かすための説明書です。すべての設定項目を覚える必要はなく、まずは最小限の構成から始められます。

同じ Web アプリでも、使用する言語、起動コマンド、必要な機能はアプリごとに異なります。

Keelson は keelson.yaml を通じてその違いを理解し、適切な方法でアプリをデプロイします。このファイルがないと、Keelson はそのアプリをどう扱えばよいか判断できません。

AI エージェントでデプロイする場合も、keelson.yaml はアプリの構成を理解するための重要な手がかりになります。エージェントがアプリのコードを読み取って keelson.yaml を自動生成することもできます。

keelson.yaml は、デプロイの開始時に読み取られます。

Keelson はこの設定をもとに、次の処理を行います。

  1. 設定の検証 — フィールドの値やフィールド間の制約をチェックする
  2. ビルド — ランタイムに応じたコンテナイメージを作成する
  3. 起動command で指定されたコマンドでアプリを開始する
  4. 機能の有効化 — ストレージ、データベース、定期実行ジョブなど、設定された機能を準備する
  5. 公開slug に基づいた URL でアプリにアクセスできるようにする

設定がアプリの実際の構成と合っていない場合、ビルドに失敗したり、ビルドは成功しても起動できなかったりすることがあります。

keelson.yaml のフィールドはすべてトップレベルに配置します。

フィールド説明
slugアプリの識別子。URL の一部になるmy-app
runtime実行環境python-slim, node-slim, go-slim
command起動コマンド"python app.py"

command は、依存パッケージのインストールと起動を 1 つのコマンドにまとめて書きます。

command: "python -m pip install -r requirements.txt && python app.py"
フィールド説明
env環境変数(キーと値のペア)
storage永続ストレージの設定
databasesSQLite データベースの設定
crons定期実行ジョブ
workersバックグラウンドワーカー
assets静的アセット配信
typeアプリ種別(web を指定すると静的サイトモード)

各フィールドの型、制約、指定可能な値については keelson.yaml リファレンス を参照してください。

commandassets の組み合わせによって、デプロイモードが自動的に決まります。

パターンcommandassets動作
通常のアプリありなしコンテナとして起動
静的サイト / SPAなしあり静的ファイルを配信
ハイブリッドありあり静的ファイル + バックエンド API

API キー、トークン、パスワードなどの秘密情報は keelson.yaml に直接書かないでください。

keelson.yaml はソースコードと一緒にリポジトリに含まれるファイルです。秘密情報は環境変数またはシークレットとして、コンソールから設定します。

# NG: 秘密情報を直接書いている
env:
OPENAI_API_KEY: "sk-xxxxxxxxxxxxx"
# OK: 値はコンソールで設定し、keelson.yaml には書かない
env:
PORT: "8080"
NODE_ENV: "production"

環境変数の管理については 環境変数とシークレット を参照してください。

まずは slugruntimecommand の 3 つだけで始められます。

slug: my-app
runtime: python-slim
command: "python -m pip install -r requirements.txt && python app.py"
env:
PORT: "8080"
slug: my-app
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
slug: my-app
runtime: go-slim
# Keelson が deploy 時に Linux 向け binary を `./app` としてビルドします。
command: "./app"
env:
PORT: "8080"

ランタイムには -slim(軽量)と -media(画像・動画処理ライブラリ含む)の 2 種類があります。迷った場合は -slim から始めてください。

アプリの種類によって、使うフィールドが変わります。

データベースを使うアプリでは、storagedatabases を追加します。

slug: my-app
runtime: python-slim
command: "python -m pip install -r requirements.txt && python app.py"
env:
PORT: "8080"
DB_PATH: "/data/main.db"
storage:
disk_id: my-app-data
databases:
- name: main
type: sqlite
path: /data/main.db

storage を設定しないと、データは永続化されず Pod の再起動時に失われます。

type: web を指定し、assets でアセットディレクトリを設定します。

slug: my-site
type: web
runtime: node-slim
assets:
dir: dist
fallback: index.html

Web サーバーなしで、定期的にスクリプトを実行するだけのアプリです。

slug: daily-report
runtime: python-slim
crons:
- name: generate
schedule: "0 9 * * *"
command: "python report.py"
timeout: 120

ハイブリッド(静的ファイル + API)

Section titled “ハイブリッド(静的ファイル + API)”

フロントエンドの静的ファイルとバックエンド API を 1 つのアプリで提供します。

slug: my-app
runtime: node-slim
command: "npm install && node server.js"
env:
PORT: "8080"
assets:
dir: public
fallback: index.html
api: /api

各構成パターンの完全な例は keelson.yaml リファレンス を参照してください。

デプロイと設定


デプロイする

このページでは、あなたが作ったアプリをKeelsonにデプロイする方法を説明します。クイックスタートでサンプルアプリを試した方が、自分のアプリを載せるときに読むことを想定しています。

Keelsonにおけるデプロイとは、コードを渡して終わりではありません。アプリがビルドされ、起動し、アプリURLでアクセスできる状態になるまでを指します。

デプロイは次の流れで進みます。

  1. アプリを用意する — ソースコードが手元にある状態にする
  2. keelson.yaml を作成する — Keelsonにアプリの動かし方を伝える設定ファイルを置く
  3. AIエージェントにデプロイを依頼する — Agent Skillを使ってデプロイを実行する
  4. Keelsonがビルド・起動・確認を行う — コンテナイメージのビルド、Pod起動、ヘルスチェックが自動で走る
  5. アプリURLで利用できるようになるhttps://<slug>.keelson.run でアプリにアクセスできる

デプロイを始める前に、以下を確認してください。

  • アプリのソースコードがある
  • 対応しているランタイムでアプリが動く
  • keelson.yaml がプロジェクトのルートに置いてある
  • 必要な環境変数やシークレットを把握している(→ 環境変数とシークレット
  • Keelson CLIがインストールされ、ログイン済みである
  • Agent Skillがインストールされている

keelson.yaml は、Keelsonがアプリをどう動かすかを判断するための設定ファイルです。プロジェクトのルートディレクトリに配置します。

このファイルには、アプリの識別子、使用するランタイム、起動コマンドなど、デプロイに必要な情報を記述します。

最小構成の例:

slug: my-app
runtime: python-slim
command: "python app.py"
  • slug — アプリの識別子。アプリURLの一部になります(my-app.keelson.run
  • runtime — 実行環境。python-slimnode-slimgo-slim など
  • command — アプリの起動コマンド

これ以外にも、環境変数、データベース、定期実行ジョブなどのフィールドがあります。全項目の詳細は keelson.yaml リファレンス を参照してください。

AIエージェントにデプロイを依頼する

Section titled “AIエージェントにデプロイを依頼する”

対象のアプリフォルダをAIエージェント(Claude Code、Codexなど)で開いた状態で、デプロイを依頼します。

依頼の例:

「このアプリをKeelsonにデプロイして」

「keelson.yaml がなければ作成してから、Keelsonにデプロイして」

「起動エラーが出たら原因を調べて修正し、再デプロイして」

AIエージェントは keelson.yaml を読み取り、ビルドとデプロイを自動で実行します。keelson.yaml がない場合は、アプリの構成を判断して作成することもできます。

デプロイを実行すると、Keelsonは以下の処理を順に行います。

  1. 設定の確認keelson.yaml の内容を検証する
  2. ビルド — ソースコードからコンテナイメージを作成する
  3. 起動 — コンテナを起動し、アプリのプロセスを開始する
  4. ヘルスチェック — アプリが正常にリクエストを受け付けるか確認する
  5. アプリURLの発行https://<slug>.keelson.run でアクセス可能になる

ユーザーがこれらの手順を個別に操作する必要はありません。AIエージェントが進行状況を確認しながら完了まで進めます。

デプロイが成功したとは、次の状態を指します。

  • アプリのコンテナが起動している
  • ヘルスチェックに通過している
  • アプリURLでアクセスできる

ビルドが通っただけでは完了ではありません。起動して、URLで正常に開ける状態が「デプロイ成功」です。

デプロイに失敗した場合、AIエージェントはビルドログやランタイムログを確認して原因を調査できます。設定ミスや起動エラーがあれば、修正して再デプロイします。

まずはエラーメッセージを確認し、必要に応じてAIエージェントに修正を依頼してください。

原因対処
keelson.yaml の不足や記述ミスファイルの有無と内容を確認する
起動コマンドの不一致command がアプリの実際のエントリポイントと合っているか確認する
必要な環境変数が未設定コンソールまたは keelson.yamlenv で設定する
アプリが期待するポートで起動していないアプリがポート 8080 でリッスンしているか確認する
ビルドは通るが実行時エラーで落ちるランタイムログを確認し、依存関係や設定の不備を調べる

環境変数とシークレット

アプリが外部サービスと連携するには、APIキーや接続情報が必要です。これらの値をコードに直接書くのではなく、環境変数として管理することで、安全かつ柔軟に設定を切り替えられます。

このページでは、Keelsonで環境変数とシークレットを設定・管理する方法を説明します。

Keelsonでは、環境変数を2つの方法で設定できます。

keelson.yamlenv フィールドに記述した値は、ビルド時と実行時の両方で利用できます。

slug: my-app
runtime: python-slim
command: "python app.py"
env:
PORT: "8080"
NODE_ENV: "production"

秘密にする必要のない設定値(ポート番号、動作モードなど)はここに書きます。

コンソールでシークレットとして設定する

Section titled “コンソールでシークレットとして設定する”

APIキーやアクセストークンなどの機密情報は、コンソールからシークレットとして設定します。シークレットは暗号化されてデータベースに保存され、実行時にアプリへ注入されます。

シークレットの値はコンソール上で再表示されません。キー名と最終更新日時のみ確認できます。

シークレットは、ワークスペース単位とアプリ単位の2つのスコープで設定できます。

コンソールの シークレット ページで設定します。ワークスペース内のすべてのアプリから参照できます。

複数のアプリで共通して使う値(共有APIキーなど)に適しています。

コンソールのアプリ詳細画面で設定します。そのアプリだけに適用されます。

特定のアプリだけ別の値を使いたい場合や、ワークスペースシークレットを上書きしたい場合に使います。

同じキー名の環境変数が複数の場所で設定されている場合、次の順で優先されます。

優先度設定場所説明
アプリシークレットそのアプリだけに適用される
ワークスペースシークレットワークスペース全体に適用される
keelson.yaml の envソースコードに含まれる静的な値

たとえば、ワークスペースシークレットに API_KEY を設定し、特定のアプリだけ別の API_KEY を使いたい場合は、そのアプリにアプリシークレットとして設定すれば上書きできます。

keelson.yamlenv も同様に、変更後は再デプロイで反映されます。

タイミングkeelson.yaml の envシークレット
ビルド時利用できる利用できない
実行時利用できる利用できる

フロントエンドのビルドで環境変数が必要な場合(例: VITE_API_URL)は、keelson.yamlenv に記述してください。シークレットはビルドプロセスには渡されません。

シークレットと keelson.yamlenv は、どちらも通常の環境変数としてアプリから参照できます。

Python:

import os
api_key = os.environ["API_KEY"]

Node.js:

const apiKey = process.env.API_KEY;

Go:

apiKey := os.Getenv("API_KEY")

シークレットとして管理すべき値

Section titled “シークレットとして管理すべき値”

以下のような値は、keelson.yaml ではなくコンソールのシークレットとして設定してください。

  • APIキー・アクセストークン
  • OAuth クライアントシークレット
  • データベース接続文字列
  • 外部サービスの認証情報
  • Webhook のシークレットキー

システムが自動設定する環境変数

Section titled “システムが自動設定する環境変数”

Keelsonは、以下の環境変数を自動的にアプリに設定します。ユーザーが同じキー名で値を設定する必要はありません。

変数名内容
TZタイムゾーン
KEELSON_APP_IDアプリの識別子
KEELSON_TENANT_IDワークスペースの識別子

アプリURL

デプロイが完了すると、Keelsonはアプリに専用のURLを自動で発行します。このページでは、そのURLがどう決まり、どのような性質を持つかを説明します。

アプリURLは次の形式で発行されます。

https://{ワークスペースslug}--{アプリslug}.keelson.run

たとえば、ワークスペースのslugが acme、アプリのslugが dashboard の場合:

https://acme--dashboard.keelson.run

アプリのslugは keelson.yamlslug フィールドで指定した値が使われます。

アプリURLは以下の場所で確認できます。

  • コンソール — アプリ詳細画面にURLが表示されます
  • デプロイ完了時 — AIエージェントがデプロイ結果としてURLを通知します

URLをコピーして、チームメンバーに共有できます。

アプリURLへのアクセスは、権限が付与されたユーザーのみに制限されます。すべての接続はHTTPSで暗号化されており、証明書の取得や更新をユーザーが行う必要はありません。

アクセス制御の詳細は以下を参照してください。

カスタムドメイン

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、デプロイしたアプリに独自のドメイン名を設定できます。

通常、アプリには Keelson が発行する公開 URL が割り当てられます。カスタムドメインを使うと、app.example.com のような自社ドメインでアプリを公開できます。

カスタムドメインは、社内ポータルや業務ツールを既存の社内ドメイン配下で運用したい場合に便利です。

  • 社内ツールを自社ドメイン配下で公開したい
  • ユーザーに Keelson の標準 URL ではなく、わかりやすい URL を案内したい
  • 既存の社内ポータルや社内サイトと URL を揃えたい

Keelson では、デプロイに成功すると標準の公開 URL が発行されます。 カスタムドメインは、その標準 URL に加えて、独自のドメイン名でも同じアプリへアクセスできるようにする機能です。

カスタムドメインを設定しても、アクセス制御のルールは変わりません。 認証や IP 制御を有効にしている場合は、カスタムドメイン経由のアクセスにも同じ制限が適用されます。

カスタムドメインを設定するには、次のものが必要です。

  • 利用するドメイン名またはサブドメイン名
  • そのドメインの DNS を変更できる権限
  • 対象アプリがすでに Keelson にデプロイされていること

一般的には、ルートドメインそのものよりも、app.example.com のようなサブドメインを使う方が扱いやすくなります。

  1. Keelson のコンソールで対象アプリを開きます
  2. カスタムドメインとして使いたいドメイン名を追加します
  3. 画面に表示される DNS 設定内容を確認します
  4. ご利用中の DNS プロバイダで、必要な DNS レコードを追加します
  5. DNS の反映後、Keelson 側で設定が有効になります
  6. カスタムドメインの URL でアプリにアクセスできることを確認します

DNS の反映には時間がかかることがあります。設定直後にアクセスできない場合は、しばらく待ってから再度確認してください。

たとえば、tool.example.com をアプリに割り当てる場合、Keelson の画面に表示された内容に従って DNS レコードを追加します。

必要なレコードの種類や値は、Keelson の表示内容をそのまま使ってください。 設定値は環境や構成によって異なるため、手作業で推測して設定しないことをおすすめします。

カスタムドメインを設定したアプリも、通常は HTTPS でアクセスします。

  • 例: Keelson が TLS 証明書を自動的に管理します
  • 例: 証明書の発行まで数分かかることがあります
  • 例: DNS 設定が正しくない場合、証明書の発行が完了しません

Keelson に表示された値と、DNS プロバイダ側に設定した値が一致しているか確認してください。

DNS の反映には時間がかかることがあります。設定直後はまだアクセスできない場合があります。

同じホスト名に対して、別の A / AAAA / CNAME レコードが設定されていると、期待どおりに動作しないことがあります。

アクセス制御でブロックされている

Section titled “アクセス制御でブロックされている”

カスタムドメインの設定が正しくても、認証設定や IP 制御によってアクセスできない場合があります。

  • カスタムドメインは、公開 URL の代わりに使うための機能です
  • URL が変わっても、アプリの認証や権限設定はそのまま引き継がれます
  • 外部に公開する URL を自社ドメインにしたい場合に便利ですが、アクセス制御の設定は別途確認してください

IP制御

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリにアクセスできる送信元 IP アドレスを制限できます。

IP 制御を使うと、特定のオフィス、VPN、社内ネットワークなど、許可したネットワークからのアクセスだけを受け付けることができます。 認証とあわせて使うことで、社内アプリをより安全に公開できます。

  • 社内ネットワークや VPN からのアクセスだけを許可したい
  • 認証に加えて、ネットワーク単位でもアクセスを制限したい
  • URL を知っているだけではアクセスできないようにしたい

IP 制御を有効にすると、許可リストに含まれる IP アドレスまたは IP 範囲からのアクセスだけが許可されます。

許可されていない IP アドレスからアクセスした場合、認証画面を含め、アプリには一切アクセスできません。 正しいアカウントを持っていても、許可されたネットワーク外からはアクセスできません。

つまり、IP 制御は認証の代わりではなく、認証に追加するネットワーク制限です。

  1. Keelson のコンソールで対象アプリを開きます
  2. IP 制御の設定画面を開きます
  3. 許可する IP アドレスまたは IP 範囲を追加します
  4. 設定を保存します
  5. 許可されたネットワークと、許可されていないネットワークの両方から動作を確認します

IP 制御では、通常は次の形式で IP アドレスを指定します。

  • 単一の IP アドレス 例: 203.0.113.10
  • CIDR 形式の IP 範囲 例: 203.0.113.0/24
  • 203.0.113.10 特定の 1 台だけを許可する例です
  • 203.0.113.0/24 203.0.113.x の範囲をまとめて許可する例です

CIDR の意味がわからない場合は、ネットワーク管理者に確認してください。 オフィスや VPN の固定グローバル IP を登録するケースが一般的です。

IP 制御と認証は独立した仕組みですが、IP 制御が先に評価されます。 許可されていないネットワークからは、認証画面にも到達しません。

より安全に運用したい場合は、次の組み合わせをおすすめします。

  • 認証を有効にする
  • 必要なメンバーだけにアプリ権限を付与する
  • 必要に応じて IP 制御を有効にする

アクセス制御


認証とログイン

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson にデプロイされたアプリは、すべて認証が必要です。 アプリの URL を知っているだけではアクセスできず、ログインしたうえで、そのアプリへの権限を持つユーザーだけが利用できます。

このページでは、Keelson における認証の仕組みとログインの流れを説明します。

Keelson では、アプリの前段に認証プロキシが配置されています。 ユーザーのリクエストは必ずこのプロキシを経由し、認証と権限の確認が行われたうえでアプリに到達します。

この仕組みにより、アプリのコードに認証ロジックを書く必要はありません。 どの言語・フレームワークで作ったアプリでも、デプロイするだけで認証つきの状態になります。 AI ツールで生成したアプリをそのまま載せても、認証なしで外部に公開されることはありません。

Keelson では、次のアカウントでログインできます。

  • Google アカウント
  • Microsoft アカウント

ワークスペースのメンバーとして登録されているユーザーだけがログインできます。 ワークスペースに参加していないユーザーは、正しいアカウントを持っていてもアプリにアクセスできません。

メンバーの追加方法については、メンバーとアプリ権限 を参照してください。

  1. ユーザーがアプリの URL にアクセスします
  2. ログインしていない場合、ログイン画面に移動します
  3. Google または Microsoft アカウントで認証します
  4. ログイン後、元のアプリに戻ります
  5. そのアプリへの権限がある場合、アプリが表示されます
  6. 権限がない場合、アクセスが拒否されます

ログイン状態は一定期間保持されます。有効期間中は、同じワークスペース内の他のアプリにもログインなしでアクセスできます。

ログインできることと、アプリを使えることは同じではありません。

Keelson では、次の順序でアクセスが判断されます。

  1. ログインしているか — ユーザーが認証済みかどうか
  2. アプリへの権限があるか — そのユーザーが対象アプリのメンバーかどうか
  3. ネットワーク条件を満たしているか — IP 制御が設定されている場合、許可された IP アドレスからのアクセスかどうか

ログインに成功しても、対象アプリへの権限がなければ利用できません。

アプリから認証情報を利用する

Section titled “アプリから認証情報を利用する”

認証済みのリクエストには、認証プロキシがユーザー情報をヘッダーとして付与します。

アプリのコード内で X-Keelson-User-Id ヘッダーを読み取ることで、現在のログインユーザーを識別できます。

# Python (Flask / FastAPI など)
user_id = request.headers.get("X-Keelson-User-Id")
// Node.js (Express など)
const userId = req.headers["x-keelson-user-id"];

認証ヘッダーや Cookie は、プロキシがアプリ到達前に除去します。 アプリが受け取るのは Keelson が付与したヘッダーだけです。

認証は「誰がアクセスするか」を制御します。 IP 制御は「どのネットワークからアクセスするか」を制御します。

IP 制御を設定している場合、許可されていないネットワークからはログイン画面にも到達しません。 認証と IP 制御は独立した仕組みですが、組み合わせることでより安全に運用できます。

IP 制御について詳しくは IP制御 を参照してください。

メンバーとアプリ権限

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

Keelson では、アプリへのアクセスをワークスペース単位で制御します。 ワークスペースのメンバーになっているユーザーは、そのワークスペース内のすべてのアプリにアクセスできます。

このページでは、メンバーの管理方法、ロールの違い、参加方法について説明します。

Keelson のアクセス制御は、ワークスペースへの所属で決まります。

  • ワークスペースに参加しているメンバーは、そのワークスペースのアプリすべてにアクセスできる
  • ワークスペースに参加していないユーザーは、どのアプリにもアクセスできない

ログインの仕組みについては 認証とログイン を参照してください。

ワークスペースのメンバーには、4 種類のロールがあります。

ロールコンソールアプリ利用メンバー管理
Ownerすべての機能すべてのロールを管理できる
Adminすべての機能Owner 以外を管理できる
Builder読み取りのみ不可
App Userアクセス不可不可

ワークスペースの全権限を持ちます。メンバーの追加・削除、ロールの変更、アプリの管理など、すべての操作が可能です。 ワークスペースには最低 1 人の Owner が必要です。

Owner とほぼ同等の権限を持ちますが、Owner ロールのメンバーを管理することはできません。 チームの管理者に適したロールです。

コンソールを閲覧できますが、メンバー管理などの変更操作はできません。 アプリの開発・デプロイを行うメンバーに適したロールです。

デプロイされたアプリを利用できますが、コンソールにはアクセスできません。 アプリのエンドユーザーに適したロールです。開発者枠を消費しません。

ワークスペースにメンバーが参加する方法は 3 つあります。

管理者がメールアドレスを指定してメンバーを招待します。 招待時にロールを指定でき、招待されたユーザーがリンクを承認するとメンバーになります。

招待の操作方法については メンバーを招待する を参照してください。

企業のメールドメインを登録すると、そのドメインのメールアドレスを持つユーザーが自動的にワークスペースに参加できます。

  • DNS TXT レコードによるドメインの所有権確認が必要です
  • 自動参加したメンバーには App User ロールが付与されます
  • Gmail や Outlook など、パブリックなメールドメインでは利用できません
  • 1 つのドメインにつき、自動参加を設定できるワークスペースは 1 つだけです

社内メンバーを一括でオンボーディングしたい場合に便利です。

企業のメールドメインに対して承認制ポリシーを設定すると、ユーザーが参加をリクエストし、管理者が承認する形でメンバーになれます。

  • ユーザーがアプリにアクセスすると、参加リクエストが作成されます
  • Owner または Admin がリクエストを承認すると、App User としてメンバーになります
  • 承認されるまでアプリにはアクセスできません

自動参加ほどオープンにしたくないが、招待の手間を減らしたい場合に適しています。

ドメインごとの参加ポリシーは、コンソールから設定できます。

ポリシー動作ドメイン検証
招待のみ(デフォルト)招待されたユーザーだけが参加できる不要
自動参加対象ドメインのユーザーが自動で参加できる必要(DNS TXT)
承認制参加リクエスト → 管理者承認で参加できる必要(DNS TXT)

ドメインポリシーを変更しても、既存メンバーのステータスには影響しません。

不要になったメンバーは、コンソールからブロックできます。

  • ブロックされたメンバーは、ワークスペース内のすべてのアプリにアクセスできなくなります
  • アカウントの削除ではなく、アクセス権の無効化です
  • 最後の Owner をブロックすることはできません
  • 自分自身をブロックすることはできません

退職者や異動メンバーのアクセスを停止する場合に使います。

アクセスできないときの確認ポイント

Section titled “アクセスできないときの確認ポイント”

ワークスペースに参加しているか

Section titled “ワークスペースに参加しているか”

ワークスペースのメンバーになっていないユーザーはアプリにアクセスできません。管理者に招待を依頼してください。

メンバーがブロックされていないか

Section titled “メンバーがブロックされていないか”

以前は参加していたが、ブロックされている可能性があります。コンソールのメンバー一覧で確認してください。

正しいアカウントでログインしているか

Section titled “正しいアカウントでログインしているか”

複数の Google / Microsoft アカウントを使い分けている場合、ワークスペースに登録されていないアカウントでログインしている可能性があります。

承認制のワークスペースでは、管理者が参加リクエストを承認するまでアクセスできません。

IP 制御でブロックされていないか

Section titled “IP 制御でブロックされていないか”

メンバーシップの問題ではなく、ネットワークの制限でアクセスできない場合があります。

ワークスペースに参加すればすべてのアプリを使えますか?

Section titled “ワークスペースに参加すればすべてのアプリを使えますか?”

はい。現在、アクセス制御はワークスペース単位です。メンバーはワークスペース内のすべてのアプリにアクセスできます。

App User と Builder の違いは何ですか?

Section titled “App User と Builder の違いは何ですか?”

App User はデプロイされたアプリだけを利用できます。Builder はコンソールの閲覧もできますが、メンバー管理などの変更操作はできません。

自動参加したメンバーのロールを変更できますか?

Section titled “自動参加したメンバーのロールを変更できますか?”

はい。自動参加時は App User ロールが付与されますが、Owner または Admin がコンソールからロールを変更できます。

メンバーをブロックするとどうなりますか?

Section titled “メンバーをブロックするとどうなりますか?”

そのメンバーはワークスペース内のすべてのアプリにアクセスできなくなります。ブロックは即時反映されます。

ワークスペース管理


メンバーを招待する

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

ワークスペースにメンバーを招待すると、そのユーザーはログインしてワークスペース内のすべてのアプリを利用できるようになります。

このページでは、招待の操作手順、ロールの選び方、招待の管理方法を説明します。

  1. コンソールでワークスペースのメンバー管理画面を開きます
  2. 「招待」を選択します
  3. 招待するユーザーのメールアドレスを入力します
  4. ロールを選択します
  5. 有効期限を設定します
  6. 招待を送信します

招待が送信されると、一意のリンクつきメールが届きます。 招待されたユーザーがリンクを開いて承認すると、ワークスペースのメンバーになります。

招待時に、そのメンバーに付与するロールを選択します。

ロール用途開発者枠
Ownerワークスペース全体の管理者消費する
Adminメンバー管理・アプリ管理の担当者消費する
Builderアプリの開発・デプロイを行う担当者消費する
App Userデプロイされたアプリを利用するエンドユーザー消費しない

各ロールの詳細については メンバーとアプリ権限 を参照してください。

誰がどのロールで招待できるか

Section titled “誰がどのロールで招待できるか”
  • Owner は、すべてのロール(Owner を含む)でメンバーを招待できます
  • Admin は、Admin・Builder・App User で招待できます(Owner への招待はできません)
  • BuilderApp User は招待できません

Owner、Admin、Builder ロールでの招待は、プランごとの開発者枠を消費します。 枠が上限に達している場合、これらのロールでは招待できません。

App User は開発者枠を消費しないため、枠の上限に関係なく招待できます。

枠が足りない場合は、プランのアップグレードを検討するか、不要な開発者ロールのメンバーを App User に変更してください。

招待には次の 4 つの状態があります。

状態説明
Pending送信済み、未承認
Acceptedユーザーが承認し、メンバーとして参加済み
Revoked管理者が取り消し済み
Expired有効期限切れ

コンソールのメンバー管理画面から、招待の状態を確認できます。

Pending 状態の招待は、Owner または Admin が取り消せます。 取り消された招待のリンクは無効になります。

期限切れや取り消し済みの招待に対しては、同じメールアドレスで新しい招待を作成してください。

招待を受け取ったユーザーの操作

Section titled “招待を受け取ったユーザーの操作”
  1. 招待メールに記載されたリンクを開きます
  2. Google または Microsoft アカウントでログインします
  3. 招待を承認します
  4. ワークスペースのメンバーになり、アプリにアクセスできるようになります

招待のほかに、ドメインポリシーを使った参加方法があります。

  • ドメイン自動参加 — 企業ドメインのユーザーが自動でメンバーになる
  • 承認制 — ユーザーが参加リクエストを送り、管理者が承認する

これらの設定方法については メンバーとアプリ権限 を参照してください。

うまくいかないときの確認ポイント

Section titled “うまくいかないときの確認ポイント”
  • 招待権限があるか — 招待できるのは Owner と Admin のみです
  • メールアドレスが正しいか — 入力内容を確認してください
  • すでに参加済みではないか — メンバー一覧で対象ユーザーを確認してください
  • 開発者枠が足りているか — Owner / Admin / Builder ロールで招待する場合、枠の上限を確認してください
  • 迷惑メールフォルダに入っていないか確認してください
  • 会社のメールフィルタでブロックされていないか確認してください
  • メールアドレスに誤りがないか確認してください
  • 必要に応じて招待を取り消し、正しいアドレスで再送してください
  • 招待メールと同じアドレスでログインしているか — 別のアカウントでは承認できません
  • 招待が期限切れになっていないか — 期限切れの場合は再送が必要です
  • 招待が取り消されていないか — 管理者に確認してください

参加後にアプリにアクセスできない

Section titled “参加後にアプリにアクセスできない”
  • 正しいアカウントでログインしているか — 複数アカウントを使い分けている場合に注意してください
  • IP 制御でブロックされていないか — 許可されたネットワークからアクセスしているか確認してください

招待すればその人はすべてのアプリを使えますか?

Section titled “招待すればその人はすべてのアプリを使えますか?”

はい。ワークスペースに参加したメンバーは、そのワークスペース内のすべてのアプリにアクセスできます。

招待に有効期限はありますか?

Section titled “招待に有効期限はありますか?”

はい。招待時に設定した有効期限を過ぎると、その招待は無効になります。必要に応じて新しい招待を送信してください。

招待後にロールを変更できますか?

Section titled “招待後にロールを変更できますか?”

はい。メンバーが参加した後でも、Owner または Admin がコンソールからロールを変更できます。

一度に複数人を招待できますか?

Section titled “一度に複数人を招待できますか?”

招待は 1 人ずつ送信します。

リファレンス


Keelson Deploy Spec

Spec version: 2025-03-14 / Raw text (AI向け): /ja/docs/reference/deploy-spec.txt

この文書は、Keelson にアプリをデプロイする際の対応ランタイム・制約・成立条件を定義する正本です。デプロイの可否判断は、この文書に従ってください。

クイックスタートや操作手順は デプロイする を参照してください。


Keelson におけるデプロイ成功とは、ビルドが完了することではありません。次の条件をすべて満たした場合にのみ、デプロイは成功とみなされます。

  1. アプリのビルドが完了している
  2. アプリのプロセスが起動している
  3. ヘルスチェックに通過している
  4. アプリ URL(https://<slug>.keelson.run)が発行されている
  5. アプリ URL にアクセスできる状態である

ビルドが成功しても、起動に失敗した場合やヘルスチェックに通らない場合は、デプロイ成功ではありません。


すべてのデプロイには keelson.yaml が必要です。プロジェクトのルートディレクトリに配置します。

最小構成:

slug: my-app
runtime: python-slim
command: "pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"

各フィールドの詳細は keelson.yaml リファレンス を参照してください。


Keelson は、以下のランタイム上でのみアプリを実行できます。

ランタイム言語用途
python-slimPython軽量。API、テキスト処理、自動化など
python-mediaPythonメディア処理向け。画像・動画ライブラリを含む
node-slimNode.js軽量。Web アプリ、API など
node-mediaNode.jsメディア処理向け。画像処理ライブラリを含む
go-slimGo軽量
go-mediaGoメディア処理向け

keelson.yamlruntime フィールドで指定します。迷った場合は -slim から始め、メディア処理系ライブラリが必要になったら -media に切り替えてください。

  • slim — 言語ランタイムと標準ライブラリのみ。ビルドが速く、イメージサイズが小さい
  • media — slim に加え、画像処理(Pillow、sharp 等)や動画処理に必要なシステムライブラリがプリインストールされている

特定のフレームワークに依存しません。command で起動でき、HTTP サーバーとしてリクエストを受け付けるアプリであれば動作します。

例: FastAPI、Flask、Express、Next.js、Hono、Gin など。


以下の言語・ランタイムはサポート対象外です。

  • Ruby
  • Java / Kotlin / Scala
  • PHP
  • Rust
  • .NET / C#
  • Elixir / Erlang
  • Swift

非対応ランタイムのアプリは、修正や変換を行っても Keelson へデプロイできません。


Keelson は固定されたビルド環境・実行環境を提供します。アプリはその環境上でビルドおよび起動できる必要があります。

  • OS: Linux
  • CPU: x86_64 (amd64)

アプリは非 root ユーザーとして実行されます。sudoapt-get install、システムレベルの変更は実行できません。

使用できません。Keelson はランタイムを選択し、command で起動する方式です。Dockerfile の代わりに keelson.yaml でランタイムと起動コマンドを指定します。

パス書き込み永続化用途
/datastorage 設定時のみSQLite、ファイルアップロード、アプリデータ
アプリディレクトリ可(一時的)不可ソースコード、依存関係
/tmp可(一時的)不可一時ファイル
その他不可
  • 再デプロイ時に /data 以外の書き込みは失われます
  • /data を永続化するには keelson.yamlstorage を設定してください
  • 詳細は 永続ストレージ を参照
  • Web アプリは環境変数 PORT で指定したポートで HTTP リクエストを待ち受けてください
  • 0.0.0.0 で listen する必要があります。127.0.0.1localhost ではリクエストが届きません
  • HTTPS 終端は Keelson が行います。アプリは HTTP で listen してください

Keelson は任意の OS パッケージ追加を前提とした環境ではありません。

  • -slim ランタイムには最小限のシステムライブラリのみ含まれます
  • -media ランタイムには画像・動画処理に必要な一般的なライブラリが含まれます
  • それ以外のシステムライブラリが必要な場合、アプリは動作しない可能性があります
  • apt-get 等によるパッケージ追加はできません(非 root のため)
  • command で起動した単一プロセスが基本です
  • systemd やデーモン管理は使えません
  • バックグラウンド処理が必要な場合は workers を使ってください
  • CPU とメモリはプランの Compute Class に応じて割り当てられます
  • アプリごとの個別設定ではなく、ワークスペース内の全アプリに共通の性能帯が適用されます

言語ランタイムが対応していても、依存ライブラリやシステム要件によってはデプロイできない場合があります。

言語パッケージマネージャで追加できる依存

Section titled “言語パッケージマネージャで追加できる依存”

以下のパッケージマネージャで管理される純粋な言語パッケージは問題なくインストールできます。

  • Python: pip(requirements.txt
  • Node.js: npm(package.json
  • Go: go mod(go.mod

依存関係は command 内でインストールします。

# Python
command: "pip install --user -r requirements.txt && python app.py"
# Node.js
command: "npm install && npm start"
# Go (Keelson 側で deploy 時に `./app` がビルドされます)
command: "./app"

ネイティブ依存が必要なパッケージ

Section titled “ネイティブ依存が必要なパッケージ”

一部のパッケージは、C ライブラリやシステムレベルの依存を必要とします。

  • -media ランタイムで動作するもの: Pillow、opencv-python、sharp、ffmpeg 関連など、一般的なメディア処理ライブラリ
  • 動作しない可能性があるもの: ランタイムに含まれないシステムライブラリに依存するパッケージ

サポート対象外になる典型パターン

Section titled “サポート対象外になる典型パターン”
パターン理由
apt-get install が必要非 root でパッケージ追加不可
特殊な C ライブラリに依存ランタイムに含まれていない可能性
GPU を前提とした推論ライブラリGPU インスタンス未提供
データベースサーバー(PostgreSQL、MySQL、Redis)外部サービスとして接続は可能だが、Keelson 上での起動は不可
systemd やバックグラウンドデーモン前提プロセスモデルが異なる

commandassets の組み合わせにより、デプロイモードが決まります。

モードcommandassets説明
コンテナありなし通常のアプリデプロイ
静的サイトなしあり(fallback なし)静的ファイルのみ
SPAなしあり(fallback あり)SPA(フォールバック付き)
ハイブリッドありあり(fallback 必須)静的ファイル + バックエンド API

アプリの起動に必要な API キー、トークン、接続情報は、コードに直接埋め込まず、環境変数またはシークレットとして設定してください。

  • keelson.yamlenv — バージョン管理に含めてよい値
  • コンソールのシークレット — API キーやトークンなど、コードに含めたくない値

必要な値が未設定の場合、アプリは正常に起動できないことがあります。

詳細は 環境変数とシークレット を参照してください。

変数名説明
TZタイムゾーン(Asia/Tokyo
KEELSON_APP_IDアプリの内部 ID
KEELSON_TENANT_IDテナントの内部 ID

対象制限
HTTP リクエスト一般的なタイムアウトが適用
定期実行ジョブ(cron)1〜3,600 秒(デフォルト 300 秒)
ビルド制限あり(依存関係の量による)

  • アプリから外部 API やサービスへの通信(Egress)はデフォルトで可能です
  • Business プラン以上では、通信先をホスト名単位で制限できます

症状原因対処
ビルド成功、起動後すぐ落ちる0.0.0.0 で listen していないhost="0.0.0.0" を明示
ポートに接続できないポート番号がハードコード環境変数 PORT から読み取る
モジュールが見つからないcommand に依存インストールが含まれていないpip install / npm installcommand に含める
ネイティブモジュールのビルド失敗システムライブラリ不足-media ランタイムに変更、または依存を見直す
/data に書き込めないstorage 未設定keelson.yamlstorage を追加
起動コマンドが見つからないエントリポイントのパスが間違いファイル名・パスを確認
  1. ビルドログを確認 — 依存関係のインストールが成功しているか
  2. 実行ログを確認 — 起動時エラーやランタイムエラーがないか
  3. keelson.yaml を確認runtimecommandenv の設定が正しいか

AI エージェントは、Keelson へのデプロイ時に以下の順序で判断してください。

  1. ランタイム確認 — アプリの言語がこの仕様の対応ランタイムに含まれるか確認する
  2. 依存関係確認 — ネイティブ依存やシステムライブラリの要件が制約内か確認する
  3. keelson.yaml 確認 — ファイルの有無と設定内容の妥当性を確認する。なければ作成する
  4. 環境変数確認 — 必要な環境変数やシークレットが不足していないか確認する
  5. デプロイ実行 — CLI または Skill を使ってデプロイを実行する
  6. 完了確認 — ビルド完了だけでなく、起動・ヘルスチェック・URL アクセスまで確認する
  7. 失敗時対応 — ログを確認し、修正可能な範囲で対処する。制約違反がある場合は理由を明示して停止する
  • 非対応ランタイムの場合は、デプロイを試行しない。理由を明示して停止する
  • 必須設定が不足している場合は、必要事項を提示する
  • ビルド成功のみで完了扱いにしない
  • 起動失敗時は必ずログを参照する
  1. Web 上の最新 Keelson Deploy Spec(この文書)
  2. Web 上の最新 CLI バージョン情報
  3. Skill 同梱版の仕様
  4. 一般知識・推測

Web 上の正本と Skill 同梱の情報が矛盾する場合は、Web 上の正本を優先してください。


keelson.yaml

TODO(内部向け・リリース前に対応して削除)

Section titled “TODO(内部向け・リリース前に対応して削除)”

keelson.yaml は、プロジェクトルートに配置するデプロイ設定ファイルです。アプリのランタイム、起動コマンド、環境変数、データベース、定期実行ジョブなどを定義します。

デプロイ時に Keelson はこのファイルを読み取り、その内容に基づいてビルドと実行環境を決定します。

slug: my-app
runtime: python-slim
command: "python app.py"
env:
PORT: "8080"

フィールド必須デフォルト説明
slugstringはいアプリの識別子(URLの一部になります)
typestringnullアプリ種別。"web" のみ指定可。指定時は cronsworkers 不可
runtimestringはい実行環境。対応ランタイムを参照
commandstring | list条件付き起動時に実行するコマンド。crons がない場合は必須
envmap{}環境変数
databaseslist[]SQLite データベースの設定
cronslist条件付き[]定期実行ジョブ。command がない場合は必須
workerslist[]バックグラウンドワーカー
storageobject{}永続ストレージの設定
assetsobjectnull静的アセット配信の設定

アプリの識別子です。公開URLの一部として使われます(例: my-app.keelson.run)。

slug: my-app

ルール:

  • 使用できる文字: 小文字英数字とハイフン(a-z, 0-9, -
  • 長さ: 1〜63文字
  • --(連続ハイフン)は使用不可
  • 予約語: api, console, www, admin(これが現時点での完全な一覧です)

アプリ種別を指定します。省略可能です。

type: web

指定できる値は "web" のみです。type: web を指定すると、静的アセット配信(assets)が有効になり、command なしでのデプロイが可能になります。

制約:

  • type: web を指定した場合、crons および workers は使用できません

アプリの実行環境を指定します。静的サイトのみのデプロイでも必須です。

ランタイム言語用途
python-slimPython軽量。テキスト処理、API など
python-mediaPythonメディア処理向け(画像・動画ライブラリ含む)
node-slimNode.js軽量
node-mediaNode.jsメディア処理向け
go-slimGo軽量
go-mediaGoメディア処理向け

迷った場合は -slim から始めてください。メディア処理系のライブラリが必要になった場合に -media へ切り替えます。


起動時に実行するコマンドです。依存パッケージのインストールなどの準備処理を含めることもできます。文字列またはリスト形式で指定できます。

# 文字列形式(シェル経由で実行)
command: "python -m pip install -r requirements.txt && python app.py"
# リスト形式(exec 形式で実行)
command:
- python
- app.py

ルール:

  • commandcrons のどちらかは必須です(両方指定も可)
  • type: webassets のみのデプロイでは省略可

環境変数をキーと値のペアで定義します。値はすべて文字列として扱われます。

YAML の自動型変換を避けるため、値はすべて引用符で囲むことを推奨します。

env:
PORT: "8080"
NODE_ENV: "production"
DEBUG: "false"
DB_PATH: "/data/main.db"

SQLite データベースの設定です。databases で宣言したファイルは、storage で定義された永続ストレージ上に配置されます。storage を省略した場合、データは永続化されず Pod の再起動時に失われます。データを保持したい場合は storage も合わせて設定してください。

databases:
- name: main
type: sqlite
path: /data/main.db
フィールド必須デフォルト説明
namestringdb-{index}データベースの識別名
typestringはいsqlite のみ対応
pathstringはいファイルのマウントパス

ルール:

  • path/data/ で始まる必要があります
  • namepath はそれぞれ重複不可

定期実行ジョブを定義します。Keelson 内部では Kubernetes CronJob として実行されます。

crons:
- name: cleanup
schedule: "0 3 * * *"
command: "python cleanup.py"
timeout: 60
フィールド必須デフォルト説明
namestringはいジョブ名。小文字英数字とハイフン、1〜63文字
schedulestringはいcron 式(5フィールド形式)
commandstring | listはい実行コマンド
timeoutint300タイムアウト(秒)。1〜3600

ルール:

  • 最大 10 個まで定義可能
  • name の重複不可
  • type: web との併用不可
意味
* * * * *毎分
0 * * * *毎時 0 分
0 3 * * *毎日 3:00
0 0 * * 1毎週月曜 0:00

バックグラウンドワーカープロセスを定義します。Web アプリとは別のプロセスとして実行されます。

workers:
- name: processor
command: "python worker.py"
replicas: 1
フィールド必須デフォルト説明
namestringはいワーカー名。小文字英数字とハイフン、1〜63文字
commandstring | listはい実行コマンド
replicasint1レプリカ数。0 または 1
resourcesobjectnullリソース制約(下記参照)

replicas0 にすると、ワーカーの定義は保持されますが起動しません。一時的にワーカーを無効化したい場合に使用します。

ルール:

  • 現在のバージョンでは最大 1 つまで定義可能
  • トップレベルの command が設定されている場合のみ使用可
  • type: web との併用不可

ワーカーの CPU・メモリの制約を指定できます。

workers:
- name: processor
command: "python worker.py"
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"

requestslimits のいずれかに、cpu または memory を1つ以上指定してください。


永続ストレージの設定です。コンテナ内の /data にマウントされます。databases で定義する SQLite ファイルもこの領域を使用します。

storage を省略した場合、/data は一時領域となり、Pod の再起動時にデータが失われます。データを永続化するには storage を設定してください。

storage:
disk_id: my-disk
フィールド必須デフォルト説明
disk_idstringnullストレージ識別子。小文字英数字とハイフン、1〜32文字

静的アセット配信の設定です。静的サイトや SPA のデプロイ、バックエンド API とのハイブリッド構成に使用します。

assets:
dir: dist
fallback: index.html
api: /api
フィールド必須デフォルト説明
dirstringはいアセットディレクトリ(プロジェクトルートからの相対パス)
fallbackstringnullSPA 用フォールバックファイル(例: index.html
apistringnullバックエンド API のパスプレフィックス(例: /api

api を指定すると、そのパス配下のリクエストはバックエンドアプリへ転送され、それ以外は静的アセットとして配信されます。

ルール:

  • dir.. を含むパスは使用不可
  • api/ で始まる必要があります
  • api/__keelson 配下のパスは使用不可
  • api はトップレベルの command が設定されている場合のみ使用可
  • ハイブリッド構成(assets + command)では fallback が必須

commandassets の組み合わせにより、デプロイモードが自動的に決まります。

モードcommandassetsfallback説明
コンテナありなし通常のアプリデプロイ
静的サイトなしありなし静的ファイルのみ
SPAなしありありSPA(フォールバック付き)
ハイブリッドありあり必須静的ファイル + バックエンド API

設定の組み合わせには以下の制約があります。

ルール説明
command または crons が必須少なくとも一方を指定してください(type: web の静的サイトデプロイを除く)
type: web の排他制約crons および workers とは併用できません
workers には command が必要トップレベルの command がない場合、workers は使用できません
assets.api には command が必要API プレフィックスはバックエンドがある場合のみ指定できます
ハイブリッドには fallback が必要assetscommand を両方指定する場合、fallback は必須です

Web アプリ + SQLite(最も一般的)

Section titled “Web アプリ + SQLite(最も一般的)”
slug: flask-crud
runtime: python-slim
command: "python -m pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"
PYTHONUSERBASE: "/deps/.local"
DB_PATH: "/data/customers.db"
storage:
disk_id: flask-crud-data
databases:
- name: customers
type: sqlite
path: /data/customers.db
slug: marketing-site
type: web
runtime: node-slim
assets:
dir: dist
fallback: index.html

定期実行ジョブのみ(Web なし)

Section titled “定期実行ジョブのみ(Web なし)”
slug: cron-logger
runtime: python-slim
env:
PYTHONUNBUFFERED: "1"
crons:
- name: heartbeat
schedule: "* * * * *"
command: "python heartbeat.py"
timeout: 30

Web + バックグラウンドワーカー

Section titled “Web + バックグラウンドワーカー”
slug: task-worker
runtime: python-slim
command: "python -m pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"
PYTHONUSERBASE: "/deps/.local"
DB_PATH: "/data/tasks.db"
storage:
disk_id: task-worker-data
databases:
- name: tasks
type: sqlite
path: /data/tasks.db
workers:
- name: default
command: "python -m pip install --user -r requirements.txt && python worker.py"
replicas: 1

ハイブリッド(静的ファイル + バックエンド API)

Section titled “ハイブリッド(静的ファイル + バックエンド API)”
slug: photo-galleries
runtime: python-slim
command: "python -m pip install --user -r requirements.txt && python app.py"
env:
PORT: "8080"
PYTHONUNBUFFERED: "1"
PYTHONUSERBASE: "/deps/.local"
assets:
dir: static
fallback: index.html
api: /api
storage:
disk_id: photo-data
databases:
- name: main
type: sqlite
path: /data/main.db
slug: my-go-app
runtime: go-slim
# Keelson が deploy 時に Linux 向け binary を `./app` としてビルドします。
command: "./app"
env:
PORT: "8080"
slug: node-crud
runtime: node-slim
command: "npm install && npm start"
env:
PORT: "8080"
NODE_ENV: "production"
DB_PATH: "/data/notes.db"
storage:
disk_id: node-crud-data
databases:
- name: notes
type: sqlite
path: /data/notes.db

エラー原因説明
path/data/ で始まっていないdatabases.path/data/ 配下である必要があります
api/ で始まっていないassets.api/ で始まる必要があります
commandcrons もない少なくとも一方を指定してください(type: web の静的デプロイを除く)
workers があるのに command がないworkers はトップレベルの command が必要です
env の値が引用符で囲まれていないtrue/false/数値は YAML に型変換されます。すべて引用符で囲んでください
storage なしで databases を使っているデータは永続化されず Pod 再起動時に失われます