Skip to content

build: optimize API container image - #144

Open
mw-slc wants to merge 18 commits into
trycompai:mainfrom
mw-slc:jarvis/optimize-api-container
Open

build: optimize API container image#144
mw-slc wants to merge 18 commits into
trycompai:mainfrom
mw-slc:jarvis/optimize-api-container

Conversation

@mw-slc

@mw-slc mw-slc commented Aug 12, 2026

Copy link
Copy Markdown

Summary

  • add a dedicated multi-stage API Dockerfile
  • prune the monorepo to the API dependency graph before installing
  • keep native build tools out of the runtime image
  • preserve Prisma migrations and generated client required at startup
  • exclude local build artifacts and secrets from Docker context

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

  • Dockerfile policy test passes
  • clean staging Docker build in progress
  • runtime health and migration verification will be added after the image completes

Summary by cubic

Optimizes the API container by replacing the generated OpenShip image with a dedicated multi-stage Dockerfile.api that 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.

  • Adds .dockerignore to exclude local artifacts and secrets from the Docker context.
  • Introduces Dockerfile.api:
    • Prunes with turbo prune api --docker, installs only API graph deps with bun, and builds the API; native tools (python3, make, g++) exist only in the builder.
    • Preserves Prisma artifacts: runs client generate at build and runs packages/db db:deploy on container start.
    • Runtime uses oven/bun:slim, copies only pruned deps, apps/api/dist, and packages (including packages/db), and serves on port 3001.
  • Adds scripts/test-api-dockerfile.sh to enforce pruning, native build tooling in builder only, presence of migrations, and no full-workspace copy.

Required actions:

  • Update CI/CD to build with -f Dockerfile.api from the repo root.
  • Set DATABASE_URL at runtime; the container now applies migrations on start. If you run migrations elsewhere, override the container CMD/entrypoint to omit db:deploy.

Written for commit 380c2e3. Summary will update on new commits.

Review in cubic

carhartlewis and others added 18 commits August 7, 2026 11:38
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

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.

@github-actions
github-actions Bot changed the base branch from release to main August 12, 2026 20:38
@github-actions

Copy link
Copy Markdown
Contributor

Retargeted this onto main.

release is the default branch so that a plain clone runs the last tagged release, but nothing merges into it — it is fast-forwarded onto the tag by the Release workflow and that is all. Changes go to main, and reach release when a release is cut.

Nothing is wrong with your branch. If the diff now shows commits that are already on main, rebase and force-push:

git fetch origin main
git rebase origin/main
git push --force-with-lease

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread Dockerfile.api
# 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 link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Copy lifecycle inputs before installing dependencies

During every clean image build, Bun runs workspace postinstall scripts against only out/json. The API script and Prisma schema arrive after this step. Installation stops before the build stage completes.

Useful? React with 👍 / 👎.

Comment thread Dockerfile.api
&& 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 link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@cubic-dev-ai cubic-dev-ai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with cubic

Comment thread Dockerfile.api
# 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

@cubic-dev-ai cubic-dev-ai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with cubic

Comment thread .dockerignore
@@ -0,0 +1,15 @@
.git

@cubic-dev-ai cubic-dev-ai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with cubic

Comment thread Dockerfile.api
# 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

@cubic-dev-ai cubic-dev-ai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with cubic

Comment thread Dockerfile.api
&& 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.

@cubic-dev-ai cubic-dev-ai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants