refactor: optimize Dockerfile for multi-platform builds and add healthcheck script
This commit is contained in:
65
Dockerfile
65
Dockerfile
@@ -1,40 +1,61 @@
|
||||
# STAGE 1: Development
|
||||
# This stage installs all dependencies (including devDependencies) and copies the source code.
|
||||
# It's used as a base for the 'builder' stage and for the development environment via docker-compose.
|
||||
FROM node:18-alpine AS development
|
||||
# Dockerfile optimized for Raspberry Pi (ARM64) and faster builds.
|
||||
|
||||
# Docker BuildKit arguments for multi-platform builds.
|
||||
# These are automatically populated by Docker.
|
||||
ARG TARGETPLATFORM
|
||||
ARG BUILDPLATFORM
|
||||
|
||||
# STAGE 1: Dependencies
|
||||
# This stage installs all dependencies (dev and prod) from package-lock.json
|
||||
# It's used as a base for both development and builder stages to leverage caching.
|
||||
FROM --platform=${BUILDPLATFORM} node:18-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
# Copy project files and install dependencies
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
# Use `npm ci` for faster, more reliable builds from package-lock.json
|
||||
RUN npm ci
|
||||
|
||||
# STAGE 2: Development
|
||||
# This stage is for local development. It includes devDependencies and source code.
|
||||
# In docker-compose.dev.yml, the source is mounted for hot-reloading.
|
||||
FROM deps AS development
|
||||
COPY . .
|
||||
# The command is specified in docker-compose.dev.yml, but we can add a default.
|
||||
CMD ["npm", "start"]
|
||||
|
||||
# STAGE 2: Builder
|
||||
# STAGE 3: Builder
|
||||
# This stage builds the Eleventy site for production.
|
||||
FROM development AS builder
|
||||
# The output will be in the default `_site` directory
|
||||
RUN npx @11ty/eleventy
|
||||
FROM deps AS builder
|
||||
COPY . .
|
||||
# Build the site. Requires a "build": "eleventy" script in package.json
|
||||
RUN npm run build
|
||||
# After building, remove development dependencies to keep the final image small.
|
||||
RUN npm prune --production
|
||||
|
||||
# STAGE 3: Production
|
||||
# STAGE 4: Production
|
||||
# This stage creates a lean, production-ready image.
|
||||
FROM node:18-alpine AS production
|
||||
WORKDIR /app
|
||||
|
||||
# Copy server dependencies from the builder stage
|
||||
COPY --from=builder /app/package*.json ./
|
||||
# Create a non-root user for better security
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
|
||||
# Install only production dependencies for the server
|
||||
RUN npm install --omit=dev
|
||||
# Copy only the necessary artifacts from the builder stage
|
||||
# Using --chown ensures the non-root user owns the files.
|
||||
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=appuser:appgroup /app/package.json ./package.json
|
||||
COPY --from=builder --chown=appuser:appgroup /app/src/server.js .
|
||||
COPY --from=builder --chown=appuser:appgroup /app/_site ./_site
|
||||
COPY --from=builder --chown=appuser:appgroup /app/src/_data ./_data
|
||||
COPY --chown=appuser:appgroup healthcheck.js .
|
||||
|
||||
# Copy the server, the built Eleventy site, and the data file for the view counter.
|
||||
# Note: The paths here are relative to the WORKDIR inside the 'builder' stage (/app).
|
||||
COPY --from=builder /app/src/server.js .
|
||||
COPY --from=builder /app/_site ./_site
|
||||
# The server expects the _data directory in /app/_data, and your config places it in src/_data.
|
||||
COPY --from=builder /app/src/_data ./_data
|
||||
USER appuser
|
||||
|
||||
# Expose the port the server runs on
|
||||
EXPOSE 3000
|
||||
|
||||
# Add a healthcheck to ensure the container is running correctly.
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||
CMD [ "node", "healthcheck.js" ]
|
||||
|
||||
# The command to start the server
|
||||
CMD [ "node", "server.js" ]
|
||||
|
@@ -8,6 +8,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
target: production # Use the 'production' stage from the Dockerfile
|
||||
platform: linux/arm64
|
||||
container_name: eleventy_prod
|
||||
ports:
|
||||
- 3000:3000
|
||||
|
20
healthcheck.js
Normal file
20
healthcheck.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const http = require('http');
|
||||
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: 3000,
|
||||
path: '/',
|
||||
timeout: 2000,
|
||||
};
|
||||
|
||||
const request = http.request(options, (res) => {
|
||||
console.log(`HEALTHCHECK STATUS: ${res.statusCode}`);
|
||||
process.exit(res.statusCode === 200 ? 0 : 1);
|
||||
});
|
||||
|
||||
request.on('error', (err) => {
|
||||
console.error('HEALTHCHECK ERROR', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
request.end();
|
@@ -4,7 +4,8 @@
|
||||
"description": "An Eleventy project with Docker and VS Code debugging.",
|
||||
"scripts": {
|
||||
"start": "eleventy --serve --watch",
|
||||
"debug": "node --inspect=0.0.0.0:9229 ./node_modules/.bin/eleventy --serve --watch"
|
||||
"debug": "node --inspect=0.0.0.0:9229 ./node_modules/.bin/eleventy --serve --watch",
|
||||
"build": "eleventy"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
Reference in New Issue
Block a user