Appearance
部署 Node.js
示例应用
javascript
// app.js
const http = require('http');
const PORT = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({ status: 'ok' }));
return;
}
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello from Node.js in Docker!\n');
});
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
});Dockerfile
dockerfile
FROM node:20-alpine
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 先复制依赖文件(利用缓存)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 复制应用代码
COPY --chown=appuser:appgroup . .
USER appuser
ENV NODE_ENV=production \
PORT=3000
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "app.js"]构建和运行
bash
# 构建镜像
docker build -t mynode-app:1.0 .
# 运行容器
docker run -d \
--name mynode-app \
--restart unless-stopped \
-p 3000:3000 \
-e NODE_ENV=production \
mynode-app:1.0
# 测试
curl http://localhost:3000
curl http://localhost:3000/healthExpress 应用 Dockerfile
dockerfile
# 多阶段构建(含 TypeScript)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runtime
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package.json .
USER app
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "dist/app.js"]开发环境(热更新)
yaml
# docker-compose.dev.yml
services:
app:
build:
context: .
target: deps
command: npx nodemon --watch src src/app.js
volumes:
- ./src:/app/src
- ./package.json:/app/package.json
ports:
- "3000:3000"
environment:
NODE_ENV: developmentDocker Compose(生产)
yaml
services:
app:
build:
context: .
target: runtime
restart: unless-stopped
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: mysql
depends_on:
mysql:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping"]
interval: 10s
retries: 5
volumes:
mysql-data:常见问题
端口绑定
Node.js 应用在容器内需要监听 0.0.0.0 而非 127.0.0.1:
javascript
server.listen(PORT, '0.0.0.0', () => {
console.log(`Server listening on 0.0.0.0:${PORT}`);
});环境变量配置
通过 -e 或 Compose 的 environment 传入,不要将 .env 文件打包进镜像。