找回密码
 立即注册

QQ登录

只需一步,快速开始

peUfSYR.png
查看: 31|回复: 0

Day 08 编写你的第一个Dockerfile:Node.js应用容器化实战

[复制链接]

876

主题

13

回帖

2808

积分

管理员

积分
2808
发表于 2026-3-29 16:16:41 | 显示全部楼层 |阅读模式
今天我们要完成一个重要任务:从零开始编写Dockerfile,将一个真实的Node.js应用打包成Docker镜像。

你将学会
  • ✅ 理解Dockerfile的核心语法和最佳实践
  • ✅ 掌握FROM、RUN、COPY、CMD等关键指令
  • ✅ 独立完成Node.js应用的容器化
  • ✅ 优化镜像大小和构建速度

    难度等级:⭐⭐⭐☆☆(进阶实践)

    所需时间:约 30-40 分钟

    前置要求
  • 已安装Docker(参考Day 2)
  • 了解基本的Linux命令
  • 具备Node.js基础知识(可选)

    准备好了吗?让我们开始构建自己的第一个Docker镜像!

    ━━━━━━━━━━━━━━━━━━━━

    🛠️ 环境准备

    在开始之前,请确保你的环境满足以下要求:

    系统要求

    | 项目 | 要求 | 检查方法 |
    |------|------|----------|
    | 操作系统 | macOS 10.15+ / Windows 10+ / Linux | - |
    | Docker版本 | 20.10+ |
    1. docker --version
    复制代码
    |
    | 内存 | 至少 4GB | - |
    | 磁盘空间 | 至少 2GB | - |

    检查命令
    1. # 检查Docker是否安装
    2. docker --version
    3. # 检查Docker是否运行
    4. docker ps
    5. # 查看Docker系统信息
    6. docker info
    复制代码

    如果以上命令报错,请先阅读 [Day 2 - Docker安装指南]。

    准备工作目录
    1. # 创建项目目录
    2. mkdir -p ~/docker-practice/day08-nodejs-app
    3. cd ~/docker-practice/day08-nodejs-app
    4. # 创建应用目录结构
    5. mkdir -p src public
    复制代码

    ✅ 环境准备完成,开始正式操作!

    ━━━━━━━━━━━━━━━━━━━━

    📖 操作步骤

    步骤1:创建Node.js示例应用

    目标:准备一个简单但完整的Web应用用于容器化

    创建package.json
    1. cat > package.json << 'EOF'
    2. {
    3.   "name": "docker-nodejs-demo",
    4.   "version": "1.0.0",
    5.   "description": "Docker Node.js示例应用",
    6.   "main": "src/server.js",
    7.   "scripts": {
    8.     "start": "node src/server.js",
    9.     "dev": "nodemon src/server.js"
    10.   },
    11.   "dependencies": {
    12.     "express": "^4.18.2"
    13.   },
    14.   "devDependencies": {
    15.     "nodemon": "^3.0.1"
    16.   }
    17. }
    18. EOF
    复制代码

    创建应用主文件
    1. cat > src/server.js << 'EOF'
    2. const express = require('express');
    3. const app = express();
    4. const PORT = process.env.PORT || 3000;
    5. // 静态文件服务
    6. app.use(express.static('public'));
    7. // API路由
    8. app.get('/api/health', (req, res) => {
    9.   res.json({
    10.     status: 'healthy',
    11.     timestamp: new Date().toISOString(),
    12.     environment: process.env.NODE_ENV || 'development'
    13.   });
    14. });
    15. app.get('/api/info', (req, res) => {
    16.   res.json({
    17.     app: 'Docker Node.js Demo',
    18.     version: '1.0.0',
    19.     node: process.version,
    20.     platform: process.platform
    21.   });
    22. });
    23. // 启动服务器
    24. app.listen(PORT, '0.0.0.0', () => {
    25.   console.log(`🚀 Server running on http://0.0.0.0:${PORT}`);
    26.   console.log(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
    27. });
    28. EOF
    复制代码

    创建前端页面
    1. cat > public/index.html << 'EOF'
    2. <!DOCTYPE html>
    3. <html lang="zh-CN">
    4. <head>
    5.     <meta charset="UTF-8">
    6.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7.     <title>Docker Node.js Demo</title>
    8.     <style>
    9.         body {
    10.             font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
    11.             max-width: 800px;
    12.             margin: 50px auto;
    13.             padding: 20px;
    14.             background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    15.             color: white;
    16.         }
    17.         .container {
    18.             background: rgba(255,255,255,0.1);
    19.             padding: 30px;
    20.             border-radius: 10px;
    21.             backdrop-filter: blur(10px);
    22.         }
    23.         h1 { margin-top: 0; }
    24.         button {
    25.             background: #4CAF50;
    26.             color: white;
    27.             border: none;
    28.             padding: 10px 20px;
    29.             margin: 5px;
    30.             cursor: pointer;
    31.             border-radius: 5px;
    32.             font-size: 16px;
    33.         }
    34.         button:hover { background: #45a049; }
    35.         #result {
    36.             margin-top: 20px;
    37.             padding: 15px;
    38.             background: rgba(0,0,0,0.2);
    39.             border-radius: 5px;
    40.             font-family: monospace;
    41.         }
    42.     </style>
    43. </head>
    44. <body>
    45.     <div class="container">
    46.         <h1>🐳 Docker + Node.js 演示应用</h1>
    47.         <p>这是一个运行在Docker容器中的Node.js应用</p>
    48.         <div>
    49.             <button onclick="checkHealth()">健康检查</button>
    50.             <button onclick="getInfo()">获取信息</button>
    51.         </div>
    52.         <div id="result"></div>
    53.     </div>
    54.     <script>
    55.         async function checkHealth() {
    56.             const res = await fetch('/api/health');
    57.             const data = await res.json();
    58.             document.getElementById('result').innerHTML =
    59.                 `<strong>健康状态:</strong><br>${JSON.stringify(data, null, 2)}`;
    60.         }
    61.         async function getInfo() {
    62.             const res = await fetch('/api/info');
    63.             const data = await res.json();
    64.             document.getElementById('result').innerHTML =
    65.                 `<strong>应用信息:</strong><br>${JSON.stringify(data, null, 2)}`;
    66.         }
    67.     </script>
    68. </body>
    69. </html>
    70. EOF
    复制代码

    验证应用结构
    1. # 查看目录结构
    2. tree .
    3. # 或使用
    4. ls -R
    复制代码

    预期输出
    1. .
    2. ├── package.json
    3. ├── public
    4. │   └── index.html
    5. └── src
    6.     └── server.js
    复制代码

    检查点:确认所有文件已创建完成

    ━━━━━━━━━━━━━━━━━━━━

    步骤2:编写基础Dockerfile

    目标:创建第一个Dockerfile,理解核心指令

    创建Dockerfile
    1. cat > Dockerfile << 'EOF'
    2. # 第1步:选择基础镜像
    3. FROM node:18-alpine
    4. # 第2步:设置工作目录
    5. WORKDIR /app
    6. # 第3步:复制package.json
    7. COPY package*.json ./
    8. # 第4步:安装依赖
    9. RUN npm install --production
    10. # 第5步:复制应用代码
    11. COPY . .
    12. # 第6步:暴露端口
    13. EXPOSE 3000
    14. # 第7步:定义启动命令
    15. CMD ["npm", "start"]
    16. EOF
    复制代码

    Dockerfile指令详解

    | 指令 | 作用 | 示例 |
    |------|------|------|
    |
    1. FROM
    复制代码
    | 指定基础镜像 |
    1. FROM node:18-alpine
    复制代码
    |
    |
    1. WORKDIR
    复制代码
    | 设置工作目录 |
    1. WORKDIR /app
    复制代码
    |
    |
    1. COPY
    复制代码
    | 复制文件到镜像 |
    1. COPY . .
    复制代码
    |
    |
    1. RUN
    复制代码
    | 执行命令(构建时) |
    1. RUN npm install
    复制代码
    |
    |
    1. EXPOSE
    复制代码
    | 声明端口 |
    1. EXPOSE 3000
    复制代码
    |
    |
    1. CMD
    复制代码
    | 容器启动命令 |
    1. CMD ["npm", "start"]
    复制代码
    |

    关键概念解释

  • FROM node:18-alpine
    1. node:18
    复制代码
    :使用Node.js 18版本
    1. alpine
    复制代码
    :基于Alpine Linux(体积小,约5MB)
  • 为什么选alpine?体积小,安全性高,启动快

  • WORKDIR /app
  • 在容器内创建/app目录
  • 后续所有操作都在此目录进行
  • 相当于
    1. RUN mkdir /app && cd /app
    复制代码

  • 分层复制的技巧
    1.    COPY package*.json ./    # 先复制依赖文件
    2.    RUN npm install          # 安装依赖
    3.    COPY . .                 # 再复制代码
    复制代码
  • 利用Docker缓存机制
  • 代码变更时不会重新安装依赖

  • CMD vs RUN
    1. RUN
    复制代码
    :构建镜像时执行(如安装软件)
    1. CMD
    复制代码
    :容器启动时执行(如启动应用)

    检查点:Dockerfile已创建,理解每行指令的作用

    ━━━━━━━━━━━━━━━━━━━━

    步骤3:构建Docker镜像

    目标:将应用打包成Docker镜像

    构建命令
    1. # 基础构建命令
    2. docker build -t my-nodejs-app:1.0 .
    3. # 参数说明:
    4. # -t: 指定镜像名称和标签
    5. # my-nodejs-app: 镜像名称
    6. # 1.0: 版本标签
    7. # .: 构建上下文(当前目录)
    复制代码

    构建过程输出
    1. [+] Building 45.2s (10/10) FINISHED
    2. => [internal] load build definition from Dockerfile            0.0s
    3. => => transferring dockerfile: 285B                            0.0s
    4. => [internal] load .dockerignore                               0.0s
    5. => [internal] load metadata for docker.io/library/node:18-...  1.2s
    6. => [1/5] FROM docker.io/library/node:18-alpine@sha256:...     5.3s
    7. => [internal] load build context                               0.1s
    8. => => transferring context: 2.45kB                             0.0s
    9. => [2/5] WORKDIR /app                                          0.2s
    10. => [3/5] COPY package*.json ./                                 0.0s
    11. => [4/5] RUN npm install --production                         35.8s
    12. => [5/5] COPY . .                                              0.1s
    13. => exporting to image                                          2.5s
    14. => => exporting layers                                         2.5s
    15. => => writing image sha256:abc123...                           0.0s
    16. => => naming to docker.io/library/my-nodejs-app:1.0            0.0s
    复制代码

    验证镜像
    1. # 查看镜像列表
    2. docker images | grep my-nodejs-app
    复制代码

    预期输出
    1. my-nodejs-app   1.0    abc123def456   2 minutes ago   180MB
    复制代码

    常见错误 ⚠️

    错误1
    1. package.json not found
    复制代码
    1. ERROR [3/5] COPY package*.json ./
    复制代码
    原因:构建上下文路径错误
    解决:确保在项目根目录执行构建命令

    错误2
    1. npm install
    复制代码
    失败
    1. npm ERR! network request failed
    复制代码
    原因:网络问题或npm源问题
    解决
    1. # 在RUN npm install前添加
    2. RUN npm config set registry https://registry.npmmirror.com
    复制代码

    错误3:构建很慢
    原因:未使用国内镜像源
    解决:配置Docker镜像加速器(参考Day 2)

    检查点:成功构建镜像,docker images可以看到新镜像

    ━━━━━━━━━━━━━━━━━━━━

    步骤4:运行容器并测试

    目标:启动容器并验证应用功能

    运行容器
    1. # 运行容器
    2. docker run -d \
    3.   --name nodejs-demo \
    4.   -p 3000:3000 \
    5.   my-nodejs-app:1.0
    6. # 参数说明:
    7. # -d: 后台运行
    8. # --name: 容器名称
    9. # -p 3000:3000: 端口映射(主机:容器)
    10. # my-nodejs-app:1.0: 使用的镜像
    复制代码

    查看容器状态
    1. # 查看运行中的容器
    2. docker ps
    3. # 查看容器日志
    4. docker logs nodejs-demo
    复制代码

    预期日志输出
    1. 🚀 Server running on http://0.0.0.0:3000
    2. 📝 Environment: development
    复制代码

    测试应用
    1. # 测试健康检查接口
    2. curl http://localhost:3000/api/health
    3. # 测试信息接口
    4. curl http://localhost:3000/api/info
    5. # 或在浏览器打开
    6. # http://localhost:3000
    复制代码

    预期API响应
    1. // /api/health
    2. {
    3.   "status": "healthy",
    4.   "timestamp": "2024-01-15T10:30:00.000Z",
    5.   "environment": "development"
    6. }
    7. // /api/info
    8. {
    9.   "app": "Docker Node.js Demo",
    10.   "version": "1.0.0",
    11.   "node": "v18.19.0",
    12.   "platform": "linux"
    13. }
    复制代码

    进入容器内部
    1. # 进入容器shell
    2. docker exec -it nodejs-demo sh
    3. # 在容器内执行命令
    4. pwd              # 查看当前目录
    5. ls -la           # 查看文件
    6. ps aux           # 查看进程
    7. exit             # 退出容器
    复制代码

    🎉 恭喜! 你已经成功完成了第一个Dockerfile的编写和镜像构建!

    ━━━━━━━━━━━━━━━━━━━━

    步骤5:优化Dockerfile

    目标:使用最佳实践优化镜像大小和构建速度

    创建.dockerignore文件
    1. cat > .dockerignore << 'EOF'
    2. node_modules
    3. npm-debug.log
    4. .git
    5. .gitignore
    6. README.md
    7. .env
    8. .DS_Store
    9. *.md
    10. .vscode
    11. coverage
    12. .npm
    13. EOF
    复制代码

    创建优化版Dockerfile
    1. cat > Dockerfile.optimized << 'EOF'
    2. # 使用多阶段构建
    3. FROM node:18-alpine AS builder
    4. # 设置工作目录
    5. WORKDIR /app
    6. # 复制依赖文件
    7. COPY package*.json ./
    8. # 安装所有依赖(包括devDependencies)
    9. RUN npm ci --only=production && npm cache clean --force
    10. # 最终镜像
    11. FROM node:18-alpine
    12. # 添加元数据标签
    13. LABEL maintainer="your-email@example.com"
    14. LABEL version="1.0"
    15. LABEL description="Docker Node.js Demo Application"
    16. # 创建非root用户
    17. RUN addgroup -g 1001 -S nodejs && \
    18.     adduser -S nodejs -u 1001
    19. # 设置工作目录
    20. WORKDIR /app
    21. # 从builder阶段复制依赖
    22. COPY --from=builder /app/node_modules ./node_modules
    23. # 复制应用代码
    24. COPY --chown=nodejs:nodejs . .
    25. # 切换到非root用户
    26. USER nodejs
    27. # 暴露端口
    28. EXPOSE 3000
    29. # 健康检查
    30. HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    31.   CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
    32. # 启动命令
    33. CMD ["node", "src/server.js"]
    34. EOF
    复制代码

    优化要点说明

  • 多阶段构建
  • 分离构建环境和运行环境
  • 减小最终镜像体积

  • 使用npm ci
    1.    RUN npm ci --only=production && npm cache clean --force
    复制代码
    1. npm ci
    复制代码
    :更快、更可靠的安装方式
    1. --only=production
    复制代码
    :只安装生产依赖
    1. npm cache clean
    复制代码
    :清理缓存

  • 创建非root用户
    1.    RUN adduser -S nodejs -u 1001
    2.    USER nodejs
    复制代码
  • 提高容器安全性
  • 避免使用root权限运行应用

  • 添加健康检查
    1.    HEALTHCHECK --interval=30s --timeout=3s \
    2.      CMD node -e "..."
    复制代码
  • 自动检测容器健康状态
  • 便于容器编排系统管理

    构建优化版镜像
    1. # 构建优化版镜像
    2. docker build -f Dockerfile.optimized -t my-nodejs-app:1.1-optimized .
    3. # 对比镜像大小
    4. docker images | grep my-nodejs-app
    复制代码

    预期对比
    1. my-nodejs-app   1.1-optimized   xyz789   1 minute ago    125MB
    2. my-nodejs-app   1.0             abc123   10 minutes ago  180MB
    复制代码

    性能对比测试
    1. # 停止旧容器
    2. docker stop nodejs-demo
    3. docker rm nodejs-demo
    4. # 运行优化版
    5. docker run -d \
    6.   --name nodejs-demo-v2 \
    7.   -p 3000:3000 \
    8.   my-nodejs-app:1.1-optimized
    9. # 查看健康状态
    10. docker ps
    11. # STATUS列会显示健康状态
    复制代码

    检查点:优化版镜像体积减小30%以上,安全性提升

    ━━━━━━━━━━━━━━━━━━━━

    💻 完整代码

    为了方便你快速上手,这里提供完整的项目结构和配置文件。

    目录结构
    1. day08-nodejs-app/
    2. ├── Dockerfile                 # 基础版Dockerfile
    3. ├── Dockerfile.optimized       # 优化版Dockerfile
    4. ├── .dockerignore             # Docker忽略文件
    5. ├── package.json              # Node.js依赖配置
    6. ├── docker-compose.yml        # 容器编排配置
    7. ├── public/
    8. │   └── index.html           # 前端页面
    9. └── src/
    10.     └── server.js            # 应用主文件
    复制代码

    docker-compose.yml
    1. version: '3.8'
    2. services:
    3.   app:
    4.     build:
    5.       context: .
    6.       dockerfile: Dockerfile.optimized
    7.     image: my-nodejs-app:1.1-optimized
    8.     container_name: nodejs-demo
    9.     ports:
    10.       - "3000:3000"
    11.     environment:
    12.       - NODE_ENV=production
    13.       - PORT=3000
    14.     restart: unless-stopped
    15.     healthcheck:
    16.       test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
    17.       interval: 30s
    18.       timeout: 3s
    19.       retries: 3
    20.       start_period: 5s
    21.     networks:
    22.       - app-network
    23. networks:
    24.   app-network:
    25.     driver: bridge
    复制代码

    Makefile(便捷操作)
    1. cat > Makefile << 'EOF'
    2. .PHONY: build run stop clean logs shell test
    3. # 构建镜像
    4. build:
    5.         docker build -f Dockerfile.optimized -t my-nodejs-app:1.1-optimized .
    6. # 使用docker-compose启动
    7. up:
    8.         docker-compose up -d
    9. # 停止服务
    10. down:
    11.         docker-compose down
    12. # 查看日志
    13. logs:
    14.         docker-compose logs -f
    15. # 进入容器
    16. shell:
    17.         docker exec -it nodejs-demo sh
    18. # 测试应用
    19. test:
    20.         @echo "Testing health endpoint..."
    21.         @curl -s http://localhost:3000/api/health | jq
    22.         @echo "\nTesting info endpoint..."
    23.         @curl -s http://localhost:3000/api/info | jq
    24. # 清理资源
    25. clean:
    26.         docker-compose down -v
    27.         docker rmi my-nodejs-app:1.1-optimized
    28. # 重新构建并启动
    29. rebuild: clean build up
    30.         @echo "✅ Rebuild complete!"
    31. EOF
    复制代码

    一键运行脚本
    1. cat > run.sh << 'EOF'
    2. #!/bin/bash
    3. set -e
    4. echo "🐳 Docker Node.js Demo - 一键启动脚本"
    5. echo "===================================="
    6. # 检查Docker是否运行
    7. if ! docker info > /dev/null 2>&1; then
    8.     echo "❌ Docker未运行,请先启动Docker"
    9.     exit 1
    10. fi
    11. # 构建镜像
    12. echo "📦 构建Docker镜像..."
    13. docker build -f Dockerfile.optimized -t my-nodejs-app:1.1-optimized .
    14. # 停止并删除旧容器
    15. echo "🧹 清理旧容器..."
    16. docker stop nodejs-demo 2>/dev/null || true
    17. docker rm nodejs-demo 2>/dev/null || true
    18. # 启动容器
    19. echo "🚀 启动容器..."
    20. docker run -d \
    21.   --name nodejs-demo \
    22.   -p 3000:3000 \
    23.   -e NODE_ENV=production \
    24.   my-nodejs-app:1.1-optimized
    25. # 等待服务启动
    26. echo "⏳ 等待服务启动..."
    27. sleep 3
    28. # 检查容器状态
    29. if docker ps | grep -q nodejs-demo; then
    30.     echo "✅ 服务启动成功!"
    31.     echo ""
    32.     echo "📍 访问地址:"
    33.     echo "   Web界面: http://localhost:3000"
    34.     echo "   健康检查: http://localhost:3000/api/health"
    35.     echo "   应用信息: http://localhost:3000/api/info"
    36.     echo ""
    37.     echo "📝 查看日志: docker logs -f nodejs-demo"
    38.     echo "🔍 进入容器: docker exec -it nodejs-demo sh"
    39.     echo "🛑 停止服务: docker stop nodejs-demo"
    40. else
    41.     echo "❌ 服务启动失败,查看日志:"
    42.     docker logs nodejs-demo
    43.     exit 1
    44. fi
    45. EOF
    46. chmod +x run.sh
    复制代码

    使用方法
    1. # 方式1: 使用一键脚本
    2. ./run.sh
    3. # 方式2: 使用Makefile
    4. make build    # 构建镜像
    5. make up       # 启动服务
    6. make logs     # 查看日志
    7. make test     # 测试接口
    8. make down     # 停止服务
    9. # 方式3: 使用docker-compose
    10. docker-compose up -d
    11. docker-compose logs -f
    12. docker-compose down
    复制代码

    📦 代码仓库GitHub - docker-30days-day08

    ━━━━━━━━━━━━━━━━━━━━

    🚀 进阶实践

    掌握了基础操作后,试试这些进阶玩法:

    实践1:添加环境变量配置

    目标:通过环境变量管理应用配置

    提示
  • 创建
    1. .env
    复制代码
    文件存储环境变量
  • 在Dockerfile中使用
    1. ENV
    复制代码
    指令设置默认值
  • 使用
    1. ARG
    复制代码
    指令接收构建参数
  • 在docker run时使用
    1. -e
    复制代码
    1. --env-file
    复制代码
    传递变量

    参考代码片段
    1. # Dockerfile中
    2. ARG NODE_ENV=production
    3. ENV NODE_ENV=${NODE_ENV}
    4. ENV APP_PORT=3000
    5. # 运行时
    6. docker run -e NODE_ENV=development -e APP_PORT=8080 ...
    复制代码

    检查清单
  • [ ] 应用能读取环境变量
  • [ ] 不同环境使用不同配置
  • [ ] 敏感信息不写入镜像

    ━━━━━━━━━━━━━━━━━━━━

    实践2:实现热重载开发环境

    目标:创建开发版Dockerfile,支持代码热重载

    建议
  • 创建
    1. Dockerfile.dev
    复制代码
  • 使用volume挂载代码目录
  • 安装nodemon实现自动重启
  • 配置不同的启动命令

    思路提示
    1. # Dockerfile.dev
    2. FROM node:18-alpine
    3. WORKDIR /app
    4. COPY package*.json ./
    5. RUN npm install  # 安装包括devDependencies
    6. COPY . .
    7. CMD ["npm", "run", "dev"]
    复制代码
    1. # 运行开发环境
    2. docker run -v $(pwd):/app -p 3000:3000 my-app:dev
    复制代码

    验证方式
  • 修改代码文件
  • 容器内应用自动重启
  • 无需重新构建镜像

    ━━━━━━━━━━━━━━━━━━━━

    实践3:构建生产级多架构镜像

    目标:构建支持AMD64和ARM64的多架构镜像

    挑战任务
  • 使用
    1. docker buildx
    复制代码
    构建多架构镜像
  • 支持Linux/AMD64和Linux/ARM64
  • 推送到Docker Hub

    参考命令
    1. # 创建builder
    2. docker buildx create --name multiarch --use
    3. # 构建多架构镜像
    4. docker buildx build \
    5.   --platform linux/amd64,linux/arm64 \
    6.   -t username/my-nodejs-app:1.1 \
    7.   --push .
    复制代码

    资源
  • Docker Buildx文档
  • 多架构镜像最佳实践

    💡 提示:完成这些实践后,在评论区分享你的成果和遇到的问题!

    ━━━━━━━━━━━━━━━━━━━━

    🐛 故障排查

    问题1:COPY失败 - no such file or directory

    症状
    1. ERROR [4/6] COPY package*.json ./
    2. failed to compute cache key: "/package.json" not found
    复制代码

    原因:构建上下文中找不到文件

    解决方案

    检查1:确认当前目录
    1. pwd  # 确保在项目根目录
    2. ls   # 确认package.json存在
    复制代码

    检查2:检查.dockerignore
    1. cat .dockerignore
    2. # 确保没有排除package.json
    复制代码

    检查3:指定构建上下文
    1. # 明确指定上下文路径
    2. docker build -t my-app:1.0 -f Dockerfile .
    复制代码

    ━━━━━━━━━━━━━━━━━━━━

    问题2:npm install失败或很慢

    症状
    1. npm ERR! network Socket timeout
    2. npm ERR! network This is a problem related to network connectivity.
    复制代码

    原因:npm默认源在国外,网络不稳定

    解决方案

    方法1:在Dockerfile中配置npm镜像源
    1. # 在RUN npm install之前添加
    2. RUN npm config set registry https://registry.npmmirror.com
    复制代码

    方法2:使用.npmrc文件
    1. cat > .npmrc << 'EOF'
    2. registry=https://registry.npmmirror.com
    3. EOF
    复制代码

    方法3:使用国内基础镜像
    1. # 使用阿里云Node.js镜像
    2. FROM registry.cn-hangzhou.aliyuncs.com/acs/node:18-alpine
    复制代码

    ━━━━━━━━━━━━━━━━━━━━

    问题3:容器启动后立即退出

    症状
    1. docker ps  # 看不到容器
    2. docker ps -a  # 状态显示Exited (1)
    复制代码

    排查步骤

    步骤1:查看容器日志
    1. docker logs nodejs-demo
    复制代码

    常见错误日志和解决方案
    1. # 错误1: 端口被占用
    2. Error: listen EADDRINUSE: address already in use :::3000
    3. # 解决:更换端口或关闭占用进程
    4. # 错误2: 模块未找到
    5. Error: Cannot find module 'express'
    6. # 解决:检查npm install是否成功
    7. # 错误3: 权限问题
    8. Error: EACCES: permission denied
    9. # 解决:检查文件权限或用户配置
    复制代码

    步骤2:交互式运行容器调试
    1. # 使用bash进入容器调试
    2. docker run -it --rm my-nodejs-app:1.0 sh
    3. # 在容器内手动启动应用
    4. node src/server.js
    复制代码

    步骤3:检查CMD配置
    1. # 确保CMD格式正确
    2. CMD ["node", "src/server.js"]  # ✅ 推荐
    3. CMD node src/server.js         # ❌ 不推荐
    复制代码

    ━━━━━━━━━━━━━━━━━━━━

    问题4:镜像体积过大

    症状
    1. docker images
    2. # 镜像超过500MB
    复制代码

    优化方案

    优化1:使用alpine基础镜像
    1. FROM node:18-alpine  # ~180MB
    2. # 而不是
    3. FROM node:18         # ~900MB
    复制代码

    优化2:多阶段构建
    1. FROM node:18-alpine AS builder
    2. RUN npm install
    3. FROM node:18-alpine
    4. COPY --from=builder /app/node_modules ./node_modules
    复制代码

    优化3:清理缓存和临时文件
    1. RUN npm install --production \
    2.     && npm cache clean --force \
    3.     && rm -rf /tmp/*
    复制代码

    优化4:使用.dockerignore
    1. # .dockerignore
    2. node_modules
    3. .git
    4. *.md
    5. .env
    6. tests
    复制代码

    查看镜像分层
    1. # 分析镜像构成
    2. docker history my-nodejs-app:1.0
    3. # 使用dive工具深度分析
    4. docker run --rm -it \
    5.   -v /var/run/docker.sock:/var/run/docker.sock \
    6.   wagoodman/dive:latest my-nodejs-app:1.0
    复制代码

    ━━━━━━━━━━━━━━━━━━━━

    问题5:构建缓存问题

    症状:代码修改后,构建使用了旧缓存

    理解缓存机制
  • Docker按层缓存
  • 某层变化会使后续层缓存失效
  • COPY指令会比较文件校验和

    强制重新构建
    1. # 不使用缓存
    2. docker build --no-cache -t my-app:1.0 .
    3. # 指定从某个阶段开始不用缓存
    4. docker build --target builder --no-cache -t my-app:1.0 .
    复制代码

    优化COPY顺序
    1. # ❌ 不好的做法 - 代码变化会重装依赖
    2. COPY . .
    3. RUN npm install
    4. # ✅ 好的做法 - 依赖不变时使用缓存
    5. COPY package*.json ./
    6. RUN npm install
    7. COPY . .
    复制代码

    ━━━━━━━━━━━━━━━━━━━━

    更多问题?

    如果遇到其他问题:
  • 查看 Docker官方文档 - Dockerfile参考
  • 搜索 Docker官方论坛
  • 查阅 Node.js Docker最佳实践
  • 在评论区留言详细描述问题
  • 加入学习群与大家讨论

    ━━━━━━━━━━━━━━━━━━━━

    📚 知识点回顾

    今天我们通过实践学习了:

    核心Dockerfile指令

    | 指令 | 作用 | 最佳实践 |
    |------|------|----------|
    |
    1. FROM
    复制代码
    | 指定基础镜像 | 优先使用alpine版本 |
    |
    1. WORKDIR
    复制代码
    | 设置工作目录 | 使用绝对路径 |
    |
    1. COPY
    复制代码
    | 复制文件 | 先复制依赖文件,利用缓存 |
    |
    1. RUN
    复制代码
    | 执行构建命令 | 合并命令减少层数 |
    |
    1. EXPOSE
    复制代码
    | 声明端口 | 仅文档作用,不实际映射 |
    |
    1. CMD
    复制代码
    | 启动命令 | 使用JSON数组格式 |
    |
    1. ENV
    复制代码
    | 环境变量 | 设置运行时配置 |
    |
    1. ARG
    复制代码
    | 构建参数 | 设置构建时变量 |
    |
    1. USER
    复制代码
    | 切换用户 | 生产环境避免root |
    |
    1. HEALTHCHECK
    复制代码
    | 健康检查 | 便于容器编排 |

    关键概念总结

  • 镜像分层原理
  • 每个指令创建一层
  • 层是只读的
  • 利用缓存加速构建

  • 构建上下文
    1. .
    复制代码
    指定的目录
  • 包含Dockerfile和所需文件
  • 使用.dockerignore排除不需要的文件

  • 多阶段构建
  • 分离构建环境和运行环境
  • 显著减小镜像体积
  • 提高安全性

  • CMD vs ENTRYPOINT
  • CMD:容器默认执行的命令(可被覆盖)
  • ENTRYPOINT:容器入口点(不易被覆盖)
  • 组合使用实现灵活配置

    Dockerfile最佳实践

    DO - 推荐做法
  • 使用官方基础镜像
  • 选择体积小的alpine版本
  • 合并RUN指令减少层数
  • 利用构建缓存,先复制依赖文件
  • 使用.dockerignore排除不需要的文件
  • 创建非root用户运行应用
  • 添加健康检查
  • 使用多阶段构建

    DON'T - 避免做法
  • 在镜像中存储敏感信息
  • 使用latest标签作为基础镜像
  • 安装不必要的软件包
  • 以root用户运行应用
  • 每个指令都新建一层
  • 忽略清理临时文件和缓存

    完整工作流程
    1. graph LR
    2.     A[编写应用代码] --> B[创建Dockerfile]
    3.     B --> C[构建镜像]
    4.     C --> D[运行容器]
    5.     D --> E[测试验证]
    6.     E --> F{是否通过}
    7.     F -->|否| G[修改优化]
    8.     G --> B
    9.     F -->|是| H[推送镜像]
    10.     H --> I[生产部署]
    复制代码

    下一步学习

    完成今天的实践后,建议:

  • 巩固练习
  • 用不同语言(Python、Java、Go)编写Dockerfile
  • 尝试容器化现有项目
  • 实践多阶段构建

  • 扩展阅读
  • Day 9:Docker镜像优化技巧
  • Day 10:Docker网络详解
  • Day 11:数据持久化与Volume

  • 实战项目
  • 构建完整的微服务应用
  • 实现CI/CD自动构建
  • 配置生产环境部署

    ━━━━━━━━━━━━━━━━━━━━

    💬 作业时间

    今日挑战
  • ✅ 完成文章中的所有步骤,成功运行Node.js容器
  • 🎯 使用Dockerfile.optimized构建优化版镜像
  • 🚀 完成至少1个进阶实践任务
  • 📸 截图分享你的运行结果

    思考题
  • 为什么要分两次COPY?先复制package.json再复制代码有什么好处?
  • CMD和ENTRYPOINT的区别是什么?什么时候用哪个?
  • 如何让镜像体积更小?至少说出3种方法

    实战任务
    尝试为你熟悉的应用(Python Flask、Java Spring Boot等)编写Dockerfile,并分享遇到的问题

    讨论话题
    在容器化过程中,你觉得最容易犯的错误是什么?如何避免?

    在评论区分享你的:
  • ✅ 实践成果截图(docker images、docker ps)
  • 💡 遇到的问题和解决方案
  • 🎯 进阶实践的心得体会
  • 📝 对Dockerfile的理解

    优秀作业奖励
  • 🏆 精选作业会获得详细点评
  • 🎁 有机会获得Docker学习资料包
  • 👥 邀请加入技术交流群

    ━━━━━━━━━━━━━━━━━━━━

    🔗 相关资源

    官方文档 📚
  • Dockerfile参考文档
  • Docker最佳实践指南
  • Node.js Docker最佳实践

    推荐工具 🛠️
  • Dive:镜像分析工具
  • Hadolint:Dockerfile代码检查
  • Docker Slim:自动优化镜像

    学习资源 📖
  • Docker官方教程
  • Docker从入门到实践
  • 12-Factor App:云原生应用设计原则

    ━━━━━━━━━━━━━━━━━━━━

    下期预告 🔮

    Day 9 - Dockerfile最佳实践与镜像优化技巧

    我们将深入学习:
  • 🎯 10个Dockerfile编写黄金法则
  • 🚀 镜像体积优化:从500MB到50MB
  • 🔒 容器安全最佳实践
  • ⚡ 构建速度优化技巧
  • 📊 镜像分析与诊断工具

    敬请期待!记得点赞、收藏、关注三连哦~ 🎉



    ━━━━━━━━━━━━━━━━━━━━

    版权声明
    本文为「Docker 30天实战系列」原创内容
  • ✅ 欢迎转发分享
  • ✅ 转载请注明出处
  • ❌ 禁止商业用途

    ━━━━━━━━━━━━━━━━━━━━

    如果这篇文章对你有帮助,请点个「在看」让更多人看到! ❤️
  • 您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码关注微信公众号

    Archiver|手机版|小黑屋|风叶林

    GMT+8, 2026-5-9 00:18 , Processed in 0.190131 second(s), 20 queries .

    Powered by 风叶林

    © 2001-2026 Discuz! Team.

    快速回复 返回顶部 返回列表