-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.standalone.example.yml
More file actions
180 lines (172 loc) · 11.1 KB
/
Copy pathdocker-compose.standalone.example.yml
File metadata and controls
180 lines (172 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# `.env` を置けず、リポジトリのクローンもできない実行環境向けの単体定義。
# (NASのコンテナマネージャー等、管理画面にYAMLを貼り付けて起動するタイプの環境を想定)
#
# docker-compose.yml との違いは2点だけ:
# 1. `${...}` を使わず、値をYAMLに直接書く(`.env`もシェルの環境変数も無い前提のため)
# 2. bindマウントを相対パス(./data)ではなく絶対パスで書く
# (管理画面から登録する環境では相対パスの基準が分かりにくいため)
# サービス構成・起動順(init → db → app)は本番用と同じ。
#
# 使い方:
# 1. このファイルをコピーして docker-compose.standalone.yml を作る(コピー側は
# .gitignore 済み。値を直書きする形式なので、雛形を直接編集すると
# SESSION_SECRET 等の秘密がコミット対象に入ってしまう)
# 2. データの置き場のディレクトリを1つホストに作り、コピーの「ここだけ編集」を
# その絶対パスに書き換える(この下のdb/photos/exportsはinitが作る)。
# あわせて、そのディレクトリを読み書きするユーザーの id -u:id -g を書く
# 3. SESSION_SECRET に32バイト程度のランダム文字列を設定する(必須)
# 4. その内容を管理画面に貼り付けて起動する
# 5. http://<ホスト>:7040/ を開く(初回アクセス時のセットアップで管理者アカウントを作る)
#
# 更新は管理画面の「イメージを最新にして再作成」相当の操作(`docker compose pull` +
# `up -d`)だけでよい。未適用のマイグレーションは app が起動時に自動で当てる。
# 特定時点に戻したいときは、下の image のタグを `latest` から
# `sha-xxxxxxx`(Actionsが付けるコミットSHAタグ)に変える —— ただしマイグレーションは
# 前進のみで巻き戻せないため、スキーマ変更を伴うリリースを戻すにはDBのリストアが要る。
#
# 通常の(リポジトリを配置できる)環境では docker-compose.yml を使う
# ——こちらは値の直書きぶん古くなりやすい。
name: travel-log
# ---- ここだけ編集: データの置き場(ホストの絶対パス。1つだけ) ----
# この下の3つは init サービスが起動時に作るので、用意するのはこの親だけでよい:
# <置き場>/db … Postgresの実データ(実体は db/18/docker)
# <置き場>/photos … 訪問記録の写真。DBには相対パスだけが入るのでDBと一緒にバックアップする
# <置き場>/exports … エクスポートのZIP。作り直せるのでバックアップは要らない
# 無ければDockerが作る。それも効かない環境では、この親だけを先に作っておくこと
# —— 下の3つは init が作るので、用意するのは常にこの1つで足りる。
# 書式は「ホスト側の絶対パス:コンテナ側」。3つのサービスが同じ場所を同じ /data に
# マウントするので、1本のアンカーを共有できる
x-data-volume: &data-volume "/path/to/travel-log/data:/data"
# ---- ここだけ編集: 実行ユーザー ----
# 上のディレクトリをホスト側で読み書きするユーザーの `id -u`:`id -g`。
# app はこのユーザーで動くので、ここが合っていないと写真の保存に失敗する。
# db は関係ない(postgresのエントリポイントが自分で所有者を揃える)
# **イメージ内の既定は 10001:10001**(ホストに実在しない番号)。data/ をホストから
# 直接編集・書き戻ししたいときだけ `id -u`:`id -g` に書き換える
x-run-as: &run-as "10001:10001"
# ---- ここだけ編集: アプリの設定(.env の代わり) ----
# セッションCookieの署名鍵(必須)。32バイト程度のランダム文字列を入れる
# (生成例: openssl rand -base64 32)。空のままだとログイン時に
# "SESSION_SECRET is not set" で失敗する。変更すると既存のログインセッションは
# すべて無効になる(再ログインすれば直る)。
x-session-secret: &session-secret ""
# Googleでログイン(任意)。空のままならメールログインのみ。
# 取得方法・リダイレクトURIの設定はREADMEの「Googleログインの設定」参照
x-google-client-id: &google-client-id ""
x-google-client-secret: &google-client-secret ""
# 公開URL(任意。例: "https://travel.example.com")。
# リバースプロキシ越し(HTTPS終端あり)で使う場合、プロキシが X-Forwarded-Proto /
# X-Forwarded-Host を送らない構成だと、Googleログインのリダイレクトが http:// で
# 組まれて認証に失敗する。そのときはここに公開URLを書いて明示する。
# 直接 http://<ホスト>:7040 で使うなら空のままでよい。
x-public-base-url: &public-base-url ""
# 周辺のAI探索(任意。例: "http://chiezo.example.lan:7010")。知識サーバー chiezo の
# 場所と、中継先で使う相手(/v1/ai/backends に出る id。空なら antigravity)。
# 空のままなら機能そのものが出ない
x-chiezo-base-url: &chiezo-base-url ""
x-chiezo-ai-backend: &chiezo-ai-backend ""
# 同じホストで chiezo が動いているのに届かない(「時間内に応答しなかった」になる)ときは、
# コンテナからホストの公開ポートへ戻る経路が塞がれている(NASのファイアウォール等)。
# そのときは chiezo のネットワークに相乗りする(ホストのポートを経由しない)。
# やることは2か所のコメントを外し、上の chiezo-base-url を
# "http://chiezo-app:7010" に書き換えるだけにしてある(外すのは下の
# app の `networks:` と、ファイル末尾の `networks:` の定義)。
# chiezo-app はコンテナ名なので、相手のプロジェクト名が何でもこの名前で引ける。
#
# 注意:
# - `networks:` を書くと既定のネットワークに自動で入らなくなる。`default` を並べ忘れると
# app が db に繋がらず起動できない
# - ネットワーク名は環境で変わる。`<プロジェクト名>_default` で、プロジェクト名は
# 管理画面で付けたスタック名。`docker network ls` で実物を確認する
# - `external: true` はそのネットワークが既に在ることが前提。chiezo を同じホストで
# 動かしていない環境でこれを書くと、本体が起動できなくなる(だから既定では外してある)
services:
# 本体より先に、データの置き場の下へ必要なディレクトリを作り、所有者を実行ユーザーに
# 合わせるワンショット。bindマウント先がホストに無いとDockerがroot所有で作ってしまい、
# 非rootで動くappが写真とエクスポートを書けずに落ちるため。appと同じイメージを使うので
# pullは増えない。$$0 は sh に渡す位置パラメータ(composeが $ をエスケープする書き方)で、
# chown先と app の user: が同じアンカーを参照できるようにしている。
# db/ はchownしない —— postgresのエントリポイントがrootで起動して自分で揃える
init:
image: ghcr.io/rtcode337/travel-log:latest
user: root
volumes:
- *data-volume
entrypoint:
- sh
- -c
- mkdir -p /data/db /data/photos /data/exports && chown -R "$$0" /data/photos /data/exports
- *run-as
restart: "no"
db:
image: postgres:18-alpine
depends_on:
init:
condition: service_completed_successfully
environment:
# ホストにポート公開しないコンテナ間だけの接続。変えるなら init の
# PG* と app の DATABASE_URL も同じ値に揃えること
POSTGRES_USER: travel_log
POSTGRES_PASSWORD: travel_log
POSTGRES_DB: travel_log
# 置き場を1つにまとめ、その下をdb/photos/exportsに切っている。既定
# (/var/lib/postgresql/18/docker)のままだとマウント直下に18/が来て
# photos・exportsと同じ段に並ぶので、db/の下へ寄せる。他のサービスと
# 同じ /data にマウントするため、既定の位置からも移している
PGDATA: /data/db/18/docker
volumes:
# db/init はマウントしない。スキーマ本体(01_schema.sql)はappが起動時に流す
- *data-volume
# postgres:18 は VOLUME /var/lib/postgresql を宣言しており、そこに何も
# マウントしないと起動のたびに空の匿名ボリュームが作られて溜まっていく。
# 実データは上のPGDATA(=/data配下)に置くのでここは使わない —— 使い捨ての
# tmpfsを当てて抑止する
tmpfs:
- /var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U travel_log"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
# 起動時にまず未適用のマイグレーションを当て、失敗したら待ち受けに進まない
# (古いスキーマのままアプリが動くのを防ぐ)。適用済みリビジョンは
# schema_migrations テーブルに記録され、2回目以降は何もせず本体が上がる
app:
image: ghcr.io/rtcode337/travel-log:latest
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://travel_log:travel_log@db:5432/travel_log
# 値は冒頭の「ここだけ編集」にまとめてある
SESSION_SECRET: *session-secret
GOOGLE_CLIENT_ID: *google-client-id
GOOGLE_CLIENT_SECRET: *google-client-secret
PUBLIC_BASE_URL: *public-base-url
CHIEZO_BASE_URL: *chiezo-base-url
CHIEZO_AI_BACKEND: *chiezo-ai-backend
NODE_ENV: production
# 訪問記録の写真置き場(lib/photoStorage.ts)。DBには相対パスのみ保存される
PHOTOS_DIR: /data/photos
# エクスポートのZIP置き場(lib/exportStorage.ts)。作り直せる使い捨て
EXPORTS_DIR: /data/exports
volumes:
# 置き場ごとマウントして、中のどれを使うかは上のPHOTOS_DIR/EXPORTS_DIRで決める。
# db/も見えるが、postgresがPGDATAを0700で作るのでappのユーザーからは読めない
- *data-volume
# 写真とエクスポートをホストのユーザー所有で書く。所有者合わせは init が済ませる
user: *run-as
# chiezo がホストの公開ポート経由で届かないときだけ、次の1行と
# ファイル末尾の networks: を有効にする(default も必ず並べる)
#networks: [default, chiezo]
ports:
# host:container。LAN内からのみ見える状態にしておくこと
- "7040:7040"
restart: unless-stopped
# chiezo のネットワークに相乗りするときだけ有効にする(上の app の networks: と対で使う)。
# name は環境で変わる(`<プロジェクト名>_default`)ので docker network ls で確かめること
#networks:
# chiezo:
# external: true
# name: chiezo_default