11# ─────────────────────────────────────────────────────────────────────────────
22# Stage 1 – deps
3- # Install *production-only* dependencies so they can be copied cleanly into
4- # the final image without devDependencies or build tooling.
3+ # Install production-only dependencies for cache-efficient builds.
54# ─────────────────────────────────────────────────────────────────────────────
65FROM node:20-alpine AS deps
76
87WORKDIR /app
98
10- # Copy dependency manifests first to maximise layer caching.
11- # If neither file changes, Docker skips the npm ci step on rebuilds.
9+ # Copy package manifests first for better layer caching.
1210COPY package*.json ./
1311
14- # Install production deps only — keep the image lean .
15- RUN npm ci --omit=dev
12+ # Install production dependencies only.
13+ RUN npm ci --omit=dev && npm cache clean --force
1614
1715# ─────────────────────────────────────────────────────────────────────────────
18- # Stage 2 – runner
19- # Final, minimal runtime image. Nothing from devDependencies makes it in .
16+ # Stage 2 – final runtime
17+ # Minimal runtime image with production assets only .
2018# ─────────────────────────────────────────────────────────────────────────────
2119FROM node:20-alpine AS runner
2220
2321WORKDIR /app
24-
2522ENV NODE_ENV=production
2623
27- # Copy production node_modules from the deps stage.
24+ # Copy prod dependencies from the deps stage.
2825COPY --from=deps /app/node_modules ./node_modules
2926
30- # Copy application source .
27+ # Copy application files (excluding ignored files in .dockerignore) .
3128COPY . .
3229
33- # Create the data directory and set ownership to the unprivileged 'node' user
34- # before we switch to that user, so the process can write tasks.json.
30+ # Create runtime data directory and set safe permissions.
3531RUN mkdir -p /app/data && chown -R node:node /app/data
3632
37- # Expose the metrics / health-check port (MetricsServer default: 3000).
38- # Override at runtime with METRICS_PORT env var if needed.
33+ # Expose the default metrics/health port.
3934EXPOSE 3000
4035
41- # SECURITY: run as the unprivileged built-in ' node' user, never root .
36+ # SECURITY: run as the unprivileged node user.
4237USER node
4338
44- # Start the keeper bot.
4539CMD ["node" , "index.js" ]
0 commit comments