MinIO設定をCoolify対応に整備し、bucket自動作成を追加

compose:
- MinIOにヘルスチェック(mc ready)を追加し、api/workerはhealthyを待つように変更
- 全認証情報を${VAR:-default}でパラメータ化し、Coolifyの環境変数/シークレットで上書き可能に
- MINIO_SERVER_URL / MINIO_BROWSER_REDIRECT_URL でリバースプロキシ背後の公開URLに対応
- workerの依存先をapiからpostgres+minioに修正し、起動順序のデッドロックを解消

API:
- S3StorageにensureBucket()を追加(HeadBucket→なければCreateBucket、冪等)
- runtime起動時にbucketを自動作成し、minio-init依存を必須ではなくした

.env.exampleにMinIO関連変数を追記
This commit is contained in:
amania-jailbreak
2026-08-05 10:31:03 +09:00
parent 93825ebc64
commit 62c32ad0ad
4 changed files with 105 additions and 35 deletions
+8 -1
View File
@@ -5,5 +5,12 @@ import { createStorage } from "./storage";
export async function createRuntime(appConfig: AppConfig) {
const { store, pool } = await createStore(appConfig);
await store.init();
return { store, storage: createStorage(appConfig), pool };
const storage = createStorage(appConfig);
// When using S3-compatible storage (e.g. MinIO), make sure the target bucket
// exists before serving traffic. This keeps the service self-contained and
// removes the need for a separate init container.
if (storage.ensureBucket) {
await storage.ensureBucket();
}
return { store, storage, pool };
}
+23
View File
@@ -5,9 +5,11 @@ import { dirname, normalize, relative, resolve } from "node:path";
import { pipeline } from "node:stream/promises";
import { Readable } from "node:stream";
import {
CreateBucketCommand,
CompleteMultipartUploadCommand,
CreateMultipartUploadCommand,
GetObjectCommand,
HeadBucketCommand,
HeadObjectCommand,
PutObjectCommand,
S3Client,
@@ -35,6 +37,7 @@ export interface StorageAdapter {
downloadToFile(key: string, filePath: string): Promise<void>;
getObject(key: string): Promise<StoredObject | null>;
headObject(key: string): Promise<{ sizeBytes: number; contentType: string } | null>;
ensureBucket?(): Promise<void>;
}
function contentTypeForPath(path: string) {
@@ -126,6 +129,26 @@ export class S3Storage implements StorageAdapter {
});
}
// Idempotently create the configured bucket so the service is self-contained
// and does not depend on an external init step (e.g. a separate minio-init
// container) before it can store objects. Safe to call on every startup.
async ensureBucket() {
const bucket = this.appConfig.S3_BUCKET;
try {
await this.client.send(new HeadBucketCommand({ Bucket: bucket }));
return;
} catch (error: any) {
const notFound = error?.$metadata?.httpStatusCode === 404 || error?.name === "NotFound" || error?.name === "NoSuchBucket";
if (!notFound) {
// Re-throw unexpected errors (auth, network) so they surface loudly.
throw error;
}
}
// us-east-1 / "auto" regions must NOT send a LocationConstraint.
await this.client.send(new CreateBucketCommand({ Bucket: bucket }));
}
async createUploadPlan(key: string, contentType: string, sizeBytes: number) {
const partSizeBytes = 16 * 1024 * 1024;
const partCount = Math.ceil(sizeBytes / partSizeBytes);