ccccccc / Dockerfile.optimized
cnmksjs's picture
Upload 49 files
24fd742 verified
# 优化版多阶段构建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"]