Dockerfile: multi-stage node:22-alpine build #7

Closed
opened 2026-04-25 22:01:50 +00:00 by forgejo_admin · 2 comments

Type

Task

Lineage

Depends on scaffolding ticket. No parent issue.

Repo

forgejo_admin/westside-admin

User Story

story-westside-admin-admin-row-crud. Foundational — the image-build pipeline requires a Dockerfile.

Context

westside-admin deploys via the same kaniko→Harbor→kustomize-tag→ArgoCD pipeline as westside-app. This ticket creates the Dockerfile that kaniko will build. Multi-stage to keep the runtime image small. Reference ~/westside-app/Dockerfile for the proven pattern (if it exists; otherwise mirror the SvelteKit adapter-node official guide).

Scope

Create Dockerfile with two stages: a builder stage that runs npm ci and npm run build, and a runtime stage that copies only the build/ directory + node_modules (production only) and runs node build/index.js. Create .dockerignore excluding node_modules, .git, .env, README.md, .vscode, .playwright-mcp, screenshots, and any other dev artifacts. Use node:22-alpine for both stages. Run as non-root user (UID 1000+). EXPOSE 3000. Define a HEALTHCHECK that hits GET /health and expects 200.

Verify locally: docker build -t westside-admin:test . succeeds, docker run -p 3000:3000 westside-admin:test serves on port 3000, image size under 250MB, no secrets baked into layers (verify via docker history).

Acceptance Criteria

  • docker build -t westside-admin:test . succeeds locally
  • Resulting image runs and serves on port 3000
  • Image size under 250MB (alpine-based)
  • No build secrets baked into the image (verify with docker history)
  • EXPOSE 3000
  • Healthcheck endpoint defined (HTTP GET /health returns 200)

Test Expectations

  • docker build then docker run -p 3000:3000 westside-admin:test then curl http://localhost:3000/health returns 200
  • Image scan via trivy image westside-admin:test shows zero HIGH/CRITICAL vulns in base layer

Constraints

  • Use node:22-alpine to match westside-app's Node version
  • Multi-stage to drop devDependencies from final image
  • Run as non-root user

Checklist

  • PR opened
  • Image builds and runs locally
  • No unrelated changes
  • project-westside-admin
  • arch-deployment-westside-admin
### Type Task ### Lineage Depends on scaffolding ticket. No parent issue. ### Repo `forgejo_admin/westside-admin` ### User Story `story-westside-admin-admin-row-crud`. Foundational — the image-build pipeline requires a Dockerfile. ### Context westside-admin deploys via the same kaniko→Harbor→kustomize-tag→ArgoCD pipeline as westside-app. This ticket creates the Dockerfile that kaniko will build. Multi-stage to keep the runtime image small. Reference `~/westside-app/Dockerfile` for the proven pattern (if it exists; otherwise mirror the SvelteKit adapter-node official guide). ### Scope Create `Dockerfile` with two stages: a `builder` stage that runs `npm ci` and `npm run build`, and a `runtime` stage that copies only the `build/` directory + `node_modules` (production only) and runs `node build/index.js`. Create `.dockerignore` excluding node_modules, .git, .env, README.md, .vscode, .playwright-mcp, screenshots, and any other dev artifacts. Use `node:22-alpine` for both stages. Run as non-root user (UID 1000+). EXPOSE 3000. Define a HEALTHCHECK that hits `GET /health` and expects 200. Verify locally: `docker build -t westside-admin:test .` succeeds, `docker run -p 3000:3000 westside-admin:test` serves on port 3000, image size under 250MB, no secrets baked into layers (verify via `docker history`). ### Acceptance Criteria - [ ] `docker build -t westside-admin:test .` succeeds locally - [ ] Resulting image runs and serves on port 3000 - [ ] Image size under 250MB (alpine-based) - [ ] No build secrets baked into the image (verify with `docker history`) - [ ] EXPOSE 3000 - [ ] Healthcheck endpoint defined (HTTP GET /health returns 200) ### Test Expectations - `docker build` then `docker run -p 3000:3000 westside-admin:test` then `curl http://localhost:3000/health` returns 200 - Image scan via `trivy image westside-admin:test` shows zero HIGH/CRITICAL vulns in base layer ### Constraints - Use `node:22-alpine` to match westside-app's Node version - Multi-stage to drop devDependencies from final image - Run as non-root user ### Checklist - [ ] PR opened - [ ] Image builds and runs locally - [ ] No unrelated changes ### Related - `project-westside-admin` - `arch-deployment-westside-admin`
Author
Owner

Scope Review: READY

Review note: review-1088-2026-04-25

Scope is solid, traceability complete (story + arch notes verified), AC testable, fits a single agent pass. Hard dep on scaffolding #6 (also in backlog) — both can review in parallel, dev work serializes.

Three nice-to-haves for the dev agent (not blockers):

  • [BODY] Add AC bullet for non-root UID verification (constraint→AC gap)
  • [BODY] Reference Dockerfile note: ~/westside-app/Dockerfile is adapter-static + nginx, not adapter-node — steer to SvelteKit adapter-node pattern (or westside-contracts) instead
  • [SCOPE] Coordinate /health route with scaffolding #6, or HEALTHCHECK AC fails in isolation
## Scope Review: READY Review note: `review-1088-2026-04-25` Scope is solid, traceability complete (story + arch notes verified), AC testable, fits a single agent pass. Hard dep on scaffolding #6 (also in backlog) — both can review in parallel, dev work serializes. Three nice-to-haves for the dev agent (not blockers): - `[BODY]` Add AC bullet for non-root UID verification (constraint→AC gap) - `[BODY]` Reference Dockerfile note: `~/westside-app/Dockerfile` is adapter-static + nginx, not adapter-node — steer to SvelteKit adapter-node pattern (or westside-contracts) instead - `[SCOPE]` Coordinate `/health` route with scaffolding #6, or HEALTHCHECK AC fails in isolation
Author
Owner

PR opened: #10

Local validation:

  • docker build succeeded
  • Image size: 240MB (under 250MB target)
  • curl localhost:3000/health -> HTTP 200
  • Runs as node user (UID 1000)
PR opened: https://forgejo.tail5b443a.ts.net/forgejo_admin/westside-admin/pulls/10 Local validation: - `docker build` succeeded - Image size: 240MB (under 250MB target) - `curl localhost:3000/health` -> HTTP 200 - Runs as `node` user (UID 1000)
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-admin#7
No description provided.