Docker Compose 多服务项目实战指南

项目   2025-06-19 18:39   3   0  

目录

  • 1. 引言:为什么使用 Docker Compose?

  • 2. 项目介绍与服务架构图

  • 3. 服务配置讲解:从混乱到规范

  • 4. 前端服务配置与调试

    • 4.1. 问题1:npm install 非常慢或失败

    • 4.2. 问题2:容器启动后立即退出

    • 4.3. 问题3:本地代码修改不生效

  • 5. 后端服务配置与问题解析

    • 5.1. 问题1:Maven 下载依赖慢或失败

    • 5.2. 问题2:后端连接数据库失败

  • 6. 数据库服务配置

    • 6.1. 问题1:数据库初始化脚本未执行

    • 6.2. 问题2:数据无法持久化

    • 6.3. 问题3:连接被拒绝

  • 7. Nginx 服务配置

    • 7.1. 配置说明

  • 8. 常见问题排查与经验总结

    • 8.1. 8.1 容器启动失败或退出

    • 8.2. 8.2 依赖安装卡顿

    • 8.3. 8.3 后端数据库连接失败

    • 8.4. 8.4 容器间访问失败

    • 8.5. 8.5 环境变量未生效

    • 8.6. 8.6 数据未持久化

    • 8.7. 8.7 初始化 SQL 未执行

  • 9. 推荐实践与配置规范

  • 10. 附录

    • 10.1. 示例 `.env`

    • 10.2. Makefile 示例


1. 引言:为什么使用 Docker Compose?

在日常开发过程中,经常遇到开发环境与线上环境不一致,导致各种异常问题出现。为了让线下环境与线上保持一致,减少“本地跑正常,线上崩”的问题,我们采用 Docker 虚拟环境。

由于项目包含前后端多个服务,手动用 `docker run` 启动繁琐,且配置容易错乱,因此选择使用 Docker Compose 来统一管理启动配置,提升开发效率。

本文通过一个微信小程序项目案例,介绍 Docker Compose 的配置方法及遇到的问题和解决方案。


2. 项目介绍与服务架构图

项目为一个微信小程序,界面通过 UniApp 编译而来。前端通过 Nginx 访问后端服务,同时 Nginx 负责图片处理。

项目包含四个容器:

  • front :前端(uniapp/vue)

  • devtool :微信开发者工具,查看编译结果

  • api :后端(Spring Boot)

  • db :数据库(PostgreSQL)

  • nginx :Nginx 代理和图片处理

37441_lxmm_2048.png


3. 服务配置讲解:从混乱到规范

在配置容器时,关键步骤包括:

  • 选择合适镜像(image、build)

  • 让镜像访问到本地文件(本地挂载和 volume)

  • 系统初始化(Postgres 初始化、npm install、mvn install)

  • 运行命令(npm run、mvn spring-boot:run)

  • 容器启动后,多容器之间协作(网络、端口、依赖、环境变量)

遇到的主要问题是配置重复、启动失败、服务通信异常等,下面我们依次讲解。


4. 前端服务配置与调试

4.1. 问题1:npm install 非常慢或失败

  • 原因 :默认镜像内 npm 使用国外源,网络慢,且没有缓存

  • 解决方案 :

    • 挂载 `.npmrc` 文件,配置国内镜像源

    • 挂载 npm 缓存目录,避免重复下载依赖

volumes:
  - ../../front:/data
  - ./.npmrc:/root/.npmrc
  - npm_cache:/root/.npm

4.2. 问题2:容器启动后立即退出

  • 原因 :默认命令执行完容器即停止

  • 解决方案 :

    • 设置 `tty: true`,`stdin_open: true`

    • 用 `command: tail -f /dev/null` 保持容器常驻方便调试

    • 正确设置启动命令如 `npm run dev:mp-weixin`

4.3. 问题3:本地代码修改不生效

  • 原因 :未正确挂载本地源码

  • 解决方案 :

    • 挂载源码目录到容器内

    • 设置工作目录 `working_dir: /data`

5. 后端服务配置与问题解析

5.1. 问题1:Maven 下载依赖慢或失败

  • 原因 :镜像默认使用国外仓库

  • 解决方案 :

    • 挂载本地 Maven 缓存目录 `.m2`

    • 使用私服或配置阿里云 Maven 镜像仓库

volumes:
  - ../../api:/app
  - ./m2:/root/.m2

5.2. 问题2:后端连接数据库失败

  • 原因 :数据库容器未启动或连接配置错误

  • 解决方案 :

    • 在 Compose 配置中用 `depends_on` 确保数据库先启动

    • 在后端配置文件和 `.env` 中正确配置数据库地址、端口和账户

6. 数据库服务配置

6.1. 问题1:数据库初始化脚本未执行

  • 原因 :初始化 SQL 文件挂载路径或格式错误;已有数据卷导致初始化跳过

  • 解决方案 :

    • 将初始化脚本挂载到 `/docker-entrypoint-initdb.d/`

    • 确保脚本文件后缀为 `.sql` 或 `.sh`

    • 清理数据卷重新初始化(`docker compose down -v`)

6.2. 问题2:数据无法持久化

  • 原因 :未挂载数据目录 Volume

  • 解决方案 :

    • 配置 named volume 持久化数据库数据目录

volumes:  tm-pgdata:
volumes:
  - tm-pgdata:/var/lib/postgresql/data

6.3. 问题3:连接被拒绝

  • 原因 :数据库未启动或端口配置错误

  • 解决方案 :

    • 使用服务名访问数据库(`db:5432`)

    • 正确映射端口供本地访问

7. Nginx 服务配置

7.1. 配置说明

下面是 Nginx 的完整配置文件,附带详细注释,涵盖代理 API、图片处理、HTTP 到 HTTPS 重定向等功能。正式环境请根据注释调整启用 HTTPS 和域名配置。

####################################### 功能说明:#    1. 代理 API 地址 /api/#    2. 处理图片请求 /images/${图片名}@${宽度}w_${高度}h_${图片质量}Q_[r(调整大小)|c(裁剪)]#    3. HTTP 重定向 HTTPS(注释部分)## 注意:#    1. 正式环境需启用 HTTPS,具体配置参考注释部分#    2. 正式环境需修改 server_name#    3. 需正确配置代理的主机 IP 和端口(API_HOST、API_PORT)#    4. 需安装 Nginx image_filter 模块支持图片处理#    5. 需修改上传图片路径(FILE_PATH)######################################upstream tm {    server ${API_HOST}:${API_PORT};
}# HTTP 重定向到 HTTPS(正式环境启用)# server {#     listen 80;#     server_name time.loujiaye.cn;#     rewrite ^(.*)$ https://time.loujiaye.cn$1 permanent;# }proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache_one:50m inactive=24h use_temp_path=off;server {    listen ${NGINX_PORT};    # listen 443 ssl http2;
    # server_name time.loujiaye.cn 127.0.0.1;

    # SSL 配置示例(正式环境启用)
    # ssl_certificate /root/cert/time.pem;
    # ssl_certificate_key /root/cert/time.key;
    # ssl_session_cache shared:SSL:1m;
    # ssl_session_timeout 5m;
    # ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # ssl_prefer_server_ciphers on;

    # 缓存相关配置
    proxy_buffer_size 16k;    proxy_buffers 4 32k;    proxy_busy_buffers_size 96k;    proxy_temp_file_write_size 96k;    index index.html;    # API 代理配置
    location ^~ /api/ {        proxy_pass http://tm/;        proxy_set_header Host $http_host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_redirect / /api/;
    }    # 处理图片请求,支持动态调整大小或裁剪
    location ~ /images/(.+)\.(png|jpg|gif|JPG|PNG|GIF)@(\d+)w_(\d+)h_(\d+)Q_([rc])$ {        set $w $3;        set $h $4;        set $q $5;        set $type $6;        set $image_path $1.$2;        set $cache_path $1_$3w_$4h_$5Q_$6.$2;        if ( $type = 'r') {            set $type 'image-resize';
        }        if ( $type = 'c') {            set $type 'image-crop';
        }        set $image_uri /$type/$image_path?w=$w&h=$h&q=$q;        if ( -f $cache_path) {            rewrite (.+)\.(png|jpg|gif|JPG|PNG|GIF)@(\d+)w_(\d+)h_(\d+)Q_([rc])$ $cache_path;            break;
        }        if ( !-f $cache_path) {            proxy_pass https://127.0.0.1$image_uri;
        }        proxy_store $cache_path;        proxy_store_access user:rw group:rw all:rw;        proxy_temp_path /tmp/;        proxy_set_header Host $Host;        expires 30d;
    }    # 图片调整大小处理
    location ~ /image-resize(.+)\.(png|jpg|gif|PNG|JPG|GIF) {        rewrite /image-resize(.+)\.(png|jpg|gif|PNG|JPG|GIF)$ $1.$2 break;        image_filter resize $arg_w $arg_h;        image_filter_jpeg_quality $arg_q;        image_filter_buffer 50M;        root ${FILE_PATH};
    }    # 图片裁剪处理
    location ~ /image-crop(.+)\.(png|jpg|gif|PNG|JPG|GIF) {        rewrite /image-crop(.+)\.(png|jpg|gif|PNG|JPG|GIF)$ $1.$2 break;        image_filter crop $arg_w $arg_h;        image_filter_jpeg_quality $arg_q;        image_filter_buffer 50M;        root ${FILE_PATH};
    }    # 静态图片访问及缓存配置
    location /images/ {        add_header Cache-Control "public";        proxy_redirect off;        proxy_set_header Host $host;        proxy_cache cache_one;        proxy_cache_valid 200 302 24h;        proxy_cache_valid 301 30d;        proxy_cache_valid any 5m;        expires 90d;        access_log off;        alias ${FILE_PATH};        autoindex on;
    }
}

8. 常见问题排查与经验总结

8.1. 容器启动失败或退出

  • 表现 :容器启动后立即退出

  • 排查 :

    • 用 `tail -f /dev/null` 暂时保持容器运行

    • 查看日志 `docker compose logs <service>`

    • 进入容器 `docker exec -it <container> sh`

8.2. 依赖安装卡顿

  • 表现 :npm、Maven 依赖安装慢或失败

  • 解决 :

    • 使用国内镜像源

    • 挂载缓存目录

8.3. 后端数据库连接失败

  • 表现 :Spring Boot 报错无法连接数据库

  • 解决 :

    • 保证数据库容器启动优先

    • 使用正确服务名和端口访问

    • 检查环境变量配置是否正确注入

8.4.  容器间访问失败

  • 表现 :API 服务无法被 Nginx 或前端访问

  • 解决 :

    • 容器间通过服务名通信,避免 localhost

    • 端口映射要正确

8.5. 环境变量未生效

  • 表现 :配置文件未正确替换变量

  • 解决 :

    • 使用 `env_file` 明确引入 `.env`

    • Nginx 使用 `envsubst` 替换模板变量

8.6.  数据未持久化

  • 表现 :重启后数据丢失

  • 解决 :

    • 使用 volume 持久化数据库数据目录

8.7.  初始化 SQL 未执行

  • 表现 :初始化脚本无效

  • 解决 :

    • 挂载 SQL 脚本目录正确

    • 清理旧数据卷

9. 推荐实践与配置规范

  • 统一使用 `.env` 管理配置变量

  • 开发时挂载源码目录,部署时构建镜像

  • 缓存依赖目录提升构建效率

  • Nginx 配置用模板 + `envsubst` 动态注入变量

  • 编写 Makefile 简化日常命令

  • 日志限制防止占用过多磁盘

  • 版本控制时忽略缓存、数据目录

10. 附录

10.1. 示例 `.env`

POSTGRES_DB=tm_db
POSTGRES_USER=tm_user
POSTGRES_PASSWORD=123456
POSTGRES_PORT=5432

API_PORT=8080
NGINX_PORT=80
FILE_PATH=/var/www/images
API_HOST=api

10.2. Makefile 示例

up:
        docker compose up -d --builddown:
        docker compose downlogs:
        docker compose logs -f



博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。