打造Docker Swarm集群服务编排部署指南:从入门到精通

发布于:2025-07-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. 为什么选择 Docker Swarm?

Docker Swarm 是 Docker 原生的集群管理与服务编排工具,简单、轻量、开箱即用。如果你正在寻找一个既能快速上手,又能应对中小型生产环境的解决方案,Swarm 绝对值得一试。相比 Kubernetes 的复杂配置,Swarm 的学习曲线更平缓,但功能却一点不含糊:负载均衡服务发现滚动更新高可用,全都能轻松搞定。

Swarm 的核心优势

  • 原生集成:无需额外安装,Docker CLI 直接支持 Swarm 命令。

  • 简单易用:几行命令就能搭建集群,适合快速部署。

  • 生产可用:支持多节点高可用、自动故障转移。

  • 灵活扩展:轻松增加节点,动态调整服务规模。

但它也不是万能的。如果你需要超大规模集群(比如上千节点)或复杂的 CRD(自定义资源定义),Kubernetes 可能更适合。不过,对于中小型团队,Swarm 的“简单即强大”哲学能让你省下不少心力。

2. 基础概念扫盲:Swarm 的核心组件

在动手之前,先搞清楚 Swarm 的几个关键概念,这样后续操作才能心中有数。

  • 节点(Node):集群中的每台机器都是一个节点,分为 Manager(管理节点)和 Worker(工作节点)。管理节点负责调度任务、维护集群状态,工作节点跑具体的容器。

  • 服务(Service):Swarm 的核心编排单位,定义了容器如何运行、需要几个副本、暴露哪些端口等。

  • 任务(Task):服务的具体执行单位,通常是一个容器。

  • 栈(Stack):通过 YAML 文件定义一组服务,类似 Kubernetes 的 Helm Chart,方便批量部署。

  • 覆盖网络(Overlay Network):Swarm 提供的虚拟网络,节点之间通过它通信,天然支持服务发现。

小贴士:Swarm 的覆盖网络默认加密,通信安全有保障,但高负载场景下可能略影响性能,记得根据业务场景权衡!

3. 环境准备:打造你的 Swarm 试验田

动手之前,先准备好实验环境。以下是我推荐的配置,简单但足以模拟生产场景:

硬件与系统要求

  • 机器:至少 3 台虚拟机或云服务器(1 台 Manager,2 台 Worker),每台建议 2 核 4GB 内存。

  • 操作系统:Ubuntu 20.04 LTS 或 CentOS 8(其他 Linux 发行版也行,但确保内核支持 Docker)。

  • 网络:确保节点间网络互通,防火墙开放以下端口:

    • TCP 2377:管理通信(加密)

    • TCP/UDP 7946:节点间通信

    • UDP 4789:覆盖网络数据传输

安装 Docker

在每台机器上安装最新版 Docker(以 Ubuntu 为例):

# 更新包索引
sudo apt-get update
# 安装依赖
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加 Docker 软件源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# 验证安装
docker --version

注意:确保所有节点的 Docker 版本一致,避免兼容性问题。可以用 docker version 检查。

配置节点

为便于管理,给每台机器起个好记的名字:

  • Manager 节点:swarm-manager

  • Worker 节点:swarm-worker1、swarm-worker2

# 设置主机名(以 swarm-manager 为例)
sudo hostnamectl set-hostname swarm-manager

4. 初始化 Swarm 集群

好了,准备工作就绪,接下来正式组建 Swarm 集群!

4.1 在 Manager 节点初始化

在 swarm-manager 上运行以下命令:

docker swarm init --advertise-addr <MANAGER_IP>

--advertise-addr 指定 Manager 的 IP 地址(用 ifconfig 或 ip addr 查看节点 IP)。执行后,你会看到类似以下输出:

Swarm initialized: current node (xxxx) is now a manager.

To add a worker to this swarm, run the following command:
    docker swarm join --token SWMTKN-1-xxxx <MANAGER_IP>:2377

To add a manager to this swarm, run the following command:
    docker swarm join --token SWMTKN-2-xxxx <MANAGER_IP>:2377

复制 docker swarm join 的 Worker 令牌,准备加入 Worker 节点。

4.2 加入 Worker 节点

在 swarm-worker1 和 swarm-worker2 上运行 Manager 提供的 join 命令,例如:

docker swarm join --token SWMTKN-1-xxxx <MANAGER_IP>:2377

成功后,输出会提示节点已加入集群。

4.3 验证集群状态

回到 Manager 节点,运行:

docker node ls

你会看到类似以下输出:

ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
xxxx *                        swarm-manager      Ready               Active              Leader
yyyy                          swarm-worker1      Ready               Active
zzzz                          swarm-worker2      Ready               Active

恭喜!你的 Swarm 集群已经搭建完成!接下来,我们要开始真正的服务编排了。

5. 部署第一个服务:从简单到复杂

让我们从一个简单的 Nginx 服务开始,逐步深入 Swarm 的服务编排功能。

5.1 部署单容器服务

在 Manager 节点运行:

docker service create --name my-nginx -p 8080:80 nginx:latest

这条命令做了啥?

  • --name:给服务命名。

  • -p 8080:80:将主机的 8080 端口映射到容器的 80 端口。

  • nginx:latest:使用最新的 Nginx 镜像。

运行后,用 docker service ls 查看服务状态:

ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
xxxx                my-nginx            replicated          1/1                 nginx:latest        *:8080->80/tcp

访问 http://<任一节点IP>:8080,你会看到 Nginx 的欢迎页面!

5.2 扩展服务规模

假设流量增加,单容器不够用,我们扩展到 3 个副本:

docker service scale my-nginx=3

Swarm 会自动在集群中调度 3 个 Nginx 容器,可能分布在不同节点。用 docker service ps my-nginx 查看任务分布:

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE
xxxx                my-nginx.1          nginx:latest        swarm-manager       Running             Running 5 minutes ago
yyyy                my-nginx.2          nginx:latest        swarm-worker1       Running             Running 4 minutes ago
zzzz                my-nginx.3          nginx:latest        swarm-worker2       Running             Running 4 minutes ago

小技巧:Swarm 的调度器默认使用 spread 策略,尽量将任务均匀分布到节点上,减少单点压力。

5.3 更新服务:零停机滚动更新

假如你想更新 Nginx 到特定版本(比如 nginx:1.21),Swarm 支持无缝滚动更新:

docker service update --image nginx:1.21 my-nginx

Swarm 会逐个替换容器,确保服务不中断。你可以用 --update-delay 10s 设置更新间隔,避免更新过快。

6. 覆盖网络:让服务互联互通

Swarm 的覆盖网络是服务通信的秘密武器。让我们创建一个自定义网络,并部署两个服务验证通信。

6.1 创建覆盖网络

在 Manager 节点运行:

docker network create --driver overlay my-overlay-network

6.2 部署带网络的服务

假设我们要部署一个前端(Nginx)和后端(自定义 API)服务,它们通过 my-overlay-network 通信。

前端服务

docker service create --name frontend \
  --network my-overlay-network \
  -p 8080:80 \
  nginx:latest

后端服务(假设用一个简单的 Python Flask 应用): 先创建一个简单的 Flask 应用镜像(后续会详细讲如何构建):

# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY app.py .
RUN pip install flask
CMD ["python", "app.py"]
# app.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello from Backend!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

构建并推送镜像到 Docker Hub(或其他镜像仓库):

docker build -t yourusername/my-flask-app:latest .
docker push yourusername/my-flask-app:latest

部署后端服务:

docker service create --name backend \
  --network my-overlay-network \
  yourusername/my-flask-app:latest

6.3 测试服务通信

在前端容器中访问后端服务(Swarm 的服务发现基于 DNS):

docker exec -it <frontend-container-id> curl http://backend:5000

你会看到 Hello from Backend! 的输出。Swarm 的覆盖网络让服务间通信像在同一台机器上一样简单!

7. 日志收集:让问题无处遁形

生产环境中,日志是排查问题的命脉。Swarm 默认将容器日志存储在节点本地,但分散的日志管理起来很麻烦。我们需要一个集中化的日志收集方案。

7.1 使用 Docker 日志驱动

Docker 支持多种日志驱动,推荐使用 FluentdLoki 收集日志。我们以 Fluentd 为例,搭建一个简单的日志收集系统。

步骤 1:部署 Fluentd 服务

创建一个 Fluentd 配置文件 fluentd.conf:

<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

<match docker.**>
  @type stdout
</match>

构建 Fluentd 镜像:

# Dockerfile
FROM fluent/fluentd:v1.14-1
COPY fluentd.conf /fluentd/etc/fluentd.conf
docker build -t yourusername/fluentd:latest .
docker push yourusername/fluentd:latest

在 Stack 文件中添加 Fluentd 服务:

version: '3.8'

services:
  fluentd:
    image: yourusername/fluentd:latest
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    ports:
      - "24224:24224"
    networks:
      - wp-network
  wordpress:
    image: wordpress:latest
    deploy:
      replicas: 3
    ports:
      - "8080:80"
    logging:
      driver: fluentd
      options:
        fluentd-address: fluentd:24224
    networks:
      - wp-network
  mysql:
    image: mysql:8.0
    deploy:
      replicas: 1
    volumes:
      - wp-data:/var/lib/mysql
    logging:
      driver: fluentd
      options:
        fluentd-address: fluentd:242Så24
    networks:
      - wp-network

networks:
  wp-network:
    driver: overlay

volumes:
  wp-data:

步骤 2:部署并验证

docker stack deploy -c wordpress-stack.yml wp-stack

Fluentd 会收集 WordPress 和 MySQL 的日志,输出到标准输出。你可以通过 docker service logs wp-stack_fluentd 查看收集的日志。

进阶玩法:将 Fluentd 配置为将日志转发到 Elasticsearch 或 Loki,再用 Grafana 可视化,打造一个强大的日志分析平台。

8. 监控:让集群健康一目了然

没有监控的集群就像开夜车没开大灯,迟早要撞墙。我们需要实时了解集群的健康状态、资源使用情况和服务性能。

8.1 使用 Prometheus 和 Grafana

Prometheus 是监控领域的明星,搭配 Grafana 的仪表盘,简直是运维的“千里眼”。我们用 Stack 文件部署一个监控堆栈。

监控 Stack 文件:monitoring-stack.yml

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:v2.37.0
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    volumes:
      - prometheus-data:/prometheus
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      - monitoring-network

  node-exporter:
    image: prom/node-exporter:v1.3.1
    deploy:
      mode: global
    networks:
      - monitoring-network

  grafana:
    image: grafana/grafana:8.5.0
    deploy:
      replicas: 1
    ports:
      - "3000:3000"
    networks:
      - monitoring-network
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123

networks:
  monitoring-network:
    driver: overlay

volumes:
  prometheus-data:

Prometheus 配置文件:prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['prometheus:9090']
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']
  - job_name: 'docker'
    static_configs:
      - targets: ['<manager-ip>:9323']

注意:Docker 默认不暴露 metrics 端点,需在 Manager 节点的 /etc/docker/daemon.json 中启用:

{
  "metrics-addr": "0.0.0.0:9323",
  "experimental": true
}

重启 Docker 服务:

sudo systemctl restart docker

部署监控堆栈

docker stack deploy -c monitoring-stack.yml monitoring

访问 http://<manager-ip>:3000,用默认账户(admin/admin123)登录 Grafana,导入 Docker 和 Node Exporter 的仪表盘模板(Grafana 社区有现成的模板,ID 比如 1860 或 11074),你就能看到节点 CPU、内存、容器状态等实时数据。

实战经验:为关键服务添加自定义 metrics(比如 WordPress 的请求延迟),可以进一步优化监控效果。

9. 负载均衡:让流量分配更聪明

Swarm 内置的负载均衡器(基于 IPVS)已经很强大,但我们可以通过一些配置让它更高效。

9.1 外部负载均衡

如果你的集群暴露多个服务,建议在 Swarm 前加一层 Nginx 或 HAProxy 作为外部负载均衡器。例如,部署一个 Nginx 服务作为反向代理:

version: '3.8'

services:
  proxy:
    image: nginx:latest
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - wp-network

networks:
  wp-network:
    driver: overlay

Nginx 配置文件:nginx.conf

worker_processes 1;

events { worker_connections 1024; }

http {
    upstream wordpress {
        server wordpress:80;
    }

    server {
        listen 80;
        server_name _;

        location / {
            proxy_pass http://wordpress;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

部署后,外部流量通过 Nginx 打到 WordPress 服务,Swarm 内部负载均衡器再将流量分发到多个 WordPress 容器。

9.2 优化 Swarm 内置负载均衡

Swarm 的负载均衡默认是基于 DNS 的轮询(round-robin)。如果需要更复杂的策略(如基于权重),可以结合外部负载均衡器或调整服务副本数。

小技巧:用 docker service update --endpoint-mode vip(默认模式)确保负载均衡稳定。如果服务通信频繁,考虑用 --endpoint-mode dnsrr 启用 DNS 轮询,减少 VIP 开销。

10. 安全加固:让你的集群固若金汤

生产环境的 Swarm 集群就像一座城堡,功能再强大也得防住“入侵者”。我们将从 Secrets 管理TLS 加密访问控制 三方面加固你的集群。

10.1 Secrets 管理:保护敏感数据

数据库密码、API 密钥等敏感信息不能明文写在 Stack 文件或环境变量里。Swarm 提供了 Secrets 功能,让你安全地存储和分发敏感数据。

创建 Secrets

假设我们的电商系统需要保护 Redis 的密码。先在 Manager 节点创建 Secret:

echo "supersecretpassword" | docker secret create redis_password -

检查 Secret 是否创建成功:

docker secret ls

输出类似:

ID                          NAME                CREATED             UPDATED
xxxx                        redis_password      5 minutes ago       5 minutes ago

在 Stack 文件中使用 Secrets

修改 ecommerce-stack.yml,将 Redis 的密码通过 Secret 注入:

version: '3.8'

services:
  frontend:
    image: yourusername/ecommerce-frontend:latest
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    ports:
      - "3000:3000"
    networks:
      - ecommerce-network
    depends_on:
      - backend

  backend:
    image: yourusername/ecommerce-backend:latest
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    environment:
      REDIS_HOST: redis
      REDIS_PASSWORD_FILE: /run/secrets/redis_password
    secrets:
      - redis_password
    networks:
      - ecommerce-network
    depends_on:
      - redis

  redis:
    image: redis:6.2
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    command: redis-server --requirepass $(cat /run/secrets/redis_password)
    volumes:
      - redis-data:/data
    secrets:
      - redis_password
    networks:
      - ecommerce-network

networks:
  ecommerce-network:
    driver: overlay

volumes:
  redis-data:

secrets:
  redis_password:
    external: true

代码调整

修改后端代码以读取 Secret 文件:

// backend/index.js
const express = require('express');
const redis = require('redis');
const fs = require('fs');
const app = express();

const password = fs.readFileSync('/run/secrets/redis_password', 'utf8').trim();
const client = redis.createClient({ 
  url: `redis://:${password}@redis:6379` 
});
client.connect();

app.get('/products', async (req, res) => {
  const cached = await client.get('products');
  if (cached) return res.json(JSON.parse(cached));

  const products = [
    { id: 1, name: 'Laptop', price: 999 },
    { id: 2, name: 'Phone', price: 499 }
  ];
  await client.set('products', JSON.stringify(products), { EX: 3600 });
  res.json(products);
});

app.listen(3001, () => console.log('Backend running on port 3001'));

重新构建并推送镜像:

docker build -t yourusername/ecommerce-backend:latest ./backend
docker push yourusername/ecommerce-backend:latest
docker stack deploy -c ecommerce-stack.yml ecommerce

安全提示:Secrets 存储在 Manager 节点的 Raft 数据库中,加密传输到容器。定期轮换 Secrets(删除旧的,创建新的),并限制 Manager 节点的访问权限。

10.2 TLS 加密:保护网络通信

Swarm 默认加密管理流量(2377 端口)和覆盖网络,但外部流量(如用户访问前端的 HTTP 请求)需要额外的 TLS 保护。我们用 Nginx 反向代理加上 Let’s Encrypt 的免费证书来实现 HTTPS。

部署 Certbot 获取证书

在 Manager 节点运行 Certbot 容器获取证书:

docker run -it --rm -v certs:/etc/letsencrypt -p 80:80 certbot/certbot certonly --standalone -d yourdomain.com

证书会存储在 certs 卷中。

更新 Nginx 配置

修改 nginx.conf 支持 HTTPS:

worker_processes 1;

events { worker_connections 1024; }

http {
    upstream frontend {
        server frontend:3000;
    }

    server {
        listen 80;
        server_name yourdomain.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name yourdomain.com;

        ssl_certificate /etc/nginx/certs/live/yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/live/yourdomain.com/privkey.pem;

        location / {
            proxy_pass http://frontend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

更新 ecommerce-stack.yml 加入 Nginx 服务:

version: '3.8'

services:
  proxy:
    image: nginx:latest
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - certs:/etc/nginx/certs
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - ecommerce-network
  frontend:
    image: yourusername/ecommerce-frontend:latest
    deploy:
      replicas: 3
    networks:
      - ecommerce-network
  backend:
    image: yourusername/ecommerce-backend:latest
    deploy:
      replicas: 2
    environment:
      REDIS_HOST: redis
      REDIS_PASSWORD_FILE: /run/secrets/redis_password
    secrets:
      - redis_password
    networks:
      - ecommerce-network
  redis:
    image: redis:6.2
    deploy:
      replicas: 1
    command: redis-server --requirepass $(cat /run/secrets/redis_password)
    volumes:
      - redis-data:/data
    secrets:
      - redis_password
    networks:
      - ecommerce-network

networks:
  ecommerce-network:
    driver: overlay

volumes:
  redis-data:
  certs:

secrets:
  redis_password:
    external: true

部署并验证

docker stack deploy -c ecommerce-stack.yml ecommerce

访问 https://yourdomain.com,你会看到安全的电商前端页面。注意:定期用 Certbot 续期证书(每 90 天),可以用定时任务自动化。

10.3 访问控制:最小权限原则

  • 限制 Docker API 访问:默认情况下,Docker 守护进程监听 unix:///var/run/docker.sock。如果暴露了 TCP 端口(如 2375),务必用防火墙限制访问:

sudo ufw allow from <trusted-ip> to any port 2375
  • RBAC:Swarm 本身不提供细粒度 RBAC,但可以通过限制 Manager 节点的 SSH 访问和 Docker CLI 权限来实现。例如,只允许特定用户运行 docker 命令:

sudo groupadd docker
sudo usermod -aG docker <username>
  • 节点隔离:用 node.labels 将敏感服务(如数据库)限制在特定节点,防止非授权节点运行。

11. 性能优化:榨干集群的每一分潜力

Swarm 集群的性能直接影响服务的响应速度和用户体验。我们从 容器资源调优网络优化 两方面入手。

11.1 容器资源调优

在 Part 2,我们为服务设置了 CPU 和内存限制,但这只是基础。以下是一些进阶技巧:

  • 动态调整资源:根据负载动态调整副本数。Swarm 没有内置的 HPA(水平自动扩展),但可以用外部工具(如 Prometheus + 自定义脚本)实现。例如,监控前端服务的 CPU 使用率,超过 70% 时增加副本:

#!/bin/bash
CPU_USAGE=$(curl -s http://<prometheus-ip>:9090/api/v1/query?query=rate(container_cpu_usage_seconds_total{service="ecommerce_frontend"}[5m]) | jq '.data.result[0].value[1]' | awk '{print $1*100}')
if (( $(echo "$CPU_USAGE > 70" | bc -l) )); then
  docker service scale ecommerce_frontend=5
fi

将脚本加入 cron 每分钟运行。

  • 内存优化:避免容器内存泄漏。定期用 docker stats 检查容器内存使用情况,必要时重启服务:

docker service update --force ecommerce_frontend

11.2 网络优化

Swarm 的覆盖网络虽然方便,但高流量场景下可能成为瓶颈。优化方法:

  • 减少跨节点通信:用 placement 约束将相关服务调度到同一节点,降低网络延迟。例如,将前端和后端放在同一节点:

frontend:
  image: yourusername/ecommerce-frontend:latest
  deploy:
    replicas: 3
    placement:
      constraints:
        - node.labels.type == app
  backend:
    image: yourusername/ecommerce-backend:latest
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.labels.type == app

给节点加标签:

docker node update --label-add type=app swarm-worker1
  • 启用压缩:在 Nginx 反向代理中启用 Gzip 压缩,减少数据传输量:

http {
    gzipocios2
    gzip on;
    gzip_types text/plain text/css application/json;
}
  • 调整 MTU:如果网络性能不佳,检查节点的 MTU 设置,确保与覆盖网络一致(默认 1500)。

12. 复杂分布式系统:带消息队列的架构

让我们部署一个更复杂的系统,加入 RabbitMQ 作为消息队列,用于异步处理订单。

Stack 文件:ecommerce-mq-stack.yml

version: '3.8'

services:
  proxy:
    image: nginx:latest
    deploy:
      replicas: 1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - certs:/etc/nginx/certs
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - ecommerce-network
  frontend:
    image: yourusername/ecommerce-frontend:latest
    deploy:
      replicas: 3
    networks:
      - ecommerce-network
  backend:
    image: yourusername/ecommerce-backend:latest
    deploy:
      replicas: 2
    environment:
      REDIS_HOST: redis
      REDIS_PASSWORD_FILE: /run/secrets/redis_password
      RABBITMQ_HOST: rabbitmq
    secrets:
      - redis_password
    networks:
      - ecommerce-network
  redis:
    image: redis:6.2
    deploy:
      replicas: 1
    command: redis-server --requirepass $(cat /run/secrets/redis_password)
    volumes:
      - redis-data:/data
    secrets:
      - redis_password
    networks:
      - ecommerce-network
  rabbitmq:
    image: rabbitmq:3.9-management
    deploy:
      replicas: 1
    ports:
      - "15672:15672"
    networks:
      - ecommerce-network
    environment:
      RABBITMQ_DEFAULT_USER: guest
      RABBITMQ_DEFAULT_PASS: guest

networks:
  ecommerce-network:
    driver: overlay

volumes:
  redis-data:
  certs:

secrets:
  redis_password:
    external: true

后端代码调整

添加 RabbitMQ 生产者,处理订单:

// backend/index.js
const amqp = require('amqplib');
const express = require('express');
const redis = require('redis');
const fs = require('fs');
const app = express();

const password = fs.readFileSync('/run/secrets/redis_password', 'utf8').trim();
const client = redis.createClient({ url: `redis://:${password}@redis:6379` });
client.connect();

async function sendToQueue(order) {
  const conn = await amqp.connect('amqp://guest:guest@rabbitmq:5672');
  const channel = await conn.createChannel();
  await channel.assertQueue('orders');
  channel.sendToQueue('orders', Buffer.from(JSON.stringify(order)));
  await channel.close();
  await conn.close();
}

app.get('/products', async (req, res) => {
  const cached = await client.get('products');
  if (cached) return res.json(JSON.parse(cached));

  const products = [
    { id: 1, name: 'Laptop', price: 999 },
    { id: 2, name: 'Phone', price: 499 }
  ];
  await client.set('products', JSON.stringify(products), { EX: 3600 });
  res.json(products);
});

app.post('/order', express.json(), async (req, res) => {
  await sendToQueue(req.body);
  res.json({ message: 'Order placed' });
});

app.listen(3001, () => console.log('Backend running on port 3001'));

部署并测试

docker stack deploy -c ecommerce-mq-stack.yml ecommerce

访问 RabbitMQ 管理界面 http://<node-ip>:15672(默认用户/密码:guest/guest),查看订单队列。发送一个 POST 请求到 /order,检查队列是否收到消息。


网站公告

今日签到

点亮在社区的每一天
去签到