Docker swarm 集群搭建实战

Docker swarm集群搭建实战

下面是一个完整、可落地的 Docker Swarm 项目实战示例,涵盖:

  • 15 台服务器节点规划
  • Swarm 集群初始化与节点加入
  • 自研 Web 应用(Python Flask)开发 + Docker 镜像构建
  • 使用私有镜像仓库(本地 registry)避免依赖公网
  • 通过 docker stack deploy 一键部署包含 Nginx、Web App、PostgreSQL 的完整应用栈
  • 精确控制服务调度(nginx/db 专用节点)

🧩 一、节点规划(共 15 节点)

类型 数量 主机名前缀 用途
Manager 3 manager-1 ~ manager-3 集群管理(不跑应用)
Worker - Nginx 3 nginx-1 ~ nginx-3 仅运行 Nginx
Worker - DB 2 db-1, db-2 仅运行 PostgreSQL
Worker - App 7 app-1 ~ app-7 运行你的 Web 应用(也可让 nginx/db 节点兼跑,但本例隔离)

✅ 所有节点操作系统:Ubuntu 22.04,已安装 Docker Engine ≥ 24.0


🌐 二、网络与端口要求

确保以下端口在所有节点间互通:

  • 2377/tcp:Swarm 管理
  • 7946/tcp+udp:节点通信
  • 4789/udp:Overlay 网络(VXLAN)
  • 5000/tcp:本地私有镜像仓库(可选)

🔨 三、步骤 1:在 manager-1 初始化 Swarm

bash 复制代码
# 在 manager-1 (IP: 192.168.1.101) 上执行
docker swarm init --advertise-addr 192.168.1.101

记下输出的 worker join token,例如:

text 复制代码
docker swarm join --token SWMTKN-1-abc...xyz 192.168.1.101:2377

👥 四、步骤 2:加入其他节点

1. 加入另外 2 个 Manager(高可用)

manager-2manager-3 上执行(先获取 manager token):

bash 复制代码
# 在 manager-1 上运行:
docker swarm join-token manager
# 得到类似命令,在 manager-2/3 上执行

2. 所有 12 个 Worker 加入集群

每个 Worker 节点(nginx-1~3, db-1~2, app-1~7)上执行:

bash 复制代码
docker swarm join --token SWMTKN-1-abc...xyz 192.168.1.101:2377

验证:

bash 复制代码
# 在任意 Manager 上
docker node ls
# 应看到 15 个节点(3 Manager + 12 Worker),状态 Ready

🏷️ 五、步骤 3:给节点打标签(用于调度控制)

bash 复制代码
# 标记 Nginx 节点
for i in {1..3}; do
  docker node update --label-add role=nginx nginx-$i
done

# 标记 DB 节点
docker node update --label-add role=db db-1
docker node update --label-add role=db db-2

# (可选)标记 App 节点(本例中 app 服务不限制,可跑在任意非-manager 节点)
# 如果想限制,也可打 label: role=app

📦 六、步骤 4:构建你的 Web 应用程序(Python Flask)

1. 创建项目目录

bash 复制代码
mkdir my-web-app && cd my-web-app

2. 编写 app.py

python 复制代码
# app.py
from flask import Flask
import psycopg2
import os

app = Flask(__name__)

@app.route('/health')
def health():
    return {"status": "ok", "service": "my-web-app"}

@app.route('/api/db')
def test_db():
    try:
        conn = psycopg2.connect(
            host=os.getenv("DB_HOST", "db"),
            user="postgres",
            password=os.getenv("DB_PASSWORD", "mysecretpassword"),
            dbname="myapp"
        )
        cur = conn.cursor()
        cur.execute("SELECT NOW();")
        now = cur.fetchone()[0]
        cur.close()
        conn.close()
        return {"status": "db connected", "time": str(now)}
    except Exception as e:
        return {"error": str(e)}, 500

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

3. requirements.txt

复制代码
flask==3.0.0
psycopg2-binary==2.9.9
gunicorn==22.0.0

4. Dockerfile

dockerfile 复制代码
FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000
CMD ["gunicorn", "--workers", "2", "--bind", "0.0.0.0:5000", "app:app"]

🖼️ 七、步骤 5:构建并推送镜像(使用本地私有 Registry)

💡 为避免依赖 Docker Hub,我们在 manager-1 上启动一个本地 registry。

1. 启动本地镜像仓库(在 manager-1)

bash 复制代码
docker run -d -p 5000:5000 --name registry registry:2

2. 构建并推送镜像

bash 复制代码
# 构建(注意 tag 为 localhost:5000/my-web-app:v1)
docker build -t localhost:5000/my-web-app:v1 .

# 推送
docker push localhost:5000/my-web-app:v1

3. 在所有 Worker 节点配置信任(因是 HTTP registry)

每个 Worker 节点/etc/docker/daemon.json 中添加:

json 复制代码
{
  "insecure-registries": ["192.168.1.101:5000"]
}

然后重启 Docker:

bash 复制代码
sudo systemctl restart docker

✅ 现在所有节点都能拉取 192.168.1.101:5000/my-web-app:v1


📄 八、步骤 6:编写 stack.yml 应用栈

yaml 复制代码
# stack.yml
version: '3.8'

services:
  # PostgreSQL 数据库(仅在 db 节点)
  db:
    image: postgres:15
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.labels.role == db
      restart_policy:
        condition: on-failure
    environment:
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - appnet

  # 自研 Web 应用(可在任意 Worker 运行,不含 Manager)
  app:
    image: 192.168.1.101:5000/my-web-app:v1
    deploy:
      replicas: 6
      restart_policy:
        condition: on-failure
      # 可选:避免调度到 Manager(默认不会,但显式更安全)
      placement:
        constraints:
          - node.role == worker
    environment:
      DB_HOST: db
      DB_PASSWORD: mysecretpassword
    networks:
      - appnet
    depends_on:
      - db

  # Nginx 反向代理(仅在 nginx 节点)
  web:
    image: nginx:alpine
    deploy:
      replicas: 3
      placement:
        constraints:
          - node.labels.role == nginx
      restart_policy:
        condition: on-failure
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: ingress
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - appnet
    depends_on:
      - app

volumes:
  db_data:

networks:
  appnet:
    driver: overlay
    attachable: true

⚙️ 九、步骤 7:准备 Nginx 配置

创建 nginx.conf(与 stack.yml 同目录):

nginx 复制代码
events {
    worker_connections 1024;
}

http {
    upstream backend {
        server app:5000;  # Swarm DNS 自动负载均衡
    }

    server {
        listen 80;

        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

🚀 十、步骤 8:部署整个应用栈

bash 复制代码
# 确保当前目录有 stack.yml 和 nginx.conf
ls -l

# 部署(使用 --with-registry-auth 传递 registry 认证,虽本地无需,但好习惯)
docker stack deploy -c stack.yml --with-registry-auth myapp

🔍 十一、验证部署

1. 查看服务

bash 复制代码
docker service ls

应看到:

复制代码
myapp_app   replicated  6/6   192.168.1.101:5000/my-web-app:v1
myapp_web   replicated  3/3   nginx:alpine
myapp_db    replicated  2/2   postgres:15

2. 检查任务分布

bash 复制代码
docker service ps myapp_db    # 应只在 db-1/db-2
docker service ps myapp_web   # 应只在 nginx-1~3
docker service ps myapp_app   # 应在任意 Worker(不含 Manager)

3. 测试外部访问

从你本地电脑访问任一节点 IP:

bash 复制代码
curl http://192.168.1.111/health
# 返回: {"status": "ok", "service": "my-web-app"}

curl http://192.168.1.101/api/db
# 返回: {"status": "db connected", "time": "2026-02-05 08:30:00..."}

✅ 成功!你的自研 Web 服务已在 15 节点 Swarm 集群中运行!


🔄 十二、后续运维(可选)

更新 Web 应用

bash 复制代码
# 修改代码 → 重新 build & push v2
docker build -t 192.168.1.101:5000/my-web-app:v2 .
docker push 192.168.1.101:5000/my-web-app:v2

# 滚动更新
docker service update --image 192.168.1.101:5000/my-web-app:v2 myapp_app

扩容

bash 复制代码
docker service scale myapp_app=10

查看日志

bash 复制代码
docker service logs myapp_app --tail 50 -f

✅ 总结:你完成了什么?

步骤 成果
✅ 集群搭建 3 Manager + 12 Worker,高可用
✅ 节点标签 精确控制 nginx/db 调度
✅ 自研应用 Python Flask + PostgreSQL
✅ 镜像管理 本地私有 registry,不依赖外网
✅ 网络通信 Overlay 网络 + 内置 DNS
✅ 外部访问 Routing Mesh + Nginx 反向代理
✅ 一键部署 docker stack deploy

这个架构可直接用于中小型生产环境,具备弹性、高可用、易维护等云原生特性。

如需扩展为 Java/Node.js,只需替换 Dockerfile 和应用代码,其余编排逻辑完全通用!

相关推荐
划水的code搬运工小李2 小时前
Ubuntu下挂载NTFS格式磁盘
linux·运维·ubuntu
炸裂狸花猫2 小时前
开源域名代理与流量限制方案 - Cloudflare + Ingress + 自签名证书
运维·云原生·容器·kubernetes·cloudflare·waf·免费域名证书
佑白雪乐2 小时前
<Linux基础12集>1-11集大复习Review
linux·运维·策略模式
鹏大师运维2 小时前
信创桌面操作系统上的WPS外观界面配置
linux·运维·wps·麒麟·统信uos·中科方德·整合模式
代码游侠2 小时前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
工程师0072 小时前
计算机网络知识(一)
运维·服务器·计算机网络
江湖有缘2 小时前
Docker环境下使用RustScan端口扫描工具教程
运维·docker·容器
海棠AI实验室2 小时前
VS Code Remote-SSH :原理、前置条件、配置套路与踩坑清单
运维·ssh
梦想的旅途22 小时前
Java/Python/Go 实现企微外部群自动化消息推送
运维·自动化·企业微信