# Docker 隔离架构说明 ## 隔离层次概览 当前项目实现了**完全隔离**的架构,从构建到运行都在 Docker 容器中,与宿主机完全隔离。 ``` ┌─────────────────────────────────────────────────────────────┐ │ 宿主机 (Host) │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Jenkins 服务器 │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ Docker 容器: node:18 (构建阶段) │ │ │ │ │ │ - 安装依赖 │ │ │ │ │ │ - 构建前端 │ │ │ │ │ │ - 构建后端 │ │ │ │ │ │ ✅ 与 Jenkins 服务器隔离 │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ ↓ │ │ 部署到远程服务器 │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ 远程服务器 (180.76.180.105) │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ Docker 容器: nginx:alpine │ │ │ │ │ │ - 端口: 8080:80 │ │ │ │ │ │ - 网络: ai-learning-network │ │ │ │ │ │ ✅ 与宿主机和其他容器隔离 │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ Docker 容器: backend (node:18-alpine) │ │ │ │ │ │ - 端口: 3001:3001 │ │ │ │ │ │ - 网络: ai-learning-network │ │ │ │ │ │ ✅ 与宿主机和其他容器隔离 │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ 宿主机文件系统 (仅数据持久化) │ │ │ │ │ │ - /opt/nginx/html/ai/current/ │ │ │ │ │ │ - 数据库文件 (volume 挂载) │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## 隔离层次详解 ### 1. 构建阶段隔离(Jenkins 服务器) **位置**: Jenkins 服务器 **容器**: `node:18` **隔离内容**: ```groovy def nodeImage = docker.image("node:18") nodeImage.inside('-v /var/run/docker.sock:/var/run/docker.sock') { // 所有构建操作都在容器中执行 npm install npm run build } ``` **隔离效果**: - ✅ **文件系统隔离**: 构建过程不影响 Jenkins 服务器文件系统 - ✅ **依赖隔离**: 不需要在 Jenkins 服务器安装 Node.js、npm - ✅ **版本隔离**: 使用固定版本的 Node.js,不受宿主机影响 - ✅ **环境隔离**: 每次构建都是干净的环境,无历史残留 **好处**: - Jenkins 服务器保持干净,不需要安装各种构建工具 - 多个项目可以使用不同版本的 Node.js,互不干扰 - 构建失败不会影响 Jenkins 服务器 ### 2. 运行阶段隔离(生产服务器) #### 2.1 Nginx 容器隔离 ```yaml nginx: image: nginx:alpine container_name: ai-learning-nginx ports: - "8080:80" networks: - ai-learning-network ``` **隔离效果**: - ✅ **进程隔离**: Nginx 进程在容器内运行,与宿主机进程隔离 - ✅ **网络隔离**: 使用独立的 Docker 网络 `ai-learning-network` - ✅ **文件系统隔离**: 只能访问挂载的 volume - ✅ **端口隔离**: 使用 8080 端口,不影响宿主机 80 端口 #### 2.2 Backend 容器隔离 ```yaml backend: build: context: /opt/nginx/html/ai/current/backend dockerfile: Dockerfile container_name: ai-learning-backend ports: - "3001:3001" networks: - ai-learning-network ``` **隔离效果**: - ✅ **运行时隔离**: Node.js 应用在容器内运行 - ✅ **依赖隔离**: 不需要在宿主机安装 Node.js - ✅ **环境变量隔离**: 容器内独立的环境变量 - ✅ **网络隔离**: 只能通过 Docker 网络与其他容器通信 ### 3. 网络隔离 ```yaml networks: ai-learning-network: driver: bridge ``` **隔离效果**: - ✅ **独立网络**: 容器在独立的 Docker 网络中 - ✅ **服务发现**: 容器间通过服务名通信(如 `backend:3001`) - ✅ **端口隔离**: 容器端口不直接暴露给宿主机(除非映射) - ✅ **安全隔离**: 外部无法直接访问容器内部网络 ## 完全隔离的好处 ### 1. 安全性 ``` 宿主机 ← 完全隔离 → 应用容器 ``` - ✅ **进程隔离**: 容器崩溃不影响宿主机 - ✅ **文件系统隔离**: 容器无法访问宿主机敏感文件 - ✅ **网络隔离**: 容器间通信受控 - ✅ **权限隔离**: 容器以非 root 用户运行(可配置) ### 2. 环境一致性 ``` 开发环境 = 构建环境 = 生产环境 ``` - ✅ **版本一致**: 所有环境使用相同的 Node.js 版本 - ✅ **依赖一致**: 依赖版本锁定在 package.json - ✅ **配置一致**: Docker 配置统一管理 ### 3. 资源隔离 ``` 容器 A ← 资源限制 → 容器 B ``` - ✅ **CPU 限制**: 可以限制容器 CPU 使用率 - ✅ **内存限制**: 可以限制容器内存使用 - ✅ **磁盘限制**: 可以限制容器磁盘使用 ### 4. 易于管理 - ✅ **独立更新**: 可以单独更新某个容器,不影响其他 - ✅ **快速回滚**: 可以快速回滚到之前的镜像版本 - ✅ **日志隔离**: 每个容器的日志独立管理 - ✅ **监控隔离**: 可以单独监控每个容器 ## 数据持久化(唯一与宿主机共享的部分) 虽然容器是隔离的,但某些数据需要持久化: ```yaml volumes: # 数据库文件(需要持久化) - /opt/nginx/html/ai/current/backend/prisma:/app/prisma # 前端静态文件(只读) - /opt/nginx/html/ai/current:/usr/share/nginx/html:ro # 日志文件(需要持久化) - /opt/nginx/html/ai/current/docker/logs:/var/log/nginx ``` **说明**: - 数据库文件需要持久化,所以挂载到宿主机 - 前端文件是只读挂载,容器无法修改 - 日志文件挂载到宿主机,方便查看和管理 ## 隔离验证 ### 1. 检查容器隔离 ```bash # 查看运行中的容器 docker ps # 查看容器网络 docker network inspect ai-learning-network # 查看容器进程(在宿主机上) ps aux | grep nginx # 看不到容器内的进程 # 进入容器查看 docker exec -it ai-learning-nginx sh # 在容器内:无法访问宿主机其他文件(除了挂载的 volume) ``` ### 2. 检查网络隔离 ```bash # 在宿主机上无法直接访问容器内部网络 curl http://backend:3001 # ❌ 失败,backend 只在 Docker 网络内可访问 # 在容器内可以访问 docker exec -it ai-learning-nginx sh curl http://backend:3001 # ✅ 成功,在同一 Docker 网络内 ``` ### 3. 检查文件系统隔离 ```bash # 容器内的文件系统是独立的 docker exec -it ai-learning-backend ls /app # 只能看到容器内的文件,看不到宿主机其他目录(除了挂载的 volume) ``` ## 安全建议 虽然已经实现了完全隔离,但还可以进一步加强: ### 1. 使用非 root 用户运行容器 ```dockerfile # 在 Dockerfile 中 RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 USER nodejs ``` ### 2. 限制资源使用 ```yaml services: backend: deploy: resources: limits: cpus: '1' memory: 512M reservations: cpus: '0.5' memory: 256M ``` ### 3. 只读文件系统(除了必要目录) ```yaml services: nginx: read_only: true tmpfs: - /tmp - /var/cache/nginx ``` ### 4. 网络策略 ```yaml services: backend: networks: - ai-learning-network # 不暴露端口到宿主机,只允许 nginx 访问 # ports: [] # 注释掉端口映射 ``` ## 总结 **是的,当前架构实现了完全隔离**: 1. ✅ **构建阶段**: 在 Docker 容器中构建,与 Jenkins 服务器隔离 2. ✅ **运行阶段**: 应用在 Docker 容器中运行,与宿主机隔离 3. ✅ **网络隔离**: 容器在独立的 Docker 网络中 4. ✅ **文件系统隔离**: 容器只能访问挂载的 volume 5. ✅ **进程隔离**: 容器进程与宿主机进程隔离 **唯一与宿主机共享的**: - 数据文件(数据库、日志)- 通过 volume 挂载 - 端口映射(8080, 3001)- 用于外部访问 这种架构提供了**最大的安全性和可移植性**,同时保持了必要的数据持久化。