Spaces:
Configuration error
Configuration error
# 优化版多阶段构建Dockerfile | |
# 这个版本针对生产环境进行了优化,镜像更小,安全性更高 | |
# ================================ | |
# 阶段1: 前端构建 | |
# ================================ | |
FROM node:18-alpine as frontend-builder | |
# 设置工作目录 | |
WORKDIR /app | |
# 只复制package文件,利用Docker缓存 | |
COPY client/package*.json ./ | |
# 安装依赖 | |
RUN npm ci --only=production && \ | |
npm cache clean --force | |
# 复制源代码 | |
COPY client/ ./ | |
# 构建前端 | |
RUN npm run build | |
# ================================ | |
# 阶段2: 后端构建 | |
# ================================ | |
FROM node:18-alpine as backend-builder | |
WORKDIR /app | |
# 复制package文件 | |
COPY server/package*.json ./ | |
# 安装依赖 | |
RUN npm ci --only=production && \ | |
npm cache clean --force | |
# 复制源代码 | |
COPY server/ ./ | |
# ================================ | |
# 阶段3: 最终生产镜像 | |
# ================================ | |
FROM node:18-alpine | |
# 安装运行时依赖 | |
RUN apk add --no-cache \ | |
nginx \ | |
supervisor \ | |
wget \ | |
curl \ | |
dumb-init \ | |
&& rm -rf /var/cache/apk/* | |
# 创建应用用户 | |
RUN addgroup -g 1001 -S appuser && \ | |
adduser -S appuser -u 1001 -G appuser | |
# 创建必要的目录 | |
RUN mkdir -p /app /var/log/nginx /var/log/supervisor /run/nginx && \ | |
chown -R appuser:appuser /app /var/log/nginx /var/log/supervisor /run/nginx | |
# 设置工作目录 | |
WORKDIR /app | |
# 复制后端文件 | |
COPY --from=backend-builder --chown=appuser:appuser /app ./ | |
# 复制前端构建文件 | |
COPY --from=frontend-builder --chown=appuser:appuser /app/dist ./public | |
# 创建nginx配置 | |
COPY --chown=appuser:appuser <<EOF /etc/nginx/nginx.conf | |
user appuser; | |
worker_processes auto; | |
pid /run/nginx/nginx.pid; | |
events { | |
worker_connections 1024; | |
use epoll; | |
multi_accept on; | |
} | |
http { | |
include /etc/nginx/mime.types; | |
default_type application/octet-stream; | |
# 日志格式 | |
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" ' | |
'\$status \$body_bytes_sent "\$http_referer" ' | |
'"\$http_user_agent" "\$http_x_forwarded_for"'; | |
access_log /var/log/nginx/access.log main; | |
error_log /var/log/nginx/error.log warn; | |
# 性能优化 | |
sendfile on; | |
tcp_nopush on; | |
tcp_nodelay on; | |
keepalive_timeout 65; | |
types_hash_max_size 2048; | |
# Gzip压缩 | |
gzip on; | |
gzip_vary on; | |
gzip_min_length 1024; | |
gzip_comp_level 6; | |
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; | |
server { | |
listen 80; | |
server_name localhost; | |
root /app/public; | |
index index.html; | |
# 前端路由 | |
location / { | |
try_files \$uri \$uri/ /index.html; | |
} | |
# API代理 | |
location /api/ { | |
proxy_pass http://127.0.0.1:5000; | |
proxy_http_version 1.1; | |
proxy_set_header Upgrade \$http_upgrade; | |
proxy_set_header Connection 'upgrade'; | |
proxy_set_header Host \$host; | |
proxy_set_header X-Real-IP \$remote_addr; | |
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto \$scheme; | |
proxy_cache_bypass \$http_upgrade; | |
} | |
# Socket.IO代理 | |
location /socket.io/ { | |
proxy_pass http://127.0.0.1:5000; | |
proxy_http_version 1.1; | |
proxy_set_header Upgrade \$http_upgrade; | |
proxy_set_header Connection "upgrade"; | |
proxy_set_header Host \$host; | |
proxy_set_header X-Real-IP \$remote_addr; | |
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto \$scheme; | |
} | |
# 静态资源缓存 | |
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)\$ { | |
expires 1y; | |
add_header Cache-Control "public, immutable"; | |
} | |
} | |
} | |
EOF | |
# 创建supervisor配置 | |
COPY --chown=appuser:appuser <<EOF /etc/supervisor/conf.d/supervisord.conf | |
[supervisord] | |
nodaemon=true | |
user=appuser | |
logfile=/var/log/supervisor/supervisord.log | |
pidfile=/run/supervisord.pid | |
childlogdir=/var/log/supervisor | |
[program:nginx] | |
command=nginx -g "daemon off;" | |
autostart=true | |
autorestart=true | |
stderr_logfile=/var/log/supervisor/nginx_error.log | |
stdout_logfile=/var/log/supervisor/nginx_access.log | |
user=appuser | |
[program:node] | |
command=node index.js | |
directory=/app | |
autostart=true | |
autorestart=true | |
stderr_logfile=/var/log/supervisor/node_error.log | |
stdout_logfile=/var/log/supervisor/node_access.log | |
user=appuser | |
environment=NODE_ENV=production,PORT=5000 | |
EOF | |
# 设置权限 | |
RUN chown -R appuser:appuser /etc/nginx /etc/supervisor | |
# 切换到应用用户 | |
USER appuser | |
# 暴露端口 | |
EXPOSE 80 | |
# 环境变量 | |
ENV NODE_ENV=production | |
ENV PORT=5000 | |
# 健康检查 | |
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ | |
CMD wget --no-verbose --tries=1 --spider http://localhost:80/api/health || exit 1 | |
# 使用dumb-init作为PID 1 | |
ENTRYPOINT ["/usr/bin/dumb-init", "--"] | |
# 启动supervisor | |
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] | |