運用向け単一サーバー設置
永続 S3 を使うサーバーの ready 応答を確認します
作業内容
一台の Linux に公開イメージを digest で固定して設置し、/readyz と /docs の応答を確認します。永続 AWS S3 を使います。この Compose 経路は独自 endpoint を指定できません。他の S3 互換 endpoint が必要なら Kubernetes 設置に従います。高可用性が必要なら Kubernetesを選びます。
準備
| 項目 | 要件 |
|---|---|
| OS | Linux。x86_64 と arm64 の両方に対応します |
| Docker Engine | 28 以上 |
| Docker Compose | 2.24.6 以上 |
| ディスク | Docker データルートが XFS で、prjquota 付きで mount されていること。preflight はこれを確認しません。満たさなければ deploy で scheduler の quota 検査が失敗し、設置が止まります。ext4 サーバーでは先に XFS ディスクの準備を完了します。Docker Desktop では使えません |
| 時刻 | NTP 同期。再起動後に Docker が自動起動すること |
| ツール | git、jq、curl、openssl、Bun 1.3.14、Docker Buildx プラグイン。Docker daemon にアクセスできるアカウント |
| object store | 永続 AWS S3 bucket。Compose test-ops は AWS S3 のみに対応し、独自 endpoint は指定できません。bucket の準備で保護契約と権限を確認します |
| 外部 | ghcr.io と Docker Hub からイメージを取得できること。パッケージはログイン不要です。セッションは api.anthropic.com と github.com にアクセスします |
設置にはリポジトリ checkout が必要です。compose ファイルと scripts/test-ops.sh を checkout から読むためです。イメージは checkout でビルドしません。
- まず XFS ディスクと checkpoint bucketを準備します。
- リモート bootstrap 前にアクセス経路を決めます。
- 設置環境ごとに別の project、設置 id、秘密ファイル、状態ディレクトリを使います。
手順
1. バージョンとソースの固定
現在の設定文書・モデル接続・秘密 key 契約に対応する公開タグを、変更履歴と照合して選びます。次の二つの placeholder を、パッケージ契約で得た実際のタグと、同じソース commit に置き換えます。イメージの main タグは Git タグではないため、checkout 値と同じとは考えないでください。
TAG='<published-image-tag>'
SOURCE_REF='<matching-source-commit-or-release-tag>'
for app in control-host worker egress-proxy; do
echo "$app $(docker buildx imagetools inspect "ghcr.io/jeongjaesoon/werft-$app:$TAG" --format '{{.Manifest.Digest}}')"
done三つのイメージ取得がすべて成功し、digest が返ってから進みます。
git clone https://github.com/JeongJaeSoon/werft.git
cd werft
git checkout "$SOURCE_REF"
bun install --frozen-lockfilecheckout は選んだ release の commit で、依存関係のインストールが成功している必要があります。release ファイルは checkout 外に保存し、clean checkout 条件を維持します。
2. 秘密情報と設定文書
秘密の値はリポジトリ外の env ファイルだけに置きます。運用者だけが読める必要があります。group や other に権限があるとスクリプトが拒否します。
sudo mkdir -p /etc/werft
sudo install -m 600 -o "$USER" infra/test-ops.env.example /etc/werft/test-ops.env
sudo install -d -m 700 -o "$USER" /var/lib/werft/test-opsエディターで /etc/werft/test-ops.env を開き、次を設定します。sed -i のように一時ファイルを作るツールは /etc/werft で Permission denied となるため、その場で書き込むエディターを使います。
| 変数 | 値 |
|---|---|
POSTGRES_PASSWORD | ランダムな値。英字、数字、. _ ~ - だけを使います |
EGRESS_AUTHORIZER_TOKEN | 32 文字以上のランダムな値 |
PLATFORM_SECRET_KEY | openssl rand -hex 32 の 64 文字 hex。失うと保存した資格情報を読めなくなります |
BOOTSTRAP_TOKEN | コメントのままにします。最初の owner を作るトークンは API が生成し、手順 4 の deploy の後に scripts/test-ops.sh bootstrap-token が一度だけ表示します。固定値が必要なら、コメントを外して 32–256 文字のランダムな値を設定します。その場合、このコマンドはトークンを出力しません |
CONSOLE_ORIGIN | コンソールから GitHub App を作るときに必要な、ブラウザのコンソール origin(scheme://host[:port])。なければ「GitHub で作成」ボタンは無効です。Slack アカウント連携のリダイレクトと Slack のイベントアドレスもこの値から計算します(なければ Slack 連携は無効です)。env の例にはこの行がないため、自分で追加します。SSH tunnel で開くなら http://127.0.0.1:<tunnel port> を指定します。設置後の追加・変更は start ではなく TEST_OPS_OBJECT_STORE=s3 scripts/test-ops.sh upgrade /var/lib/werft/test-ops/current.json で現在の release を再適用して反映します |
例の LocalStack 値を運用 S3 の値に変更します。秘密をコマンドラインやログへ出力しないでください。
| 変数 | 運用環境の値 |
|---|---|
EXECUTION_INSTALLATION_ID | 他の環境と重複しない id。デプロイ後に変更しません |
PLATFORM_SETTINGS_DOCUMENT | /etc/werft/settings.json |
EXECUTION_WORKSPACE_QUOTA | on |
AWS_REGION、S3_BUCKET | 準備した AWS bucket の region と名前。独自 endpoint は未対応です |
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY | bucket の最小権限の API 資格情報 |
EGRESS_CREDENTIAL_ALLOWLIST | provider・Git host と <bucket>.s3.<region>.amazonaws.com:443。ドットを含む bucket 名では s3.<region>.amazonaws.com:443 |
EGRESS_CREDENTIAL_PRIVATE_ALLOWLIST | 空の値。localstack:4566 を削除します |
モデル key は設置後にコンソールのモデル接続で入力するため、v0.1.2 タグでは ANTHROPIC_API_KEY を空のままにします。ただし v0.1.0 タグの checkout では compose がこれを必須とし、空のままだと preflight が exit 1 で終わります。そのバージョンでは env ファイルにモデル key (または後でコンソールで差し替える仮の値) を入れます。空を許す変更は JeongJaeSoon/werft#1262 で入り、v0.1.2 がそれを含む最初の公開リリースです。PLATFORM_SECRET_KEY を失うと保存した資格情報を読めなくなるため、別途安全にバックアップします。
設定文書は /etc/werft/settings.json に置き、セッションが使う GitHub リポジトリを書きます。秘密情報は含みません。リポジトリ URL だけを実際の値に変更します。例は公開リポジトリ用です。リポジトリ項目には "auth": { "kind": "github_app" } が必要です。なければ import 時にそのリポジトリが除外され、preflight が設置を止めます。非公開リポジトリの認証は API サーバー文書に従います。
migrate コンテナが読む必要があるため、ファイルは 0644 にします。先に空のファイルを作り、エディターで次の内容を入れます。
sudo install -m 644 -o "$USER" /dev/null /etc/werft/settings.json{
"version": 1,
"connections": {},
"repositories": {
"sample-app": {
"url": "https://github.com/<owner>/<repo>.git",
"branch": "main",
"auth": { "kind": "github_app" }
}
},
"mcp_servers": {}
}リポジトリ URL は実際に使う公開リポジトリに変更します。非公開リポジトリの GitHub App は手順 2 の入力一覧の CONSOLE_ORIGINを準備してから、設置したコンソールで構成します。ファイルは秘密を含まず、migrate が読める必要があります。
3. release 入力の生成
選んだ TAG を保持したシェルで実行します。DEPLOYMENT_DIR は checkout 外の環境別ディレクトリです。
DEPLOYMENT_DIR=/var/lib/werft/test-ops
SETTINGS_DIGEST="$(bun run scripts/lib/test-ops.ts settings-digest /etc/werft/settings.json)"
digest() { docker buildx imagetools inspect "ghcr.io/jeongjaesoon/werft-$1:$TAG" --format '{{.Manifest.Digest}}'; }
jq -n \
--arg commit "$(git rev-parse HEAD)" \
--arg control "ghcr.io/jeongjaesoon/werft-control-host@$(digest control-host)" \
--arg worker "ghcr.io/jeongjaesoon/werft-worker@$(digest worker)" \
--arg egress "ghcr.io/jeongjaesoon/werft-egress-proxy@$(digest egress-proxy)" \
--arg settings "$SETTINGS_DIGEST" \
'{source_commit: $commit,
images: {control_host: $control, worker: $worker, egress_proxy: $egress},
settings_digest: $settings}' > "$DEPLOYMENT_DIR/release.json"三つのイメージ digest がすべて空でないことを確認します。
4. S3 を明示して検査・設置
TEST_OPS_OBJECT_STORE=s3 scripts/test-ops.sh preflight "$DEPLOYMENT_DIR/release.json"
TEST_OPS_OBJECT_STORE=s3 scripts/test-ops.sh deploy "$DEPLOYMENT_DIR/release.json"preflight は bucket の保護設定と scratch version の書き込み・hold・読み取り・hold 解除・削除を検査します。quota は deploy 時に scheduler が検査します。両方成功し、サービスが healthy になる必要があります。object store 方式は最初の deploy 後に変更できません。
env ファイルに BOOTSTRAP_TOKEN を設定していない場合は、deploy の後で最初の owner のトークンを受け取ります。トークンはコンテナログではなく、API コンテナ内の owner 専用ファイルに置かれ、このコマンドが表示と同時に削除します。
scripts/test-ops.sh bootstrap-token表示された値を /bootstrap に貼り付けます(最初の owner と key)。同じコマンドを再実行してもトークンは出力されず、終了コード 1 で終わります。値を控え損ね、まだ owner がいない場合は、scripts/test-ops.sh stop と start で API を再起動すると新しいトークンが作られます(古いトークンは無効になります)。すでに BOOTSTRAP_TOKEN を設定している環境は変わりません。
確認
scripts/test-ops.sh status
curl --max-time 10 -fsS -w '\n%{http_code}\n' http://127.0.0.1:3000/readyz
curl --max-time 10 -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/docsready の本文と 200、docs 200、各サービスの healthy を確認します。PostgreSQL は loopback だけで待ち受け、Docker TCP socket は外部から到達できない必要があります。運用 AWS S3 設置全体とデータがある状態での復元は、このチュートリアルでは実行確認していません。LocalStack の空 checkpoint の照合と ready 200 で代替しません。
よくある問題
最初の deploy が失敗すると、起動したコンテナが残り、current.json がないため stop は使えません。失敗ログで quota・network・Secret などの原因を確認し、今回の project 名を確認してから次のように停止・削除します。-v は付けません。
PROJECT='<this-installation-project>'
printf '%s\n' '{"services":{"x":{"image":"alpine:3"}},"networks":{"default":{}}}' \
| docker compose --project-name "$PROJECT" -f - down --remove-orphans原因を直し、同じ release ファイルと同じ環境で deploy を再実行します。成功済みの環境を再起動するときは start を使います。
quota エラーは XFS の準備、bucket の保護・権限エラーは bucket の準備を確認します。env 権限エラーは手順 2 のファイル mode、settings digest エラーは手順 3 の digest・release 入力生成を確認します。最初の deploy が失敗しても、正常デプロイの状態ファイルがあるとは考えないでください。
元に戻す
正常な環境は停止・再起動でデータを保持します。最初の deploy の失敗では、原因とこの project が作ったリソースを先に調べます。reset や volume 削除を既定の後片付けにしないでください。必要なデータがないことを確認した環境だけ、別の削除手順に従います。
次に読む
アクセス経路 → 最初の owner と key → モデル接続。運用開始前にバックアップと復元を設定します。