案例 海狸IM 2.1 私有化部署:中间件、Go 微服务与 Nginx 的启动顺序

2026-10-01 20:01:32

海狸IM 2.1 私有化部署:中间件、Go 微服务与 Nginx 的启动顺序

海狸IM 部署到自己服务器上,数据不出机房,是私有化 IM 的常见诉求。

一、先搞清楚你要部署的是什么

海狸IM 的后端不是单体服务,而是一套 Go + go-zero 微服务。看 beaver-server/app/ 目录,业务被拆成 user、chat、group、friend、moment、circle、emoji、file、call、notification、gateway、auth、open、platform 等 17 个模块,每个模块再分 API 层和 RPC 层。

微服务意味着两件事:

  1. 有一堆中间件依赖:MySQL(主存储)、Redis(缓存/会话)、ETCD(服务发现与配置)、RocketMQ(消息推送)、LiveKit(音视频)。
  2. 服务之间有启动顺序:先 RPC,再 API,最后 Admin,反过来不行。

二、服务器准备

官方文档(beaver-docs/guide/deployment.md)建议:

  • 最低:2 核 2.4GHz+ / 2GB / 50GB SSD / 10Mbps+
  • 推荐(100-1000 用户):4 核 3.0GHz+ / 8GB+ / 200GB+ SSD / 100Mbps+

系统建议 Ubuntu 20.04+ LTS,需要公网 IP + 域名。如果要把 RocketMQ、OpenSearch 日志栈全拉起来,内存别低于 4GB,不然 JVM 系组件会挤得很难受。

装 Docker 和 Docker Compose:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

装完记得重新登录一次让 docker 组生效。

三、第一步:拉起中间件

基础中间件(MySQL / Redis / ETCD / Nginx)用一个 docker-compose 拉起,放在 /mnt/docker/docker-compose.yml:

services:
  redis:
    image: redis:4
    command: redis-server --appendonly yes --requirepass "your_redis_password"
    ports:
      - "6379:6379"
    volumes:
      - ./redis:/data
  mysql:
    image: mysql:5.7.31
    restart: always
    privileged: true
    environment:
      MYSQL_ROOT_PASSWORD: "your_mysql_password"
    command: [
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_general_ci',
      '--max_connections=3000'
    ]
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/my.cnf
  etcd:
    image: quay.io/coreos/etcd:v3.5.15
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://your_internal_ip:2379,http://your_external_ip:2379
    ports:
      - "2379:2379"
  nginx:
    image: nginx
    restart: always
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d:/etc/nginx/conf.d

beaver-server/docker/docker-compose.yml 里还提供另外几样,按需起:

  • LiveKit:音视频必需。信令 7880、RTC over TCP 7881、UDP 媒体端口段 50000-50050。
  • RocketMQ 5.3.1:namesrv(9876)+ broker(10909-10912),还有一个 rocketmq-init 一次性任务,自动创建 ws_push_topic——WebSocket 消息推送走这个 topic。
  • 日志可观测栈(可选):OpenSearch 2.19 + Dashboards + OTel Collector(4317/4318 收 OTLP)。服务端 beaverlog 日志通过 OtlpAddr 配置推到这里。小团队可以先不起,不影响核心功能。

起服务之前先改三处:Redis 密码、MySQL root 密码、ETCD 的内外网广播地址。安全建议:随机密码(16-32 位),别用默认端口——3306、6379、2379 挂在公网上就是靶子。

cd /mnt/docker
docker-compose up -d
docker-compose ps

四、第二步:初始化数据库

新建数据库:库名 beaver,字符集 utf8mb4,排序规则 utf8mb4_bin。

把 main.go 里数据库连接的密码和地址改成你的,执行初始化:

go run main.go -db

看到输出 所有表结构生成成功 就说明建表完成。表结构是 GORM 风格自动生成的,不用手工导 SQL。

五、第三步:改服务端配置

beaver-server/deploy/ 下就是部署单元,每个服务一个目录(user_api/、user_rpc/、chat_api/……共 30 多个),各带一份 docker-compose 和 yaml 配置。

要改的配置集中在三处(对应 deploy/config.txt 里的替换规则):

# Etcd 地址
127.0.0.1:2379 -> 你的地址:2379
# MySQL 连接串
root:123456@tcp(127.0.0.1:3306)/beaver -> 你的账号密码@tcp(你的地址:端口)/beaver
# Redis 地址与密码
127.0.0.1:6379 -> 你的地址:端口
Password: '123456' -> Password: '你的密码'

改法两种:手工逐个改各服务目录下的 yaml,或改好 config.txt 之后跑 ./deploy/config.sh 批量替换(注意它会直接改写 yaml,不自动备份,跑之前最好留一份副本)。

镜像可以直接用官方 wsrh8888/ 开头的镜像,不用自己编译。

六、第四步:按顺序启动微服务

cd /mnt/beaver
./deploy/stop.sh
./deploy/start.sh

start.sh 的逻辑是:先创建 beaver_network(没有的话),然后按目录名后缀 _rpc → _api → _admin 分三批,每批对每个服务目录执行 down → pull → build → up -d,批间等 2 秒。stop.sh 反向按 Admin → API → RPC 停止并清理。

两个小坑:

  • Linux 上如果脚本因为空格转义问题起不来,文档给了一行修复:
sed -i 's/\\$/$/g' deploy/start.sh

(stop.sh 同理)

  • 想单独重启某个服务,进对应目录手动 docker-compose up -d 就行。

七、第五步:Nginx 收口

关键配置在 /mnt/docker/nginx/conf.d/server.conf:

location /beaver/api {
    rewrite ^/beaver/(.*)$ /$1 break;
    proxy_pass http://10.0.24.6:20800;  # 代理到宿主机服务
    # WebSocket 支持 - 必须加这三个头,否则长连接起不来
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 300;
    proxy_connect_timeout 30;
}

三个 WebSocket 头是 IM 的命根子,漏了的话登录能过、消息收不到。HTTPS 版本文档里也给了模板,证书放 ./nginx/ssl 挂载进去即可。

八、验证:从登录页到音视频

  1. 浏览器打开域名,能看到登录页 → Nginx 和 API 通了。
  2. 注册账号,密码登录成功 → 数据库、user 服务、gateway 正常。
  3. 客户端(桌面端 Electron)配置服务器地址后登录,能收发消息 → WebSocket 通了。
  4. 两个人发起音视频通话 → LiveKit 通了。这一步失败,九成是 7880/7881 没放行 TCP,或 50000-50050 没放行 UDP。

九、实际踩过的坑

  • 宿主机已有 MySQL 占了 3306:改映射端口("3307:3306"),同步改服务端连接串。
  • LiveKit 端口没放行:音视频一直连不上,聊天却一切正常,很有迷惑性。记得 UDP 端口段。
  • 防火墙只放了 TCP:云服务器安全组里 UDP 要单独勾。
  • RocketMQ dashboard(8080)和 OpenSearch Dashboards(5601)别裸奔在公网:这套管理界面默认没有鉴权,用安全组限制到内网或 VPN。

十、这套部署的边界

  • 不是“一条命令起全栈”:中间件 compose 和服务端 deploy/ 是分开的,中间还有数据库初始化、配置替换、按序启动几步。
  • 服务端本身不在中间件 compose 里:34 个微服务各自一个 compose 目录,由 start.sh 统一编排,这是 go-zero 项目常见形态。
  • 日志栈是可选组件:不起 OpenSearch/OTel 不影响功能,只是没有集中日志可查。
  • 文档在持续补:beaver-docs 的 deployment 章节目前覆盖到初始化和基础部署,高可用、扩容还没有。

参考链接

复制全文 生成海报 Go go-zero 微服务 私有化部署 Nginx Docker

推荐文章

程序员茄子在线接单