File size: 5,287 Bytes
24fd742 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# 优化版多阶段构建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"]
|