Docker Compose 多服务编排实战:从零搭建微服务架构
Docker Compose 多服务编排实战从零搭建微服务架构目录为什么需要 Docker Compose实战项目架构环境准备核心服务搭建高级特性负载均衡与服务发现日志集中管理EFK 栈生产环境最佳实践常见问题排查为什么需要 Docker Compose在单体应用时代一个容器可能足以运行整个应用。但在微服务架构下一个完整的应用通常由多个服务组成Web 前端、API 网关、多个后端服务、数据库、缓存、消息队列等。手动管理这些容器的痛点需要记住每个服务的启动顺序和依赖关系网络配置复杂服务间通信困难环境不一致导致在我机器上能跑的问题日志分散在各个容器难以排查问题Docker Compose 通过一个简单的 YAML 文件定义多容器应用一条命令即可启动整个技术栈。实战项目架构我们将构建一个完整的电商微服务系统包含以下组件┌─────────────────────────────────────────────────────────────┐ │ Nginx 网关 │ │ (负载均衡 反向代理) │ └─────────────┬───────────────────────────────────────────────┘ │ ┌─────────┴──────────┐ │ │ ┌───▼────┐ ┌────▼────┐ │前端服务 │ │ API 网关 │ │(React) │ │(Node.js)│ └────┬───┘ └────┬────┘ │ │ └─────────┬─────────┘ │ ┌──────────┼──────────┐ │ │ │ ┌───▼───┐ ┌──▼───┐ ┌───▼───┐ │订单服务 │ │用户服务│ │商品服务 │ │(Java) │ │(Java) │ │(Java) │ └───┬───┘ └──┬───┘ └───┬───┘ │ │ │ └─────────┼──────────┘ │ ┌─────────▼──────────┐ │ │ ┌───▼────┐ ┌────▼────┐ │PostgreSQL│ │ Redis │ │(主从集群)│ │ (缓存) │ └─────────┘ └─────────┘环境准备1. 安装 Docker Compose# 验证安装docker-compose--version# 如果未安装使用以下命令Linuxcurl-Lhttps://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname-s)-$(uname-m)-o/usr/local/bin/docker-composechmodx /usr/local/bin/docker-compose2. 项目目录结构mkdir-pecommerce-platform/{services/{frontend,api-gateway,order-service,user-service,product-service},infra/{postgres,redis,nginx},logs,fluentd/conf}cdecommerce-platform tree-L2预期输出. ├── docker-compose.yml # 主编排文件 ├── docker-compose.prod.yml # 生产环境覆盖配置 ├── docker-compose.efk.yml # 日志收集栈 ├── services/ │ ├── frontend/ # React 前端 │ ├── api-gateway/ # Node.js API 网关 │ ├── order-service/ # Java 订单服务 │ ├── user-service/ # Java 用户服务 │ └── product-service/ # Java 商品服务 ├── infra/ │ ├── nginx/ # Nginx 配置 │ ├── postgres/ # 数据库初始化脚本 │ └── redis/ # Redis 配置 ├── logs/ # 日志挂载目录 └── fluentd/ └── conf/ └── fluent.conf # Fluentd 收集规则核心服务搭建步骤 1数据库与基础设施创建docker-compose.yml基础层version:3.8services:# PostgreSQL 主库postgres-master:image:postgres:15-alpinecontainer_name:ecommerce-postgres-masterenvironment:POSTGRES_USER:ecommercePOSTGRES_PASSWORD:${DB_PASSWORD:-secure_password_123}POSTGRES_DB:ecommerce_dbPGDATA:/var/lib/postgresql/data/pgdatavolumes:-postgres-master-data:/var/lib/postgresql/data-./infra/postgres/init-master.sql:/docker-entrypoint-initdb.d/init.sqlports:-5432:5432healthcheck:test:[CMD-SHELL,pg_isready -U ecommerce -d ecommerce_db]interval:10stimeout:5sretries:5networks:-backend-network# Redis 缓存redis:image:redis:7-alpinecontainer_name:ecommerce-rediscommand:redis-server--appendonly yes--maxmemory 256mb--maxmemory-policy allkeys-lruvolumes:-redis-data:/dataports:-6379:6379healthcheck:test:[CMD,redis-cli,ping]interval:5stimeout:3sretries:5networks:-backend-network# 消息队列RabbitMQrabbitmq:image:rabbitmq:3.12-management-alpinecontainer_name:ecommerce-rabbitmqenvironment:RABBITMQ_DEFAULT_USER:adminRABBITMQ_DEFAULT_PASS:${MQ_PASSWORD:-admin123}ports:-5672:5672# AMQP 端口-15672:15672# 管理界面volumes:-rabbitmq-data:/var/lib/rabbitmqnetworks:-backend-networkvolumes:postgres-master-data:redis-data:rabbitmq-data:networks:backend-network:driver:bridgeipam:config:-subnet:172.20.0.0/16关键配置解析健康检查确保数据库就绪后才启动依赖服务环境变量使用${VAR:-default}语法提供默认值同时支持外部传入命名卷数据持久化避免容器重启数据丢失自定义网络指定 IP 段避免与现有网络冲突步骤 2Java 微服务以订单服务为例创建services/order-service/Dockerfile# 多阶段构建优化镜像大小 FROM eclipse-temurin:17-jdk-alpine AS builder WORKDIR /app COPY .mvn/ .mvn COPY mvnw pom.xml ./ RUN ./mvnw dependency:go-offline COPY src ./src RUN ./mvnw package -DskipTests # 运行阶段使用更小的 JRE 镜像 FROM eclipse-temurin:17-jre-alpine WORKDIR /app # 创建非 root 用户提升安全性 RUN addgroup -S spring adduser -S spring -G spring USER spring:spring COPY --frombuilder /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -XX:UseContainerSupport, -XX:MaxRAMPercentage75.0, -jar, app.jar]在docker-compose.yml中添加服务定义# 订单服务order-service:build:context:./services/order-servicedockerfile:Dockerfilecontainer_name:ecommerce-order-serviceenvironment:-SPRING_PROFILES_ACTIVEdocker-SPRING_DATASOURCE_URLjdbc:postgresql://postgres-master:5432/ecommerce_db-SPRING_DATASOURCE_USERNAMEecommerce-SPRING_DATASOURCE_PASSWORD${DB_PASSWORD:-secure_password_123}-SPRING_REDIS_HOSTredis-SPRING_RABBITMQ_HOSTrabbitmq-SERVER_PORT8080depends_on:postgres-master:condition:service_healthyredis:condition:service_healthyrabbitmq:condition:service_starteddeploy:replicas:2resources:limits:cpus:1memory:512Mreservations:cpus:0.25memory:256Mnetworks:-backend-network-service-network# 用户服务类似配置user-service:build:context:./services/user-servicecontainer_name:ecommerce-user-serviceenvironment:-SPRING_DATASOURCE_URLjdbc:postgresql://postgres-master:5432/ecommerce_dbdepends_on:postgres-master:condition:service_healthynetworks:-backend-network-service-network# 商品服务product-service:build:context:./services/product-servicecontainer_name:ecommerce-product-serviceenvironment:-SPRING_DATASOURCE_URLjdbc:postgresql://postgres-master:5432/ecommerce_db-SPRING_REDIS_HOSTredisdepends_on:postgres-master:condition:service_healthyredis:condition:service_healthynetworks:-backend-network-service-network生产级优化点多阶段构建将编译和运行分离最终镜像体积减少 60% 以上资源限制通过deploy.resources限制 CPU 和内存防止单个服务耗尽主机资源非 root 用户遵循安全最佳实践减少攻击面JVM 容器感知使用-XX:UseContainerSupport让 JVM 正确识别容器内存限制步骤 3API 网关Node.js创建services/api-gateway/DockerfileFROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction npm cache clean --force COPY . . EXPOSE 3000 USER node CMD [node, server.js]添加网关配置api-gateway:build:./services/api-gatewaycontainer_name:ecommerce-api-gatewayenvironment:-NODE_ENVproduction-PORT3000-ORDER_SERVICE_URLhttp://order-service:8080-USER_SERVICE_URLhttp://user-service:8080-PRODUCT_SERVICE_URLhttp://product-service:8080-REDIS_URLredis://redis:6379ports:-3000:3000depends_on:-order-service-user-service-product-servicenetworks:-backend-network-service-networkhealthcheck:test:[CMD,wget,--quiet,--tries1,--spider,http://localhost:3000/health]interval:30stimeout:10sretries:3步骤 4前端与 Nginx 负载均衡创建infra/nginx/nginx.confupstream api_gateway { least_conn; # 最少连接数负载均衡算法 server api-gateway:3000 max_fails3 fail_timeout30s; } upstream order_service { least_conn; server order-service:8080; } server { listen 80; server_name localhost; # 前端静态资源 location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } # API 代理 location /api/ { proxy_pass http://api_gateway/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 超时配置 proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 健康检查端点 location /nginx-health { access_log off; return 200 healthy\n; add_header Content-Type text/plain; } }添加 Nginx 和前端服务# React 前端构建frontend:build:context:./services/frontenddockerfile:Dockerfileargs:-REACT_APP_API_URL/apicontainer_name:ecommerce-frontendnetworks:-frontend-network# Nginx 网关与负载均衡nginx:image:nginx:alpinecontainer_name:ecommerce-nginxports:-80:80volumes:-./infra/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:rodepends_on:-frontend-api-gatewaynetworks:-frontend-network-service-network高级特性负载均衡与服务发现服务扩展与负载均衡Docker Compose 支持快速扩展服务实例# 扩展订单服务为 3 个实例docker-composeup-d--scaleorder-service3修改 Nginx 配置以支持动态上游# 使用变量配合 resolver 实现动态服务发现 resolver 127.0.0.11 valid30s; # Docker 内置 DNS upstream backend { zone upstream_backend 64k; server order-service:8080 resolve; }网络隔离策略创建分层网络提升安全性networks:# 外部访问层frontend-network:driver:bridgeinternal:false# 服务间通信层service-network:driver:bridgeinternal:true# 禁止外部访问# 数据层仅数据库和缓存backend-network:driver:bridgeinternal:true网络隔离原则数据库和缓存只在backend-network不暴露端口到宿主机微服务同时连接backend-network访问数据和service-network服务间通信Nginx 是唯一暴露 80 端口的入口日志集中管理EFK 栈当服务数量增加分散的日志难以排查问题。我们集成 EFKElasticsearch Fluentd Kibana实现日志中心化。创建docker-compose.efk.ymlversion:3.8services:elasticsearch:image:elasticsearch:8.11.0container_name:ecommerce-elasticsearchenvironment:-discovery.typesingle-node-xpack.security.enabledfalse-ES_JAVA_OPTS-Xms512m -Xmx512mvolumes:-es-data:/usr/share/elasticsearch/dataports:-9200:9200networks:-logging-networkfluentd:image:fluent/fluentd:v1.16-1container_name:ecommerce-fluentdvolumes:-./fluentd/conf:/fluentd/etc-./logs:/var/log/fluentdports:-24224:24224-24224:24224/udpdepends_on:-elasticsearchnetworks:-logging-networkkibana:image:kibana:8.11.0container_name:ecommerce-kibanaenvironment:-ELASTICSEARCH_HOSTShttp://elasticsearch:9200ports:-5601:5601depends_on:-elasticsearchnetworks:-logging-networkvolumes:es-data:networks:logging-network:driver:bridge创建fluentd/conf/fluent.confsourcetype forward port 24224 bind 0.0.0.0/sourcefilter**type parser format json key_name log reserve_data true/filtermatch**type elasticsearch host elasticsearch port 9200 logstash_format true logstash_prefix ecommerce-logs flush_interval 10s/match使用方式# 启动业务服务 EFK 栈docker-compose-fdocker-compose.yml-fdocker-compose.efk.yml up-d# 配置业务服务日志驱动在主docker-compose.yml中添加日志驱动配置order-service:logging:driver:fluentdoptions:fluentd-address:localhost:24224tag:order-servicelabels:service_name,environment访问http://localhost:5601查看 Kibana 界面创建索引模式ecommerce-logs-*即可搜索所有服务日志。生产环境最佳实践1. 多环境配置分离创建docker-compose.prod.yml覆盖生产配置version:3.8services:order-service:deploy:replicas:3resources:limits:cpus:2memory:1Glogging:driver:json-fileoptions:max-size:100mmax-file:10restart:unless-stoppedpostgres-master:volumes:-/mnt/nfs/postgres-data:/var/lib/postgresql/data# 使用 NFS 存储command:postgres -c max_connections200 -c shared_buffers2GB -c effective_cache_size6GB启动命令# 开发环境docker-composeup-d# 生产环境合并配置docker-compose-fdocker-compose.yml-fdocker-compose.prod.yml up-d2. 敏感信息管理使用 Docker SecretsSwarm 模式或环境变量文件# .env 文件加入 .gitignoreDB_PASSWORDyour_secure_passwordJWT_SECRETyour_jwt_secretorder-service:env_file:-.envsecrets:-db_password-jwt_secretsecrets:db_password:file:./secrets/db_password.txtjwt_secret:file:./secrets/jwt_secret.txt3. 健康检查与自动恢复order-service:healthcheck:test:[CMD,curl,-f,http://localhost:8080/actuator/health]interval:30stimeout:10sretries:3start_period:60s# 启动宽限期restart:unless-stopped4. 资源限制与日志轮转nginx:logging:driver:json-fileoptions:max-size:10mmax-file:3labels:service_name,environmentenv:OS_VERSION常见问题排查问题 1服务启动顺序依赖现象应用服务启动失败提示数据库连接超时。解决使用depends_on配合健康检查确保数据库就绪后才启动应用。depends_on:postgres-master:condition:service_healthy# 需要 Docker Compose 2.20问题 2容器间通信失败现象服务 A 无法访问服务 B提示Connection refused。排查步骤检查是否在同一网络docker network inspect backend-network检查服务名是否正确使用容器名而非 localhost检查端口是否暴露内部通信不需要ports映射问题 3数据卷权限错误现象PostgreSQL 启动失败Permission denied。解决# 宿主机目录赋予容器用户权限sudochown-R999:999 ./postgres-data# 999 是 postgres 容器用户 ID问题 4内存不足 OOM现象容器频繁重启Exit Code 137。解决添加 JVM 参数和资源限制environment:-JAVA_OPTS-XX:UseContainerSupport-XX:MaxRAMPercentage75.0deploy:resources:limits:memory:1G完整启动流程# 1. 克隆项目并进入目录gitcloneyour-repocdecommerce-platform# 2. 创建环境变量文件cat.envEOF DB_PASSWORDSecurePssw0rd123 JWT_SECRETyour-256-bit-secret EOF# 3. 构建所有镜像首次docker-composebuild# 4. 启动基础设施数据库、缓存docker-composeup-dpostgres-master redis rabbitmq# 5. 等待数据库就绪docker-composeexecpostgres-master pg_isready-Uecommerce# 6. 启动业务服务docker-composeup-dorder-service user-service product-service# 7. 启动网关和前端docker-composeup-dapi-gateway frontend nginx# 8. 验证状态docker-composeps# 9. 查看日志docker-composelogs-forder-service# 10. 压力测试可选docker-composeup-d--scaleorder-service3总结通过本实战项目我们掌握了✅多服务编排使用 Docker Compose 管理 8 个服务的依赖关系✅网络设计分层网络架构实现安全隔离✅负载均衡Nginx 反向代理 服务扩展✅日志收集EFK 栈实现中心化日志管理✅生产优化资源限制、健康检查、多阶段构建Docker Compose 是微服务开发测试阶段的利器配合 Swarm 或 Kubernetes 可实现生产级容器编排。建议将 Compose 文件纳入版本控制并通过 CI/CD 流水线自动化部署。提示本实战代码已整理为可运行模板你可以基于此架构快速搭建自己的微服务平台。生产环境建议结合 Docker Swarm 或 Kubernetes 实现更强大的编排能力。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2454942.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!