直接上代码....
- 主要是两个服务: Next.js 服务和Nginx服务
Dockerfile
# Use Node.js 18 Alpine image as the base image for all stages
FROM node:18-alpine AS base
# Install necessary dependencies
FROM base AS deps
# Install libc6-compat for compatibility
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Set npm registry to mirror
ENV NPM_CONFIG_REGISTRY=https://registry.npmmirror.com/
# Copy the package.json and lock files, then install dependencies
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
# Use Yarn if yarn.lock is present
# Use npm if package-lock.json is present
# Use pnpm if pnpm-lock.yaml is present
# Exit if no lockfile is found
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Build the application
FROM base AS builder
WORKDIR /app
# Copy installed dependencies from the 'deps' stage
COPY --from=deps /app/node_modules ./node_modules
# Copy the rest of the application code
COPY . .
RUN \
# Build using Yarn if yarn.lock is present
if [ -f yarn.lock ]; then yarn run build; \
# Build using npm if package-lock.json is present
elif [ -f package-lock.json ]; then npm run build; \
# Build using pnpm if pnpm-lock.yaml is present
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
# Exit if no lockfile is found
else echo "Lockfile not found." && exit 1; \
fi
# Run the application
FROM base AS runner
WORKDIR /app
# Set environment to production
ENV NODE_ENV production
# Add system group for nodejs user
RUN addgroup --system --gid 1001 nodejs
# Add system user for Next.js with UID 1001
RUN adduser --system --uid 1001 nextjs
# Copy necessary files from the builder stage
COPY --from=builder /app/public ./public
# Create the .next directory
RUN mkdir .next
# Change ownership of the .next directory
RUN chown nextjs:nodejs .next
# Copy the compiled application from the builder stage and set the correct ownership
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Switch to the non-root user 'nextjs'
USER nextjs
# Expose port 5173 for the application
EXPOSE 5173
# Set the port to 5173
ENV PORT 5173
# Allow the app to be accessed from any IP
ENV HOSTNAME "0.0.0.0"
# Run the app using Node.js
CMD ["node", "server.js"]
docker-compose.yml
version: '3.8'
services:
app:
container_name: app # 设置 app 服务的容器名称
build:
context: .
ports:
- '5173:5173'
environment:
- NODE_ENV=production
- PORT=5173
networks:
- cosette-net
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5173"]
interval: 30s
retries: 3
start_period: 5s
timeout: 10s
nginx:
container_name: nginx # 设置 nginx 服务的容器名称
image: nginx:alpine
ports:
- '80:80'
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- cosette-net
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
retries: 3
start_period: 5s
timeout: 10s
networks:
cosette-net:
driver: bridge
next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
/* config options here */
output: 'standalone'
}
export default nextConfig
nginx\default.conf
server {
listen 80;
# Server name
server_name localhost;
location / {
# Proxy pass to the application
proxy_pass http://app:5173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /_next/static/ {
# Serve static files from Next.js
# alias /.next/static/;
# Disable access logs
# access_log off;
# Set cache expiration
# expires max;
# Add cache control header
# add_header Cache-Control "public, max-age=31536000, immutable";
proxy_pass http://app:5173/_next/static/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Error log file
error_log /var/log/nginx/error.log;
# Access log file
access_log /var/log/nginx/access.log;
}
nginx\Dockerfile
FROM nginx:alpine
# Remove any existing config files
RUN rm /etc/nginx/conf.d/*
# Copy config files
# *.conf files in "conf.d/" dir get included in main config
COPY ./default.conf /etc/nginx/conf.d/
# Expose the listening port
EXPOSE 80
# Launch NGINX
CMD [ "nginx", "-g", "daemon off;" ]