容器化部署架构
1 ) 关键配置文件
-
Dockerfile:定义镜像构建流程(生产依赖安装 → 应用构建 → 最终镜像生成) -
.dockerignore:排除非必要文件,缩小镜像体积 -
核心优化:
dockerfile# 使用轻量级基础镜像 (Alpine) FROM node:18-alpine AS production WORKDIR /app COPY package*.json ./ RUN npm ci --only=production # 仅安装生产依赖 # 构建阶段 FROM node:18-alpine AS build WORKDIR /app COPY . . RUN npm run build # 执行项目构建 # 最终镜像 FROM production COPY --from=build /app/dist ./dist # 仅复制构建产物 EXPOSE 3000 CMD ["node", "dist/main"]优势:
- 最终镜像不含构建缓存,体积减少约60%
- 阶段隔离保障生产环境纯净性
2 ) Docker Compose编排
yaml
version: '3.8'
services:
main: # 主服务
build:
context: ./app/main # Dockerfile路径
restart: always
env_file: ./.env # 加载环境变量
ports:
- "3000:3000" # 端口映射
client: # 客户端服务
build:
context: ./app/client
restart: always
env_file: ./.env
ports:
- "3001:3001"
depends_on:
- main
启动命令:
bash
docker-compose up --build -d # 强制重建镜像并后台运行
依赖管理与构建问题解决
1 ) Monorepo依赖冲突
-
问题根源:子项目存在独立
package-lock.json导致依赖不一致 -
修复方案:
bash# 删除所有子项目锁文件 rm -f ./app/main/package-lock.json ./app/client/package-lock.json # 在根目录统一安装依赖 npm install -
调整
Dockerfile:dockerfile# 删除以下冗余指令 COPY package-lock.json ./ # 移除锁文件拷贝
2 ) 环境变量动态注入
-
.env文件配置:envNODE_ENV=production SERVICE_HOST=main # 容器内通信使用服务名 -
客户端动态主机配置:
typescript// app.module.ts (client) @Module({ imports: [ ClientsModule.register([{ name: 'MAIN_SERVICE', transport: Transport.TCP, options: { host: process.env.SERVICE_HOST || 'localhost', // 动态解析主机 port: 3000 } }]) ] }) export class AppModule {}
网络通信与安全实践
1 ) 容器间通信机制
-
无需暴露端口:同一Compose网络内通过服务名称直接访问
typescript// Client 调用 Main 服务 this.client.send({ cmd: 'REQUEST' }, 'MAIN_SERVICE'); -
网络隔离拓扑:
外部请求 Client:3001 内部网络 Main:3000
2 ) 跨域安全强化
-
生产环境加密方案:
yaml# docker-compose.yml 扩展 services: main: networks: micro-net: aliases: - main.internal # 内部域名 -
TLS加密通信(可选):
typescript// 启用加密传输 transport: Transport.TCP, options: { tls: { cert: readFileSync('cert.pem'), key: readFileSync('key.pem') } }
3 ) NestJS 微服务客户端代码示例:
typescript
// client/src/app.module.ts
import { ClientsModule, Transport } from '@nestjs/microservices';
@Module({
imports: [
ClientsModule.register([
{
name: 'MAIN_SERVICE',
transport: Transport.TCP,
options: {
host: process.env.NODE_ENV === 'production' ? 'main' : 'localhost',
port: 3000,
},
},
]),
],
})
export class AppModule {}
typescript
// client/src/app.controller.ts
import { Controller, Get, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
@Controller()
export class AppController {
constructor(@Inject('MAIN_SERVICE') private readonly client: ClientProxy) {}
@Get()
async getData() {
return this.client.send({ cmd: 'fetchData' }, {}).toPromise();
}
}
-
网络安全实践:
- 仅暴露网关端口(如
client的3001),内部服务(如main)不直接映射到宿主机。 - 跨集群通信需使用 TLS 加密(需运维工具辅助,避免手动配置证书)。
- 仅暴露网关端口(如
-
端到端测试:
- 启动服务:
docker-compose up -d。 - 验证通信:访问
client端口(http://localhost:3001)应返回main服务的响应。 - 关键结论:同一 Docker Compose 网络中的服务可通过服务名互访,实现安全隔离。
- 启动服务:
部署验证流程
1 ) 启动与监控
bash
docker-compose up -d --build # 构建并启动
docker ps # 验证容器状态
2 ) 服务测试
| 测试目标 | 访问方式 | 预期响应 |
|---|---|---|
| Client服务 | http://localhost:3001 |
调用Main服务返回数据 |
| Main服务 | 内部端口main:3000 |
不直接暴露,仅限内部访问 |
3 ) 问题排查路径
bash
# 查看容器日志
docker logs -f workspace-client-1
# 进入容器诊断
docker exec -it workspace-main-1 sh
curl http://localhost:3000/health # 服务健康检查
核心总结
1 ) 容器化最佳实践
- 多阶段构建:分离开发/生产依赖,镜像体积缩减至200MB以下
- 依赖治理:Monorepo项目需统一锁文件管理
- 动态配置:通过
.env实现环境无感切换
2 ) 微服务通信铁律
- 内部服务互访:通过 Docker Compose 服务名称直接通信
- 外部暴露控制:仅网关类服务开放端口,内部服务隔离运行
- 安全基线:生产环境强制启用 TLS 或服务网格加密
3 ) 运维提效
docker-compose.yml统一管理服务生命周期- 容器日志集中采集(ELK/Sentry)
- 异地部署时采用 Kubernetes 管理容器集群