build: optimize API container image - #144
Conversation
release: promote main
…es--release chore: release release
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: v1.8.1
release: v1.8.2
release: v1.9.0
release: v1.10.0
release: v1.11.0
release: v1.12.0
release: v1.13.0
|
Someone is attempting to deploy a commit to the Comp AI - PoC Team on Vercel. A member of the Team first needs to authorize it. |
|
Retargeted this onto
Nothing is wrong with your branch. If the diff now shows commits that are already on git fetch origin main
git rebase origin/main
git push --force-with-lease |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 380c2e3186
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # Install only the API workspace and its transitive workspace dependencies. | ||
| COPY --from=pruner /workspace/out/json/ ./ | ||
| COPY --from=pruner /workspace/out/bun.lock ./bun.lock | ||
| RUN bun install --frozen-lockfile |
There was a problem hiding this comment.
| && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends python3 make g++ \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Install only the API workspace and its transitive workspace dependencies. |
There was a problem hiding this comment.
Remove the new Dockerfile comments
The new explanatory comments violate the repository's absolute ban on added code comments. Remove this comment and lines 30-31.
AGENTS.md reference: AGENTS.md:L25-L28
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
5 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/test-api-dockerfile.sh">
<violation number="1" location="scripts/test-api-dockerfile.sh:1">
P2: This test script is never invoked: no CI workflow and no package.json script references it, so the Dockerfile policy it checks is never enforced. The PR description states the Dockerfile policy test passes, but the script must be wired into CI (or a package script that CI runs) for that to be true automatically.</violation>
</file>
<file name="Dockerfile.api">
<violation number="1" location="Dockerfile.api:16">
P3: These new Dockerfile comments violate the repository rule against adding code comments. Remove the explanatory comments and keep the Dockerfile self-documenting through its stage and command structure.</violation>
<violation number="2" location="Dockerfile.api:19">
P2: `bun install --frozen-lockfile` runs before the full source (including the Prisma schema) is copied in. Only `out/json` (package.json manifests) is present at this point, so any workspace postinstall/lifecycle script that depends on files from `out/full` — such as a Prisma generate step — will fail during install. Copy `out/full` before running `bun install`, or ensure lifecycle scripts don't depend on files that arrive later.</violation>
<violation number="3" location="Dockerfile.api:33">
P2: The runtime image copies the builder's full dependency trees, which install devDependencies because the builder's `bun install --frozen-lockfile` runs without NODE_ENV=production. Across the pruned graph (root, apps/api, and per-package node_modules under the isolated linker) this carries typescript, turbo, @biomejs/biome, supertest, concurrently, @nestjs/testing, @types/* and pg into the production image. That directly undercuts the PR's goal of keeping build tooling out of the runtime layer.</violation>
</file>
<file name=".dockerignore">
<violation number="1" location=".dockerignore:15">
P2: The PR's goal is to keep local build artifacts and secrets out of the Docker context, but this new file omits entries the repo's own `.gitignore` already protects. The pruner stage runs `COPY . .`, so any `*.pem` private key, or `.eve`/`.output`/`out/`/`build` output directories present locally, gets copied into the image layers. Add those patterns to match `.gitignore` (lines 25, 38, 44, 45), especially `*.pem`.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| @@ -0,0 +1,8 @@ | |||
| #!/usr/bin/env bash | |||
There was a problem hiding this comment.
P2: This test script is never invoked: no CI workflow and no package.json script references it, so the Dockerfile policy it checks is never enforced. The PR description states the Dockerfile policy test passes, but the script must be wired into CI (or a package script that CI runs) for that to be true automatically.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/test-api-dockerfile.sh, line 1:
<comment>This test script is never invoked: no CI workflow and no package.json script references it, so the Dockerfile policy it checks is never enforced. The PR description states the Dockerfile policy test passes, but the script must be wired into CI (or a package script that CI runs) for that to be true automatically.</comment>
<file context>
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+file=${1:-Dockerfile.api}
</file context>
| # Install only the API workspace and its transitive workspace dependencies. | ||
| COPY --from=pruner /workspace/out/json/ ./ | ||
| COPY --from=pruner /workspace/out/bun.lock ./bun.lock | ||
| RUN bun install --frozen-lockfile |
There was a problem hiding this comment.
P2: bun install --frozen-lockfile runs before the full source (including the Prisma schema) is copied in. Only out/json (package.json manifests) is present at this point, so any workspace postinstall/lifecycle script that depends on files from out/full — such as a Prisma generate step — will fail during install. Copy out/full before running bun install, or ensure lifecycle scripts don't depend on files that arrive later.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Dockerfile.api, line 19:
<comment>`bun install --frozen-lockfile` runs before the full source (including the Prisma schema) is copied in. Only `out/json` (package.json manifests) is present at this point, so any workspace postinstall/lifecycle script that depends on files from `out/full` — such as a Prisma generate step — will fail during install. Copy `out/full` before running `bun install`, or ensure lifecycle scripts don't depend on files that arrive later.</comment>
<file context>
@@ -0,0 +1,40 @@
+# Install only the API workspace and its transitive workspace dependencies.
+COPY --from=pruner /workspace/out/json/ ./
+COPY --from=pruner /workspace/out/bun.lock ./bun.lock
+RUN bun install --frozen-lockfile
+
+COPY --from=pruner /workspace/out/full/ ./
</file context>
| @@ -0,0 +1,15 @@ | |||
| .git | |||
There was a problem hiding this comment.
P2: The PR's goal is to keep local build artifacts and secrets out of the Docker context, but this new file omits entries the repo's own .gitignore already protects. The pruner stage runs COPY . ., so any *.pem private key, or .eve/.output/out//build output directories present locally, gets copied into the image layers. Add those patterns to match .gitignore (lines 25, 38, 44, 45), especially *.pem.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .dockerignore, line 15:
<comment>The PR's goal is to keep local build artifacts and secrets out of the Docker context, but this new file omits entries the repo's own `.gitignore` already protects. The pruner stage runs `COPY . .`, so any `*.pem` private key, or `.eve`/`.output`/`out/`/`build` output directories present locally, gets copied into the image layers. Add those patterns to match `.gitignore` (lines 25, 38, 44, 45), especially `*.pem`.</comment>
<file context>
@@ -0,0 +1,15 @@
+.env.*
+!.env.example
+coverage
+*.log
</file context>
| # The API bundle keeps third-party packages external. Copy only the pruned API | ||
| # dependency graph rather than the complete CRM monorepo workspace. | ||
| COPY --from=builder /workspace/package.json /workspace/bun.lock ./ | ||
| COPY --from=builder /workspace/node_modules ./node_modules |
There was a problem hiding this comment.
P2: The runtime image copies the builder's full dependency trees, which install devDependencies because the builder's bun install --frozen-lockfile runs without NODE_ENV=production. Across the pruned graph (root, apps/api, and per-package node_modules under the isolated linker) this carries typescript, turbo, @biomejs/biome, supertest, concurrently, @nestjs/testing, @types/* and pg into the production image. That directly undercuts the PR's goal of keeping build tooling out of the runtime layer.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Dockerfile.api, line 33:
<comment>The runtime image copies the builder's full dependency trees, which install devDependencies because the builder's `bun install --frozen-lockfile` runs without NODE_ENV=production. Across the pruned graph (root, apps/api, and per-package node_modules under the isolated linker) this carries typescript, turbo, @biomejs/biome, supertest, concurrently, @nestjs/testing, @types/* and pg into the production image. That directly undercuts the PR's goal of keeping build tooling out of the runtime layer.</comment>
<file context>
@@ -0,0 +1,40 @@
+# The API bundle keeps third-party packages external. Copy only the pruned API
+# dependency graph rather than the complete CRM monorepo workspace.
+COPY --from=builder /workspace/package.json /workspace/bun.lock ./
+COPY --from=builder /workspace/node_modules ./node_modules
+COPY --from=builder /workspace/apps/api/package.json ./apps/api/package.json
+COPY --from=builder /workspace/apps/api/node_modules ./apps/api/node_modules
</file context>
| && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends python3 make g++ \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Install only the API workspace and its transitive workspace dependencies. |
There was a problem hiding this comment.
P3: These new Dockerfile comments violate the repository rule against adding code comments. Remove the explanatory comments and keep the Dockerfile self-documenting through its stage and command structure.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Dockerfile.api, line 16:
<comment>These new Dockerfile comments violate the repository rule against adding code comments. Remove the explanatory comments and keep the Dockerfile self-documenting through its stage and command structure.</comment>
<file context>
@@ -0,0 +1,40 @@
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends python3 make g++ \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install only the API workspace and its transitive workspace dependencies.
+COPY --from=pruner /workspace/out/json/ ./
+COPY --from=pruner /workspace/out/bun.lock ./bun.lock
</file context>
Summary
Motivation
The generated OpenShip image copied the complete workspace into a 2.61 GB runtime layer. A single API deployment took roughly 21 minutes, mostly copying and exporting dependency layers.
Validation
Summary by cubic
Optimizes the API container by replacing the generated OpenShip image with a dedicated multi-stage
Dockerfile.apithat prunes the monorepo to the API dependency graph. The old image copied the entire workspace (≈2.61 GB) and took ~21 minutes to deploy; the new image is smaller, builds faster, and keeps build tools out of runtime..dockerignoreto exclude local artifacts and secrets from the Docker context.Dockerfile.api:turbo prune api --docker, installs only API graph deps withbun, and builds the API; native tools (python3,make,g++) exist only in the builder.packages/db db:deployon container start.oven/bun:slim, copies only pruned deps,apps/api/dist, andpackages(includingpackages/db), and serves on port 3001.scripts/test-api-dockerfile.shto enforce pruning, native build tooling in builder only, presence of migrations, and no full-workspace copy.Required actions:
-f Dockerfile.apifrom the repo root.DATABASE_URLat runtime; the container now applies migrations on start. If you run migrations elsewhere, override the container CMD/entrypoint to omitdb:deploy.Written for commit 380c2e3. Summary will update on new commits.