Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/postgres-18-volume-mount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"seamless-cli": patch
---

Fix the scaffolded database failing to start on PostgreSQL 18.

The PostgreSQL 18 bump moved the image tag but not the volume mount. PostgreSQL 18+ images store data
in a major-versioned subdirectory (`/var/lib/postgresql/18/docker`), so a mount at
`/var/lib/postgresql/data` is ignored and the container refuses to start, restart-looping on:

```
Error: in 18+, these Docker images are configured to store database data in a
format which is compatible with "pg_ctlcluster" ...
Counter to that, there appears to be PostgreSQL data in:
/var/lib/postgresql/data (unused mount/volume)
```

The generated `docker-compose.yml` now mounts `pgdata:/var/lib/postgresql`. See
docker-library/postgres#1259.

This only ever affected projects scaffolded from the unreleased PostgreSQL 18 change, so no published
version of the CLI produced a broken scaffold.
22 changes: 22 additions & 0 deletions src/generators/docker/docker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,28 @@ describe("generateDockerCompose", () => {
expect(compose.endsWith("\n")).toBe(true);
});

// PostgreSQL 18+ images keep data in a major-versioned subdirectory, so a mount
// at .../data is ignored and the container restart-loops on
// "in 18+, these Docker images are configured to store database data in a
// format which is compatible with pg_ctlcluster". The scaffold shipped exactly
// that for one release cycle.
it("mounts the database volume where PostgreSQL 18 actually stores data", async () => {
writeAuthEnvFixture(tmpDir, "SEAMLESS_JWKS_ACTIVE_KID");

await generateDockerCompose(tmpDir, {
authMode: "local",
adminMode: "image",
});

const compose = fs.readFileSync(
path.join(tmpDir, "docker-compose.yml"),
"utf-8",
);

expect(compose).toContain("- pgdata:/var/lib/postgresql\n");
expect(compose).not.toContain("/var/lib/postgresql/data");
});

// Publishing on 0.0.0.0 put the auth server on the LAN, and it is configured to
// hand back OTP codes in the response for local login.
it("publishes every port on loopback only", async () => {
Expand Down
6 changes: 5 additions & 1 deletion src/generators/docker/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ services:
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: postgres
volumes:
- pgdata:/var/lib/postgresql/data
# PostgreSQL 18+ images store data in a major-versioned subdirectory
# (/var/lib/postgresql/18/docker), so the mount goes one level up. Mounting
# .../data instead leaves the volume unused and the container refuses to
# start. See docker-library/postgres#1259.
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myuser -d postgres"]
interval: 5s
Expand Down
Loading