From 2efe4bb536e0ac9af1b66aa7a6214b770f53ecff Mon Sep 17 00:00:00 2001 From: pq198363-ops <246611021+pq198363-ops@users.noreply.github.com> Date: Sat, 4 Jul 2026 09:59:11 +0800 Subject: [PATCH] docs: add container deployment guide --- .dockerignore | 14 ++++++++++++++ Dockerfile | 37 +++++++++++++++++++++++++++++++++++++ README.md | 26 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d9b5671 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +node_modules +dist +.git +.github +.env +.env.* +*.log +.DS_Store +coverage +Dockerfile +README.md +docs +src/**/*.test.ts +**/*.test.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d2979ff --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +# syntax=docker/dockerfile:1 + +FROM node:22-bookworm-slim AS deps +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +FROM deps AS build +COPY tsconfig.json ./ +COPY src ./src +RUN npm run build + +FROM node:22-bookworm-slim AS production-deps +WORKDIR /app +ENV NODE_ENV=production + +COPY package*.json ./ +RUN npm ci --omit=dev && npm cache clean --force + +FROM node:22-bookworm-slim AS runtime +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=3001 + +COPY --from=production-deps --chown=node:node /app/node_modules ./node_modules +COPY --from=build --chown=node:node /app/dist ./dist +COPY --chown=node:node package*.json ./ + +USER node +EXPOSE 3001 +STOPSIGNAL SIGTERM + +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 CMD node -e "fetch('http://127.0.0.1:' + (process.env.PORT || '3001') + '/health').then((res) => { if (!res.ok) process.exit(1); }).catch(() => process.exit(1));" + +CMD ["node", "dist/index.js"] diff --git a/README.md b/README.md index 337ee4f..722a923 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,32 @@ agentpay-backend/ | `npm run dev` | Run with ts-node | | `npm start` | Run production build | +## Running with Docker + +Build a production image from the repository root: + +```bash +docker build -t agentpay-backend . +``` + +Run it locally, publishing the API on `http://localhost:3001`: + +```bash +docker run --rm --name agentpay-backend -p 3001:3001 -e PORT=3001 agentpay-backend +``` + +Check the container health endpoint: + +```bash +curl -fsS http://localhost:3001/health +``` + +The runtime image contains only production dependencies and the compiled +`dist/` output, runs as the non-root `node` user, and uses `SIGTERM` as the +stop signal so the application graceful-shutdown handler can drain in-flight +requests. Pass configuration with `-e NAME=value` or `--env-file`; real `.env` +files are ignored by Docker builds and must not be baked into image layers. + ## Documentation - [Billing units and settlement semantics](docs/billing-units.md) explains