Docker 和 Docker Compose 在 Windows 上的实际应用

项目案例:virtual-chat(Spring Boot 虚拟聊天应用)
环境:Windows 10/11 + Docker Desktop
技术栈:Java 17、Spring Boot、Maven、Docker、Docker Compose


目录


一、前言

在现代软件开发中,容器化技术已经成为标准化部署的重要手段。Docker 作为最流行的容器化平台,能够帮助开发者实现"一次构建,到处运行"的目标。而 Docker Compose 则进一步简化了多容器应用的编排和管理。

本文将以 virtual-chat 项目为例,详细介绍在 Windows 环境下如何使用 Docker 和 Docker Compose 进行项目的构建、打包和部署,并分享实际开发中遇到的问题和解决方案。


二、Docker Desktop for Windows 安装与配置

2.1 系统要求

  • Windows 10 64位:专业版、企业版或教育版(Build 19041 或更高版本)
  • Windows 11:所有版本
  • 启用 WSL 2(Windows Subsystem for Linux)
  • BIOS 中启用虚拟化技术

2.2 安装步骤

  1. 下载 Docker Desktop

    • 访问官网:https://www.docker.com/products/docker-desktop
    • 下载 Windows 版本安装包
  2. 安装过程

    # 双击下载的 Docker Desktop Installer.exe
    # 按照向导完成安装
    # 安装完成后重启计算机
    
  3. 验证安装

    # 检查 Docker 版本
    docker --version
    
    # 检查 Docker Compose 版本
    docker-compose --version
    
    # 运行测试容器
    docker run hello-world
    
  4. 启动 Docker Desktop

    • 从开始菜单启动 Docker Desktop
    • 等待右下角托盘图标显示"Docker Desktop is running"
    • 确保 WSL 2 后端正常运行

三、配置国内镜像源加速构建

由于 Docker Hub 在国内访问速度较慢,配置国内镜像源可以显著提升镜像拉取和构建速度。

3.1 配置方法

  1. 打开 Docker Desktop 设置

    • 右键点击任务栏 Docker 图标
    • 选择 “Settings” → “Docker Engine”
  2. 添加国内镜像源

    在 registry-mirrors 数组中添加以下镜像源:

    {
      "builder": {
        "gc": {
          "defaultKeepStorage": "20GB",
          "enabled": true
        }
      },
      "experimental": false,
      "registry-mirrors": [
        "https://docker.m.daocloud.io",
        "https://huecker.io",
        "https://dockerhub.timeweb.cloud",
        "https://noohub.ru"
      ]
    }
    
  3. 应用并重启

    • 点击 “Apply & restart”
    • 等待 Docker Desktop 重启完成

3.2 验证配置

# 查看 Docker 信息,确认镜像源已生效
docker info | Select-String "Registry Mirrors"

# 测试拉取镜像速度
docker pull eclipse-temurin:17-jre-alpine

提示:如果某个镜像源失效,可以尝试更换其他源。常用的国内镜像源包括阿里云、DaoCloud、腾讯云等。


四、方式一:使用 Dockerfile 直接构建部署

4.1 项目准备

以 virtual-chat 项目为例,首先确保项目能够正常构建:

# 进入项目目录
cd d:\aiwork\virtual-chat

# 本地 Maven 构建(推荐先本地构建,避免 Docker 内下载依赖超时)
mvn clean package -DskipTests

4.2 创建 Dockerfile

我们使用简化版的 Dockerfile.simple,采用两阶段构建思路(本地构建 + Docker 打包):

# 使用官方的 OpenJDK 17 JRE 镜像作为基础镜像
FROM eclipse-temurin:17-jre-alpine

# 安装 curl 用于健康检查
RUN apk add --no-cache curl

# 设置工作目录
WORKDIR /app

# 复制已构建的 JAR 文件
COPY target/virtual-chat-0.0.1-SNAPSHOT.jar app.jar

# 暴露端口
EXPOSE 8080

# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]

4.3 创建 .dockerignore

为了避免将不必要的文件复制到镜像中,创建 .dockerignore 文件:

# Git
.git
.gitignore

# IDE
.vscode
.idea
*.iml

# Maven
target/
!.mvn/wrapper/maven-wrapper.jar
!target/virtual-chat-0.0.1-SNAPSHOT.jar

# Data
data/
*.db

# Logs
*.log

# OS
.DS_Store
Thumbs.db

# Documentation
*.md
*.docx
*.txt

# Scripts
*.bat
*.ps1

# Python
__pycache__/
*.pyc
*.pyo

# Generated files
generated-images/

关键点:注意第 11-13 行,我们排除了整个 target/ 目录,但显式允许了最终的 JAR 文件。这样既减少了镜像体积,又保留了必要的构建产物。

4.4 构建 Docker 镜像

# 构建镜像(指定标签)
docker build -f Dockerfile.simple -t virtual-chat:latest .

# 查看构建的镜像
docker images | Select-String "virtual-chat"

4.5 运行容器

# 启动容器
docker run -d `
  --name virtual-chat-app `
  -p 8080:8080 `
  -v ${PWD}/data:/app/data `
  -e SPRING_PROFILES_ACTIVE=prod `
  virtual-chat:latest

# 查看运行状态
docker ps | Select-String "virtual-chat"

# 查看日志
docker logs -f virtual-chat-app

# 访问应用
curl http://localhost:8080

4.6 停止和清理

# 停止容器
docker stop virtual-chat-app

# 删除容器
docker rm virtual-chat-app

# 删除镜像(可选)
docker rmi virtual-chat:latest

五、方式二:使用 Docker Compose 编排部署

对于包含多个服务的应用(如数据库 + 应用服务器),Docker Compose 提供了更便捷的编排方式。

5.1 创建 docker-compose.yml

version: '3.8'

services:
  virtual-chat:
    build:
      context: .
      dockerfile: Dockerfile.simple
    container_name: virtual-chat-app
    ports:
      - "8080:8080"
    volumes:
      # 挂载数据目录以保持H2数据库持久化
      - ./data:/app/data
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVER_PORT=8080
    restart: unless-stopped

5.2 使用 Docker Compose 部署

# 构建并启动服务(后台运行)
docker-compose up -d --build

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f virtual-chat

# 停止服务
docker-compose down

# 停止并删除卷(会清除数据)
docker-compose down -v

5.3 多服务编排示例

如果项目需要连接数据库,可以扩展 docker-compose.yml:

version: '3.8'

services:
  # 应用服务
  virtual-chat:
    build:
      context: .
      dockerfile: Dockerfile.simple
    container_name: virtual-chat-app
    ports:
      - "8080:8080"
    depends_on:
      - postgres
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/virtualchat
      - SPRING_DATASOURCE_USERNAME=postgres
      - SPRING_DATASOURCE_PASSWORD=secret
    restart: unless-stopped

  # PostgreSQL 数据库
  postgres:
    image: postgres:15-alpine
    container_name: virtual-chat-db
    environment:
      POSTGRES_DB: virtualchat
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: unless-stopped

volumes:
  postgres-data:

六、常见问题与解决方案

6.1 问题一:构建进程卡死

现象:

[+] Building 0.0s (0/0)
# 长时间卡在 0/0 进度

原因:

  • Docker Buildx 构建进程异常
  • 网络问题导致镜像拉取超时
  • 资源不足

解决方案:

  1. 查找并终止构建进程

    # 查找 Docker 构建进程
    Get-Process | Where-Object {$_.ProcessName -like "*docker*build*"}
    
    # 强制终止进程(谨慎使用)
    Stop-Process -Name "com.docker.build" -Force
    
  2. 清理构建缓存

    # 清理未使用的构建缓存
    docker builder prune -a -f
    
    # 清理所有未使用的资源
    docker system prune -a -f
    
  3. 重启 Docker Desktop

    • 通过 Docker Desktop UI 完全退出
    • 重新启动 Docker Desktop
    • 等待服务完全恢复后再继续操作

重要提示:强制终止 com.docker.build 进程可能导致 Docker Desktop 后端连接中断,建议优先通过 UI 重启。

6.2 问题二:镜像拉取超时

现象:

Error response from daemon: Get "https://registry-1.docker.io/v2/": 
context deadline exceeded

解决方案:

  1. 检查镜像源配置

    docker info | Select-String "Registry Mirrors"
    
  2. 更换可用的镜像源

    • 参考第三章重新配置镜像源
    • 尝试不同的镜像源组合
  3. 手动拉取基础镜像

    # 先单独拉取基础镜像
    docker pull eclipse-temurin:17-jre-alpine
    
    # 再执行构建
    docker build -f Dockerfile.simple -t virtual-chat:latest .
    

6.3 问题三:Maven 依赖下载失败

现象:

[ERROR] Failed to execute goal on project virtual-chat: 
Could not resolve dependencies

解决方案:

  1. 优先本地构建

    # 在宿主机上先完成 Maven 构建
    mvn clean package -DskipTests
    
    # 再使用 Dockerfile.simple 打包
    docker build -f Dockerfile.simple -t virtual-chat:latest .
    
  2. 配置 Maven 镜像源
    在项目根目录创建 settings.xml:

    <settings>
      <mirrors>
        <mirror>
          <id>aliyun</id>
          <mirrorOf>central</mirrorOf>
          <name>Aliyun Maven</name>
          <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
      </mirrors>
    </settings>
    
  3. 在 Dockerfile 中挂载 settings.xml

    COPY settings.xml /root/.m2/settings.xml
    

6.4 问题四:端口冲突

现象:

Error starting userland proxy: Bind for 0.0.0.0:8080 failed: 
port is already allocated

解决方案:

  1. 查找占用端口的进程

    netstat -ano | findstr :8080
    tasklist | findstr <PID>
    
  2. 修改映射端口

    # docker-compose.yml
    ports:
      - "8081:8080"  # 将宿主机的 8081 映射到容器的 8080
    
  3. 停止占用端口的服务

    taskkill /F /PID <PID>
    

6.5 问题五:数据持久化丢失

现象:
容器重启后,H2 数据库或其他数据丢失。

解决方案:

使用 Volume 挂载数据目录:

volumes:
  - ./data:/app/data

确保 .dockerignore 中排除了 data/ 目录,避免数据被覆盖。


七、核心配置文件详解

7.1 Dockerfile.simple 解析

# 第1行:指定基础镜像
# eclipse-temurin:17-jre-alpine 是轻量级的 Java 17 JRE 镜像
# Alpine Linux 基础使得镜像体积更小(约 200MB vs 标准版的 600MB+)
FROM eclipse-temurin:17-jre-alpine

# 第5行:安装必要工具
# curl 用于健康检查和调试
# --no-cache 避免缓存包,减小镜像体积
RUN apk add --no-cache curl

# 第8行:设置工作目录
# 后续的所有相对路径都基于此目录
WORKDIR /app

# 第11行:复制 JAR 文件
# 从宿主机的 target 目录复制已构建的 JAR 到容器的 /app 目录
# 重命名为 app.jar 便于统一管理
COPY target/virtual-chat-0.0.1-SNAPSHOT.jar app.jar

# 第14行:声明暴露的端口
# 这只是文档说明,实际端口映射在 docker run 或 docker-compose 中指定
EXPOSE 8080

# 第17行:定义容器启动时执行的命令
# ENTRYPOINT 使得容器像一个可执行程序一样运行
# java -jar 启动 Spring Boot 应用
ENTRYPOINT ["java", "-jar", "app.jar"]

关键设计点:

  • 使用 JRE 而非 JDK,减小镜像体积
  • Alpine Linux 基础镜像,进一步压缩体积
  • 本地构建 + Docker 打包,避免在容器内下载依赖
  • 固定 ENTRYPOINT,支持通过 docker run 传递 JVM 参数

7.2 docker-compose.yml 解析

# 指定 Compose 文件格式版本
version: '3.8'

# 定义服务列表
services:
  # 服务名称(可自定义)
  virtual-chat:
    # 构建配置
    build:
      # 构建上下文:当前目录
      context: .
      # 指定使用的 Dockerfile
      dockerfile: Dockerfile.simple
    
    # 容器名称(固定名称便于管理)
    container_name: virtual-chat-app
    
    # 端口映射:宿主机端口:容器端口
    ports:
      - "8080:8080"
    
    # 数据卷挂载:宿主机路径:容器路径
    volumes:
      # 挂载数据目录以实现持久化
      - ./data:/app/data
    
    # 环境变量
    environment:
      # 激活 Spring Boot 的生产环境配置
      - SPRING_PROFILES_ACTIVE=prod
      # 设置服务器端口
      - SERVER_PORT=8080
    
    # 重启策略:除非手动停止,否则自动重启
    restart: unless-stopped

关键字段说明:

字段作用示例值
build.context构建上下文目录. 表示当前目录
build.dockerfile指定 Dockerfile 路径Dockerfile.simple
container_name容器名称固定名称便于管理
ports端口映射"宿主机端口:容器端口"
volumes数据卷挂载"宿主机路径:容器路径"
environment环境变量传递给容器的配置
restart重启策略unless-stopped / always / no

7.3 .dockerignore 解析

# 排除 Git 相关文件
.git
.gitignore

# 排除 IDE 配置文件
.vscode
.idea
*.iml

# Maven 构建目录(但保留最终 JAR)
target/
!.mvn/wrapper/maven-wrapper.jar
!target/virtual-chat-0.0.1-SNAPSHOT.jar

# 排除数据文件(避免覆盖持久化数据)
data/
*.db

# 排除日志文件
*.log

# 排除操作系统文件
.DS_Store
Thumbs.db

# 排除文档文件
*.md
*.docx
*.txt

# 排除脚本文件
*.bat
*.ps1

# 排除 Python 缓存
__pycache__/
*.pyc
*.pyo

# 排除生成的图片文件
generated-images/

设计原则:

  • 减少镜像体积:排除不必要的文件,显著减小镜像大小
  • 提高构建速度:减少需要传输到 Docker daemon 的文件数量
  • 保护敏感数据:避免将 .env、密钥文件等复制到镜像中
  • 保持数据独立:排除 data/ 目录,确保容器内外数据隔离

八、Docker 与 Docker Compose 的区别与优势

8.1 核心区别

特性DockerDocker Compose
定位单容器管理工具多容器编排工具
配置文件Dockerfiledocker-compose.yml
适用场景单个应用容器化多服务应用编排
命令复杂度需要手动管理多个容器一条命令管理所有服务
网络管理需手动创建和管理网络自动创建内部网络
依赖管理需手动控制启动顺序通过 depends_on 自动管理

8.2 Docker 的优势

  1. 环境一致性

    • "在我的机器上能运行"不再是问题
    • 开发、测试、生产环境完全一致
  2. 资源隔离

    • 每个容器拥有独立的文件系统、网络、进程空间
    • 避免应用之间的依赖冲突
  3. 快速部署

    • 秒级启动容器
    • 支持快速扩缩容
  4. 轻量级

    • 相比虚拟机,容器共享宿主机内核
    • 资源开销小,启动速度快
  5. 版本控制

    • 镜像可以打标签、版本化管理
    • 支持快速回滚

8.3 Docker Compose 的优势

  1. 简化多容器管理

    # 传统方式:需要分别启动多个容器
    docker run -d --name db postgres:15
    docker run -d --name app --link db myapp
    
    # Compose 方式:一条命令启动所有服务
    docker-compose up -d
    
  2. 声明式配置

    • 所有服务配置集中在一个 YAML 文件中
    • 易于版本控制和团队协作
  3. 自动网络管理

    • 自动创建内部网络
    • 服务之间可以通过服务名互相访问
    # 应用可以直接使用服务名 "postgres" 访问数据库
    SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/virtualchat
    
  4. 依赖管理

    depends_on:
      - postgres
      - redis
    

    确保服务按正确顺序启动

  5. 一键启停

    # 启动所有服务
    docker-compose up -d
    
    # 停止所有服务
    docker-compose down
    
    # 查看日志
    docker-compose logs -f
    
  6. 环境隔离

    # 可以为不同环境使用不同的 compose 文件
    docker-compose -f docker-compose.dev.yml up
    docker-compose -f docker-compose.prod.yml up
    

8.4 选择建议

使用 Docker 的场景:

  • 单个应用的容器化
  • 简单的微服务部署
  • 学习和实验

使用 Docker Compose 的场景:

  • 多服务应用(如 Web + Database + Cache)
  • 本地开发环境搭建
  • 微服务架构的原型开发
  • 需要频繁启停的开发测试环境

生产环境建议:

  • 小规模:Docker Compose + 监控
  • 中大规模:Kubernetes / Docker Swarm

九、总结

9.1 最佳实践总结

  1. 镜像源配置

    • 始终配置国内镜像源以提升构建速度
    • 准备多个备用镜像源
  2. 构建优化

    • 优先本地构建,避免在 Docker 内下载依赖
    • 使用多阶段构建或简化版 Dockerfile
    • 合理配置 .dockerignore 减小镜像体积
  3. 数据持久化

    • 使用 Volume 挂载重要数据目录
    • 定期备份持久化数据
  4. 错误处理

    • 遇到构建卡顿时,优先重启 Docker Desktop
    • 定期清理未使用的镜像和缓存
    • 查看详细日志定位问题
  5. 安全考虑

    • 不要在镜像中硬编码敏感信息
    • 使用环境变量或 secrets 管理配置
    • 定期更新基础镜像修复安全漏洞

9.2 工作流程回顾

单服务

多服务

是

否

安装 Docker Desktop

配置国内镜像源

选择部署方式

编写 Dockerfile

编写 docker-compose.yml

本地 Maven 构建

Docker 构建镜像

构建成功?

启动容器

排查问题

清理缓存/重启 Docker

验证应用运行

部署完成

9.3 后续学习方向

  1. Docker 高级特性

    • 多阶段构建优化镜像体积
    • Docker BuildKit 高级功能
    • 自定义网络和存储驱动
  2. 容器编排

    • Kubernetes 入门与实践
    • Docker Swarm 集群管理
    • Helm Chart 包管理
  3. CI/CD 集成

    • GitHub Actions + Docker
    • Jenkins 自动化构建
    • 私有镜像仓库搭建
  4. 监控与日志

    • Prometheus + Grafana 监控
    • ELK 日志收集
    • 容器健康检查

附录:常用命令速查

Docker 基础命令

# 镜像管理
docker images                    # 列出镜像
docker pull <image>              # 拉取镜像
docker rmi <image>               # 删除镜像
docker build -t <tag> .          # 构建镜像

# 容器管理
docker ps                        # 查看运行中的容器
docker ps -a                     # 查看所有容器
docker run -d <image>            # 运行容器
docker stop <container>          # 停止容器
docker rm <container>            # 删除容器
docker logs -f <container>       # 查看日志
docker exec -it <container> sh   # 进入容器

# 系统清理
docker system prune -a -f        # 清理所有未使用资源
docker builder prune -a -f       # 清理构建缓存

Docker Compose 命令

# 服务管理
docker-compose up -d             # 后台启动服务
docker-compose down              # 停止并删除服务
docker-compose ps                # 查看服务状态
docker-compose logs -f           # 查看日志
docker-compose restart           # 重启服务
docker-compose build             # 重新构建镜像

# 高级用法
docker-compose up -d --build     # 重新构建并启动
docker-compose down -v           # 停止并删除卷
docker-compose exec <service> sh # 进入服务容器

更多推荐