Files
SecMPS/owl_zlmediakit/联网部署手册.md
2026-05-15 23:22:48 +08:00

1636 lines
51 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GoWVP (Owl) + ZLMediaKit 飞腾S5000 + 统信UOS20 联网部署手册
> **文档版本**: v1.0
> **生成日期**: 2026-04-29
> **适用环境**: 飞腾S5000C (ARM64) + 统信UOS20服务器版(1070) + 联网环境
> **目标系统**: ARM64 (aarch64) / ARMv8.2
---
## 更新记录
| 版本号 | 更新人 | 更新日期/时间 | 更新内容 |
|--------|--------|---------------|----------|
| v1.0 | 浮浮酱 | 2026-04-29 | 初始版本,基于离线部署手册 v1.2 适配联网环境 |
---
## 目录
### 一级导航
1. [文档概述](#一文档概述)
2. [环境说明](#二环境说明)
3. [环境初始化](#三环境初始化)
4. [服务部署](#四服务部署)
5. [配置联动](#五配置联动)
6. [验证步骤](#六验证步骤)
7. [常见问题排查](#七常见问题排查)
8. [附录](#八附录)
### 二级导航
**一、文档概述**
- [1.1 部署架构](#11-部署架构)
- [1.2 部署方式选择](#12-部署方式选择)
**二、环境说明**
- [2.1 硬件环境](#21-硬件环境)
- [2.2 软件环境](#22-软件环境)
- [2.3 统信UOS版本确认方法](#23-统信uos版本确认方法)
- [2.4 网络环境](#24-网络环境)
**三、环境初始化**
- [3.1 确认系统版本和包管理器](#31-确认系统版本和包管理器)
- [3.2 安装 Docker](#32-安装docker)
- [3.3 配置 Docker 国内镜像加速(推荐)](#33-配置-docker-国内镜像加速推荐)
- [3.4 安装常用工具](#34-安装常用工具)
- [3.5 创建部署目录](#35-创建部署目录)
**四、服务部署**
- [4.1 拉取 Docker 镜像](#41-拉取-docker-镜像)
- [4.2 准备配置文件](#42-准备配置文件)
- [4.3 启动服务](#43-启动服务)
- [4.4 部署 ZLMediaKit单独运行方式](#44-部署-zlmediakit单独运行方式)
- [4.5 部署 GoWVPOwl单独运行方式](#45-部署-gowvpowl单独运行方式)
**五、配置联动**
- [5.1 ZLMediaKit Hook 配置](#51-zlmediakit-hook-配置)
- [5.2 GoWVP 环境变量配置](#52-gowvp-环境变量配置)
- [5.3 重启服务使配置生效](#53-重启服务使配置生效)
- [5.4 联动验证](#54-联动验证)
**六、验证步骤**
- [6.1 验证脚本](#61-验证脚本)
- [6.2 手动验证步骤](#62-手动验证步骤)
- [6.3 推流测试](#63-推流测试)
**七、常见问题排查**
- [7.1 Docker 无法启动](#71-docker-无法启动)
- [7.2 容器启动后立即退出](#72-容器启动后立即退出)
- [7.3 ARM64 镜像无法运行](#73-arm64-镜像无法运行)
- [7.4 GoWVP 无法连接 ZLMediaKit](#74-gowvp-无法连接-zlmediakit)
- [7.5 GB28181 设备无法接入](#75-gb28181-设备无法接入)
- [7.6 性能问题](#76-性能问题)
- [7.7 ARM64 架构稳定性问题(重要)](#77-arm64-架构稳定性问题重要)
**八、附录**
- [附录A: 端口清单](#附录a端口清单)
- [附录B: 源码编译 ZLMediaKit备用方案](#附录b源码编译zlmediakit备用方案)
- [附录C: 源码编译 GoWVP备用方案](#附录c源码编译gowvp备用方案)
- [附录D: 防火墙配置](#附录d防火墙配置)
- [附录E: 参考链接](#附录e参考链接)
- [附录F: ARM64 架构问题速查表](#附录farm64-架构问题速查表)
---
## 一、文档概述
本手册指导您在**可联网的生产环境**中,于**飞腾S5000C ARM64服务器**统信UOS20操作系统上完成以下部署
- **GoWVP (Owl)**: GB28181-2022 标准视频监控管理平台
- **ZLMediaKit**: 高性能流媒体服务器
- **联动配置**: 让 Owl 通过 HTTP API 和 WebHook 调用 ZLMediaKit 的流媒体能力
> 与离线部署手册的区别:本手册所有操作均在联网的生产服务器上直接执行,无需额外的联网笔记本准备离线包,部署流程更简洁。
### 1.1 部署架构
```
┌─────────────────────────────────────────────────────────────┐
│ 监控设备 (摄像头/NVR) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ GB28181 │ │ ONVIF │ │
│ │ 协议接入 │ │ 协议接入 │ │
│ └──────┬───────┘ └──────┬───────┘ │
└─────────────────────┼─────────────────┼──────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ 统信UOS20 服务器 (ARM64) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Docker 容器运行时 │ │
│ │ ┌─────────────────┐ ┌───────────────────────┐ │ │
│ │ │ GoWVP (Owl) │◄──►│ ZLMediaKit │ │ │
│ │ │ 容器 │API │ 流媒体容器 │ │ │
│ │ │ │Hook│ │ │ │
│ │ │ - GB28181 SIP │ │ - RTMP/RTSP/HLS │ │ │
│ │ │ - Web管理界面 │ │ - WebRTC/FLV │ │ │
│ │ │ - 设备管理 │ │ - 录像/转码 │ │ │
│ │ │ - AI检测(YOLO) │ │ │ │ │
│ │ └─────────────────┘ └───────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ 数据持久化卷 │
│ (./data 挂载到容器内的 /opt/media/bin/configs) │
└─────────────────────────────────────────────────────────────┘
```
### 1.2 部署方式选择
| 方案 | 说明 | 推荐度 | 适用场景 |
|------|------|--------|----------|
| **方案A: Docker Compose 融合部署** | 一个docker-compose.yml同时启动owl+ZLMediaKit | ⭐⭐⭐⭐⭐ | **本手册推荐,最简单** |
| **方案B: Docker 分离部署** | 两个独立容器通过Docker网络通信 | ⭐⭐⭐⭐ | 需要独立升级/维护时 |
| **方案C: 二进制直接部署** | 不依赖Docker直接运行可执行文件 | ⭐⭐⭐ | 服务器资源极度受限时 |
> **本手册以方案ADocker Compose 融合部署)为主**同时提供方案B和C的备用说明。
---
## 二、环境说明
### 2.1 硬件环境
| 项目 | 规格 |
|------|------|
| **CPU** | 飞腾腾云 S5000C (Phytium S5000C) |
| **指令集** | ARMv8.2 (64位兼容aarch64) |
| **核心数** | 16核 / 32核 / 64核 (根据采购型号) |
| **主频** | 2.1GHz (64核版) / 2.3GHz (32/16核版) |
| **内存** | 建议 >= 16GB DDR5 |
| **存储** | 建议 >= 500GB SSD (用于录像存储) |
| **网络** | 千兆以太网 (用于GB28181流媒体和Web管理) |
### 2.2 软件环境
| 项目 | 规格 |
|------|------|
| **操作系统** | 统信UOS服务器版 V20 (1070) |
| **镜像文件名** | `uos-server-20-military-1070-20251016-arm64.iso` |
| **内核版本** | kernel-4.19 (默认) / kernel-5.10 (可选) |
| **包管理器** | **需确认**:可能是 `yum`(A/E版本) 或 `apt`(D版本) |
| **架构** | aarch64 / ARM64 |
### 2.3 统信UOS版本确认方法
在**生产环境服务器**上执行以下命令确认系统版本:
```bash
# 查看操作系统详细信息
cat /etc/os-release
# 查看系统版本标记
cat /etc/system-release 2>/dev/null || cat /etc/centos-release 2>/dev/null || cat /etc/debian_version 2>/dev/null
# 查看包管理器类型
which apt-get && echo "使用 apt (Debian系)"
which yum && echo "使用 yum (RHEL系)"
```
**判断依据:**
- 如果看到 `Anolis``openEuler``uel20` 等字样 -> **A/E版本使用 `yum`**
- 如果看到 `Debian``Ubuntu` 等字样 -> **D版本使用 `apt`**
- 1070军事版通常基于龙蜥/欧拉,**大概率使用 `yum/dnf`**
### 2.4 网络环境
| 环境 | 网络状态 | 用途 |
|------|----------|------|
| **生产服务器** | **可访问互联网** | 下载镜像、安装依赖、部署服务 |
| **网络要求** | 可访问 Docker Hub 或国内镜像仓库 | 拉取 ARM64 容器镜像 |
| **带宽建议** | >= 10Mbps | Docker 镜像总大小约 500MB-1GB |
---
## 三、环境初始化
> **本章节所有操作在生产环境服务器上执行**,服务器需保持联网状态。
### 3.1 确认系统版本和包管理器
```bash
# 1. 查看操作系统信息
cat /etc/os-release
# 2. 确认包管理器
which yum && echo "使用 yum" || echo "未安装 yum"
which apt-get && echo "使用 apt" || echo "未安装 apt-get"
# 3. 确认架构
uname -m
# 预期输出: aarch64
# 4. 确认CPU信息
cat /proc/cpuinfo | grep "model name" | head -1
```
### 3.2 安装 Docker
#### 3.2.1 通过包管理器安装(推荐)
**如果系统使用 `yum` (A/E版本 - 龙蜥/欧拉):**
```bash
# 1. 更新系统包(可选,首次部署建议执行)
sudo yum update -y
# 2. 安装必要依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 3. 添加 Docker 官方仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 4. 安装 Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 5. 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 6. 验证安装
docker --version
docker-compose --version 2>/dev/null || echo "docker-compose 未安装,将在下一步安装"
```
> **如果添加官方仓库失败**部分内网环境限制可使用统信UOS自带仓库安装
> ```bash
> # 直接使用系统仓库安装
> sudo yum install -y docker docker-compose
> sudo systemctl start docker
> sudo systemctl enable docker
> ```
**如果系统使用 `apt` (D版本 - Debian):**
```bash
# 1. 更新包索引
sudo apt-get update
# 2. 安装必要依赖
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
# 3. 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 4. 添加 Docker 仓库
echo "deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 5. 安装 Docker CE
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 6. 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 7. 验证安装
docker --version
docker compose version
```
#### 3.2.2 通过静态二进制安装(备用方案)
如果包管理器安装失败,可使用静态二进制:
```bash
# 创建临时目录
mkdir -p /tmp/docker-install && cd /tmp/docker-install
# 下载 Docker CE ARM64 静态二进制包
# 推荐版本: 27.5.1 (稳定),也可选择更新的版本
wget https://download.docker.com/linux/static/stable/aarch64/docker-27.5.1.tgz
# 解压并安装
tar -xzf docker-27.5.1.tgz
sudo cp -p docker/* /usr/bin/
# 下载 Docker Compose ARM64
sudo wget -O /usr/bin/docker-compose https://github.com/docker/compose/releases/download/v2.29.1/docker-compose-linux-aarch64
sudo chmod +x /usr/bin/docker-compose
# 创建 systemd 服务
sudo tee /etc/systemd/system/docker.service > /dev/null << 'EOF'
[Unit]
Description=Docker Application Container Engine
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 启动 Docker
sudo systemctl daemon-reload
sudo systemctl start docker
sudo systemctl enable docker
# 验证
docker --version
docker-compose --version
```
### 3.3 配置 Docker 国内镜像加速(推荐)
由于 Docker Hub 在国内访问不稳定,建议配置镜像加速器:
```bash
# 创建/编辑 Docker 守护进程配置文件
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
EOF
# 重启 Docker 使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker
# 验证加速器是否生效
docker info | grep -A 5 "Registry Mirrors"
```
> **注意**: 以上加速器地址可能会变更,如失效请搜索最新可用地址。
> 在部分涉密/军用网络环境中,可能无法访问公共镜像仓库,此时需要联系网络管理员获取内部镜像仓库地址。
### 3.4 安装常用工具
```bash
# yum 系统
sudo yum install -y wget curl vim net-tools telnet htop
# apt 系统
sudo apt-get install -y wget curl vim net-tools telnet htop
```
### 3.5 创建部署目录
```bash
# 创建部署根目录
sudo mkdir -p /opt/owl-zlmediakit
cd /opt/owl-zlmediakit
# 创建数据持久化目录
sudo mkdir -p /data/owl-zlm/record /data/owl-zlm/log /data/owl-zlm/gowvp-configs /data/owl-zlm/snap
sudo chmod -R 755 /data/owl-zlm/
# 查看目录结构
ls -la
```
---
## 四、服务部署
### 4.1 拉取 Docker 镜像
```bash
# 拉取 ZLMediaKit 官方 ARM64 镜像
docker pull zlmediakit/zlmediakit:master
# 拉取 GoWVP (Owl) 官方 ARM64 镜像
docker pull gospace/gowvp:latest
# 验证镜像架构(必须显示 "arm64"
docker inspect zlmediakit/zlmediakit:master | grep Architecture
# 预期输出: "Architecture": "arm64"
docker inspect gospace/gowvp:latest | grep Architecture
# 预期输出: "Architecture": "arm64"
# 查看已下载镜像
docker images | grep -E "zlmediakit|gowvp"
```
**国内网络加速(如拉取缓慢或失败):**
```bash
# 方案A: 使用华为云镜像加速 ZLMediaKit
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/zlmediakit/zlmediakit:master-linuxarm64
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/zlmediakit/zlmediakit:master-linuxarm64 zlmediakit/zlmediakit:master
# 方案B: 使用阿里云镜像加速 GoWVP
docker pull registry.cn-shanghai.aliyuncs.com/ixugo/homenvr:latest
docker tag registry.cn-shanghai.aliyuncs.com/ixugo/homenvr:latest gospace/gowvp:latest
```
> **重要提醒**: 即使服务器是 ARM64 架构,也建议通过 `docker inspect` 确认镜像架构为 `arm64`,避免意外拉取到多架构镜像中的错误版本。
### 4.2 准备配置文件
#### 4.2.1 IP 地址配置说明(重要)
在编辑配置文件前请确认以下IP地址使用规则
| 配置项 | 当前值 | 用途 | 修改建议 |
|--------|--------|------|----------|
| `GOWVP_ZLM_HOST` | `192.168.3.108` | GoWVP向外部返回的流媒体地址 | **必须改为服务器实际IP**,否则外部设备/浏览器无法访问 |
| `externIP` | `192.168.3.108` | WebRTC外部访问IP | **必须改为服务器实际IP**否则WebRTC无法穿透 |
| Hook回调地址 | `127.0.0.1` | ZLMediaKit回调GoWVP的内部接口 | **保持127.0.0.1**两者在同一服务器的host网络模式下本机通信无需暴露 |
> **为什么GOWVP_ZLM_HOST不能用127.0.0.1**
> - GoWVP在生成播放地址如FLV、HLS、WebRTC链接会将此地址返回给浏览器或设备
> - 如果返回`http://127.0.0.1:80/xxx`,浏览器会在**用户本机**寻找服务器,显然找不到
> - 必须返回`http://192.168.3.108:80/xxx`,外部设备才能正确访问
> **为什么Hook回调可以保持127.0.0.1**
> - Hook是ZLMediaKit**主动调用**GoWVP的内部通知机制
> - 两者都使用`network_mode: host`,共享服务器的网络栈
> - ZLMediaKit在服务器上访问`127.0.0.1:15123`就是访问同一台服务器上的GoWVP完全正确
**如果您的服务器IP不是192.168.3.108,请务必修改以下两个配置:**
```bash
# 获取服务器实际IP用于替换配置中的IP
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "服务器IP: ${SERVER_IP}"
```
#### 4.2.2 创建 docker-compose.yml
创建文件 `/opt/owl-zlmediakit/docker-compose.yml`
```bash
cd /opt/owl-zlmediakit
sudo tee docker-compose.yml > /dev/null << 'EOF'
version: '3.8'
services:
# ZLMediaKit 流媒体服务
zlmediakit:
image: zlmediakit/zlmediakit:master
container_name: zlmediakit
restart: always
privileged: true
network_mode: host
volumes:
- ./data/zlm-config.ini:/opt/media/conf/config.ini:ro
- ./data/record:/opt/media/bin/www/record
- ./data/log:/opt/media/bin/log
environment:
- TZ=Asia/Shanghai
logging:
driver: json-file
options:
max-size: "100m"
max-file: "3"
# GoWVP (Owl) 管理平台
gowvp:
image: gospace/gowvp:latest
container_name: gowvp
restart: always
network_mode: host
depends_on:
- zlmediakit
volumes:
- ./data/gowvp-configs:/opt/media/bin/configs
- ./data/record:/opt/media/bin/www/record
environment:
- TZ=Asia/Shanghai
# 必须使用服务器实际IP不能填127.0.0.1
# 原因GoWVP向浏览器/设备返回的流媒体播放地址会包含此IP
- GOWVP_ZLM_HOST=192.168.3.108
- GOWVP_ZLM_PORT=80
- GOWVP_ZLM_SECRET=035c73f7-bb6b-4889-a715-d9eb2d1925cc
logging:
driver: json-file
options:
max-size: "100m"
max-file: "3"
EOF
```
> **注意**: 如果服务器IP不是 `192.168.3.108`,请将 `GOWVP_ZLM_HOST` 修改为实际IP。
#### 4.2.3 创建 ZLMediaKit 配置文件
创建文件 `/opt/owl-zlmediakit/data/zlm-config.ini`
```bash
cd /opt/owl-zlmediakit
sudo tee data/zlm-config.ini > /dev/null << 'EOF'
; ZLMediaKit 配置文件
; 针对 ARM64 + 联网环境优化
[api]
apiDebug=1
secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
snapRoot=./www/snap/
defaultSnap=./www/logo.png
downloadRoot=./www
[ffmpeg]
bin=/usr/bin/ffmpeg
cmd=%s -re -i %s -c copy -f flv %s
snap=%s -i %s -y -f mjpeg -t 0.001 %s
[general]
enableVhost=0
flowThreshold=1024
maxStreamWaitMS=15000
streamNoneReaderDelayMS=20000
resetWhenRePlay=1
mergeWriteMS=0
mediaServerId=owl-zlm-server-01
wait_add_track_ms=3000
wait_track_ready_ms=10000
[hls]
fileBufSize=65536
segDur=2
segNum=3
segRetain=5
broadcastRecordTs=0
fastRegister=0
[hook]
enable=1
on_publish=https://127.0.0.1:15123/api/v1/hook/on_publish
on_play=https://127.0.0.1:15123/api/v1/hook/on_play
on_stream_not_found=https://127.0.0.1:15123/api/v1/hook/on_stream_not_found
on_server_started=https://127.0.0.1:15123/api/v1/hook/on_server_started
on_server_keepalive=https://127.0.0.1:15123/api/v1/hook/on_server_keepalive
on_send_rtp_stopped=https://127.0.0.1:15123/api/v1/hook/on_send_rtp_stopped
on_rtp_server_timeout=https://127.0.0.1:15123/api/v1/hook/on_rtp_server_timeout
admin_params=secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
timeoutSec=20
[http]
charSet=utf-8
keepAliveSecond=30
maxReqSize=40960
notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit-4.0</center></body></html>
port=80
rootPath=./www
sendBufSize=65536
sslport=443
virtualPath=
[multicast]
addrMax=239.255.255.255
addrMin=239.0.0.0
udpTTL=64
[record]
appName=record
fastStart=0
fileBufSize=65536
fileSecond=3600
sampleMS=500
[rtmp]
directProxy=1
enhanced=0
handshakeSecond=15
keepAliveSecond=15
port=1935
[rtp]
audioMtuSize=600
h264_stap_a=1
opus_rtp_ext=0
rtpMaxSize=10
videoMtuSize=1400
[rtp_proxy]
dumpDir=
port=10000
port_range=30000-30500
[rtsp]
authBasic=0
directProxy=1
handshakeSecond=15
keepAliveSecond=15
port=554
sslport=332
[srt]
latencyMul=4
pktBufSize=8192
port=9000
timeoutSec=5
[rtc]
# WebRTC外部IP必须设置为服务器实际IP否则外部浏览器无法播放
externIP=192.168.3.108
port=8000
tcpPort=8000
rembBitRate=0
[shell]
maxReqSize=1024
port=9000
[cluster]
origin_url=
retry_count=3
timeout_sec=15
EOF
```
### 4.3 启动服务
```bash
cd /opt/owl-zlmediakit
# 首次启动建议前台运行,观察日志确认无错误
docker-compose up
# 如果日志显示服务正常启动,按 Ctrl+C 停止前台运行
# 然后后台启动
docker-compose up -d
# 查看运行状态
docker-compose ps
# 查看 ZLMediaKit 日志
docker logs -f zlmediakit
# 查看 GoWVP 日志
docker logs -f gowvp
```
**启动成功标志:**
- `docker-compose ps` 显示两个容器状态为 `Up`
- ZLMediaKit 日志显示 `MediaServer` 已启动,监听端口无报错
- GoWVP 日志显示 Web 服务已启动,端口 15123 监听正常
### 4.4 部署 ZLMediaKit单独运行方式
> 如果使用 Docker Compose 融合部署,此节可跳过。本节仅用于单独部署 ZLMediaKit 的场景。
```bash
# 单独运行 ZLMediaKit 容器
docker run -id \
--name zlmediakit \
--restart always \
--privileged \
--network host \
-v /opt/owl-zlmediakit/data/zlm-config.ini:/opt/media/conf/config.ini:ro \
-v /opt/owl-zlmediakit/data/record:/opt/media/bin/www/record \
-v /opt/owl-zlmediakit/data/log:/opt/media/bin/log \
-e TZ=Asia/Shanghai \
zlmediakit/zlmediakit:master
# 查看日志
docker logs -f zlmediakit
```
### 4.5 部署 GoWVPOwl单独运行方式
> 如果使用 Docker Compose 融合部署,此节可跳过。
```bash
# 单独运行 GoWVP 容器
docker run -id \
--name gowvp \
--restart always \
--network host \
-v /opt/owl-zlmediakit/data/gowvp-configs:/opt/media/bin/configs \
-v /opt/owl-zlmediakit/data/record:/opt/media/bin/www/record \
-e TZ=Asia/Shanghai \
-e GOWVP_ZLM_HOST=192.168.3.108 \
-e GOWVP_ZLM_PORT=80 \
-e GOWVP_ZLM_SECRET=035c73f7-bb6b-4889-a715-d9eb2d1925cc \
gospace/gowvp:latest
# 查看日志
docker logs -f gowvp
```
---
## 五、配置联动
GoWVP 与 ZLMediaKit 的联动已通过以下方式配置完成:
1. **ZLMediaKit Hook 回调**: ZLMediaKit 在流注册、播放、推流等事件发生时,通过 HTTP POST 请求通知 GoWVP
2. **GoWVP RESTful API**: GoWVP 通过 ZLMediaKit 的 HTTP API 控制流的拉取、转码、录制等操作
3. **共享存储**: 两个容器通过 bind mount 共享 `./data/record` 目录,用于录像文件存储
### 5.1 ZLMediaKit Hook 配置
上述 `zlm-config.ini` 中已包含 Hook 配置:
```ini
[hook]
enable=1
on_publish=https://127.0.0.1:15123/api/v1/hook/on_publish
on_play=https://127.0.0.1:15123/api/v1/hook/on_play
on_stream_not_found=https://127.0.0.1:15123/api/v1/hook/on_stream_not_found
on_server_started=https://127.0.0.1:15123/api/v1/hook/on_server_started
on_server_keepalive=https://127.0.0.1:15123/api/v1/hook/on_server_keepalive
on_send_rtp_stopped=https://127.0.0.1:15123/api/v1/hook/on_send_rtp_stopped
on_rtp_server_timeout=https://127.0.0.1:15123/api/v1/hook/on_rtp_server_timeout
admin_params=secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
timeoutSec=20
```
### 5.2 GoWVP 环境变量配置
上述 `docker-compose.yml` 中已包含环境变量配置:
```yaml
environment:
- GOWVP_ZLM_HOST=192.168.3.108 # ZLMediaKit 地址必须使用服务器实际IP
- GOWVP_ZLM_PORT=80 # ZLMediaKit HTTP端口
- GOWVP_ZLM_SECRET=035c73f7-bb6b-4889-a715-d9eb2d1925cc # API密钥
```
> **关于 GOWVP_ZLM_HOST 必须使用实际IP的说明**
> - 此IP用于GoWVP生成对外播放地址如FLV、HLS、WebRTC链接
> - 如果填`127.0.0.1`,浏览器会尝试连接用户本地电脑,导致播放失败
> - 如果服务器有多个网卡/IP建议填写摄像头/用户浏览器可访问的那个IP
> **如需修改配置**:编辑 `data/zlm-config.ini` 或 `docker-compose.yml` 后,执行 `docker-compose restart` 使配置生效。
### 5.3 重启服务使配置生效
```bash
cd /opt/owl-zlmediakit
docker-compose restart
# 等待30秒后检查状态
sleep 30
docker-compose ps
```
### 5.4 联动验证
```bash
# 查看 ZLMediaKit 日志,确认 Hook 回调成功
docker logs zlmediakit | grep -i "hook"
# 查看 GoWVP 日志,确认收到 ZLMediaKit 事件
docker logs gowvp | grep -i "zlm\|hook"
```
---
## 六、验证步骤
### 6.1 验证脚本
创建并运行验证脚本:
```bash
cd /opt/owl-zlmediakit
# 创建验证脚本
sudo tee scripts/verify.sh > /dev/null << 'EOF'
#!/bin/bash
# GoWVP + ZLMediaKit 部署验证脚本
set -e
SERVER_IP=$(hostname -I | awk '{print $1}')
ZLM_SECRET="035c73f7-bb6b-4889-a715-d9eb2d1925cc"
echo "=========================================="
echo " GoWVP + ZLMediaKit 部署验证"
echo " 服务器IP: ${SERVER_IP}"
echo "=========================================="
# 1. 检查 Docker 状态
echo -e "\n[1/6] 检查 Docker 状态..."
if systemctl is-active --quiet docker; then
echo " ✓ Docker 运行正常"
else
echo " ✗ Docker 未运行"
exit 1
fi
# 2. 检查容器状态
echo -e "\n[2/6] 检查容器状态..."
if docker ps | grep -q zlmediakit; then
echo " ✓ ZLMediaKit 容器运行中"
else
echo " ✗ ZLMediaKit 容器未运行"
exit 1
fi
if docker ps | grep -q gowvp; then
echo " ✓ GoWVP 容器运行中"
else
echo " ✗ GoWVP 容器未运行"
exit 1
fi
# 3. 测试 ZLMediaKit API
echo -e "\n[3/6] 测试 ZLMediaKit API..."
if curl -s "http://${SERVER_IP}/index/api/getApiList" > /dev/null; then
echo " ✓ ZLMediaKit API 响应正常"
else
echo " ✗ ZLMediaKit API 无响应"
fi
# 4. 测试获取流列表
echo -e "\n[4/6] 测试获取媒体流列表..."
if curl -s "http://${SERVER_IP}/index/api/getMediaList?secret=${ZLM_SECRET}" > /dev/null; then
echo " ✓ 媒体流列表接口正常"
else
echo " ✗ 媒体流列表接口异常"
fi
# 5. 测试 GoWVP Web 服务
echo -e "\n[5/6] 测试 GoWVP Web 服务..."
if curl -s -I "http://${SERVER_IP}:15123" | grep -q "200\|302"; then
echo " ✓ GoWVP Web 服务响应正常"
else
echo " ✗ GoWVP Web 服务无响应"
fi
# 6. 检查端口监听
echo -e "\n[6/6] 检查关键端口..."
for port in 80 15123 15060 1935 554; do
if netstat -tlnp 2>/dev/null | grep -q ":${port} " || ss -tlnp 2>/dev/null | grep -q ":${port} "; then
echo " ✓ 端口 ${port} 监听正常"
else
echo " ✗ 端口 ${port} 未监听"
fi
done
echo -e "\n=========================================="
echo " 验证完成"
echo " ZLMediaKit: http://${SERVER_IP}"
echo " GoWVP: http://${SERVER_IP}:15123"
echo "=========================================="
EOF
sudo chmod +x scripts/verify.sh
# 运行验证脚本
sudo ./scripts/verify.sh
```
### 6.2 手动验证步骤
#### 6.2.1 验证 ZLMediaKit
```bash
# 获取服务器IP
SERVER_IP=$(hostname -I | awk '{print $1}')
# 测试 ZLMediaKit API
curl "http://${SERVER_IP}/index/api/getApiList"
# 测试获取流列表
curl "http://${SERVER_IP}/index/api/getMediaList?secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc"
# 在浏览器中访问
# http://<服务器IP>
```
#### 6.2.2 验证 GoWVP
```bash
# 测试 GoWVP Web 界面
curl -I "http://${SERVER_IP}:15123"
# 在浏览器中访问管理界面
# http://<服务器IP>:15123
# 默认账号密码请查看 GoWVP 官方文档
```
#### 6.2.3 验证 GB28181 端口
```bash
# 检查 SIP 端口UDP/TCP 15060
netstat -ulnp | grep 15060
netstat -tlnp | grep 15060
# 检查流媒体端口范围20000-20100
netstat -ulnp | grep -E "20000|20001|20002"
```
### 6.3 推流测试
如果您有支持 RTMP/RTSP 的摄像头或推流工具,可以进行测试:
```bash
# RTMP 推流测试地址使用FFmpeg
ffmpeg -re -i test.mp4 -c copy -f flv rtmp://<服务器IP>/live/test
# 播放测试
# RTMP: rtmp://<服务器IP>/live/test
# HLS: http://<服务器IP>/live/test/hls.m3u8
# FLV: http://<服务器IP>/live/test.live.flv
```
---
## 七、常见问题排查
### 7.1 Docker 无法启动
**现象**: `systemctl start docker` 失败
**排查步骤**:
```bash
# 查看详细错误
journalctl -u docker -n 50
# 检查内核是否支持容器
cat /proc/1/cgroup
# 手动运行dockerd查看错误
/usr/bin/dockerd
```
**解决方案**:
- 确保内核版本 >= 3.10统信UOS kernel-4.19 满足要求)
- 检查 `/var/run/docker.sock` 权限
- 确保 `iptables` 可用:`which iptables`
- 检查 SELinux 状态:`getenforce`,如为 Enforcing 可尝试临时关闭:`setenforce 0`
### 7.2 容器启动后立即退出
**现象**: `docker ps` 看不到运行的容器
**排查步骤**:
```bash
# 查看容器退出日志
docker logs zlmediakit
docker logs gowvp
# 查看容器状态
docker ps -a
docker inspect zlmediakit
```
**常见原因**:
- 端口被占用:`netstat -tlnp | grep :80`
- 配置文件路径错误:检查 volume 映射
- 权限不足:确保使用 `--privileged` 或正确配置 capabilities
### 7.3 ARM64 镜像无法运行
**现象**: 报错 `exec format error`
**原因**: 镜像架构与服务器不匹配(拉取了 x86_64 镜像)
**解决方案**:
```bash
# 检查镜像架构
docker inspect zlmediakit/zlmediakit:master | grep Architecture
# 必须显示 "arm64"
# 如果错误,删除错误镜像并重新拉取
docker rmi zlmediakit/zlmediakit:master
docker pull --platform linux/arm64 zlmediakit/zlmediakit:master
```
### 7.4 GoWVP 无法连接 ZLMediaKit
**现象**: GoWVP 日志显示连接 ZLMediaKit 失败
**排查步骤**:
```bash
# 检查 ZLMediaKit 是否正常运行
curl http://127.0.0.1/index/api/getApiList
# 检查 secret 是否一致
grep secret data/zlm-config.ini
grep GOWVP_ZLM_SECRET docker-compose.yml
# 检查 Hook 配置是否正确
grep "on_publish\|on_play" data/zlm-config.ini
```
### 7.5 GB28181 设备无法接入
**现象**: 摄像头无法注册到 GoWVP
**排查步骤**:
```bash
# 检查 SIP 端口是否监听
netstat -ulnp | grep 15060
# 检查防火墙
firewall-cmd --list-ports # 如果使用 firewalld
iptables -L -n | grep 15060
# 查看 GoWVP 日志
docker logs -f gowvp | grep -i "sip\|register"
```
**必要端口清单**:
| 端口 | 协议 | 用途 |
|------|------|------|
| 80 | TCP | HTTP/Web |
| 443 | TCP | HTTPS |
| 15123 | TCP | GoWVP Web管理 |
| 15060 | UDP/TCP | GB28181 SIP |
| 1935 | TCP | RTMP |
| 554 | TCP | RTSP |
| 8000 | UDP/TCP | WebRTC |
| 9000 | UDP | SRT |
| 10000 | UDP | RTP代理 |
| 20000-20100 | UDP | GB28181 媒体流 |
| 30000-30500 | UDP | RTP端口范围 |
### 7.6 性能问题
**现象**: 视频卡顿、延迟高
**优化建议**:
```bash
# 查看CPU和内存使用情况
top
htop
# 查看磁盘IO
iostat -x 1
# ZLMediaKit 配置优化关闭转码以节省CPU
# 在 config.ini 中:
[ffmpeg]
cmd=%s -re -i %s -c copy -f flv %s # 使用 copy 而不是重新编码
# 限制日志大小避免磁盘占满
docker system prune -f
```
### 7.7 ARM64 架构稳定性问题(重要)
> ⚠️ **本章节针对飞腾S5000C等ARM64服务器的重要风险提示**
#### 7.7.1 已知问题概述
**GitHub Issue**: [#3466 - In ARM architecture, ZLM live streaming is unstable](https://github.com/ZLMediaKit/ZLMediaKit/issues/3466)
**问题描述**: ZLMediaKit 在 ARM64 (aarch64) 架构下运行 GB28181 RTP 推流时,存在**偶发性崩溃**问题x86_64 架构下相同配置稳定运行。
#### 7.7.2 具体症状
| 症状 | 描述 |
|------|------|
| **进程崩溃** | MediaServer 进程意外退出Docker 容器重启 |
| **Signal 11** | 收到 SIGSEGV (段错误),内存访问违规 |
| **流中断** | GB28181 RTP 推流频繁断开,需重新注册 |
| **错误日志** | `Unsupported codec: PCMU``Unsupported codec: invalid` |
**典型错误日志**:
```
2024-04-11 07:13:07.002 W [MediaServer] [319-event poller 3] Factory.cpp:118 getTrackByCodecId | Unsupported codec: PCMU
2024-04-11 07:13:24.885 W [MediaServer] [319-event poller 3] Factory.cpp:200 getFrameFromPtr | Unsupported codec: invalid
```
**崩溃堆栈特征**(简化):
```
Signal 11 received
Stacktrace:
FrameCacheAble::FrameCacheAble(...)
Factory::getFrameFromBuffer(...)
FrameMerger::inputFrame(...)
FrameMerger::flush(...)
DecoderImp::flush(...)
RtpProcessHelper::~RtpProcessHelper()
```
> **崩溃位置分析**: 堆栈显示崩溃发生在**帧缓存分配**和**解码器刷新**阶段,疑似与内存对齐或并发访问有关。
#### 7.7.3 可重现性
| 条件 | 可重现性 |
|------|----------|
| Docker 部署 + ARM64 | **高** - 社区多个用户报告 |
| 物理机/虚拟机 ARM64 | **中** - 部分用户报告 |
| x86_64 (相同配置) | **无法重现** - 稳定运行 |
| GB28181 RTP 推流 | **高** - 主要触发场景 |
| RTMP/RTSP 推流 | **低** - 偶发 |
| 空闲状态 | **无** - 仅在活跃推流时 |
#### 7.7.4 可能原因分析
1. **内存对齐问题**: ARM64 架构对内存对齐要求更严格,某些数据结构在 x86 上能正常工作但在 ARM 上触发 SIGSEGV
2. **并发访问竞争**: FrameMerger 在多线程环境下可能存在 race condition
3. **Codec 解析异常**: 某些摄像头发送的 PS 流格式不规范ARM 版解码器处理异常时未正确保护
4. **Docker 环境差异**: Docker 在 ARM64 上的 QEMU 模拟或 seccomp 策略可能影响行为
#### 7.7.5 规避方案与解决方案
**方案一:使用官方最新镜像(推荐尝试)**
```bash
# 确保使用最新 master 分支镜像,可能已修复
# 官方维护者持续在修复 ARM64 相关问题
docker pull zlmediakit/zlmediakit:master
docker inspect zlmediakit/zlmediakit:master | grep -E "Created|Revision"
```
**方案二:启用容器自动重启**
```yaml
# 在 docker-compose.yml 中已配置 restart: always
# 崩溃后容器会自动重启,业务中断时间 < 10 秒
services:
zlmediakit:
restart: always
# 可选:增加重启策略
deploy:
restart_policy:
condition: any
delay: 5s
max_attempts: 10
```
**方案三:限制单路流的并发处理**
```ini
# 在 config.ini 中降低并发处理线程数
[general]
# 减少事件轮询线程数(默认等于 CPU 核心数)
# 可尝试设置为物理核心数的一半
# 注意: 此配置需查阅最新文档确认参数名
[ffmpeg]
# 关闭转码,减少编解码压力
cmd=%s -re -i %s -c copy -f flv %s
```
**方案四:使用 host 网络模式(已默认配置)**
```yaml
# docker-compose.yml 中已配置 network_mode: host
# 避免 Docker 桥接网络在 ARM64 上的性能开销和潜在 bug
services:
zlmediakit:
network_mode: host
```
**方案五:监控并自动恢复**
```bash
# 创建监控脚本 /opt/owl-zlmediakit/scripts/monitor.sh
sudo tee /opt/owl-zlmediakit/scripts/monitor.sh > /dev/null << 'EOF'
#!/bin/bash
while true; do
if ! docker ps | grep -q zlmediakit; then
echo "$(date): ZLMediaKit 容器异常,正在重启..." >> /var/log/zlm-monitor.log
cd /opt/owl-zlmediakit && docker-compose restart zlmediakit
fi
sleep 10
done
EOF
sudo chmod +x /opt/owl-zlmediakit/scripts/monitor.sh
# 使用 systemd 或 screen 后台运行监控脚本
# 或使用 systemd 定时任务
```
**方案六:源码编译(终极方案)**
```bash
# 如果 Docker 镜像问题持续,可在 ARM64 服务器上本地编译
# 本地编译会针对具体 CPU 指令集优化,可能规避问题
cd /usr/src/ZLMediaKit
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-faligned-new"
make -j$(nproc)
```
#### 7.7.6 生产环境建议
| 场景 | 建议 |
|------|------|
| **测试/开发环境** | 可直接使用 Docker 部署,观察稳定性 |
| **生产环境(关键业务)** | 强烈建议**先进行 7x24 小时压力测试**,确认无崩溃后再上线 |
| **已出现崩溃** | 启用自动重启 + 监控脚本,同时向 ZLMediaKit GitHub 提交 issue |
| **追求极致稳定** | 考虑在 ARM64 上源码编译,或改用 x86_64 服务器部署 ZLMediaKit |
#### 7.7.7 社区状态跟踪
- **Issue 状态**: Closed (因未按模板提交被关闭,但问题真实存在)
- **社区反馈**: 多名用户确认在 RK3568、树莓派、鲲鹏等 ARM64 设备上遇到类似问题
- **官方态度**: 维护者表示会持续关注 ARM64 兼容性,建议用户使用最新版本
- **建议操作**: 如遇到崩溃,请收集完整堆栈和复现步骤,向 [ZLMediaKit Issues](https://github.com/ZLMediaKit/ZLMediaKit/issues) 提交反馈
#### 7.7.8 相关 Issue 深度分析
> 以下三个 Issue 与 ARM64 稳定性密切相关,建议主人一并了解。
---
**Issue #3202 - RK3588 SIGABRT 崩溃**
| 项目 | 详情 |
|------|------|
| **硬件** | RK3588 (Ubuntu 20.04.6) |
| **信号** | `SIGABRT` (signal 6) |
| **版本** | git hash `e593ef5/2023-12-17` |
| **触发条件** | 视频流不稳定时持续崩溃 |
**崩溃堆栈特征**:
```
[0]: MediaServer(+0x992ba8)
[4]: libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x188)
[8]: MediaServer(Assert_Throw+0x184)
```
**根本原因**(官方维护者 @xia-chu 回复):
> "这个不算bug是你的编译器默认关闭了异常功能一抛异常就默认 abort。编译器开启异常功能需要加上编译选项 `-fexceptions`。"
**技术解释**:
- ARM 交叉编译工具链(如 `aarch64-linux-gnu-gcc`**默认关闭 C++ 异常处理**
- 当 ZLMediaKit 内部抛出 C++ 异常(如 `Assert_Throw` 失败libstdc++ 的 terminate handler 被调用
- 由于异常被禁用,该 handler 直接调用 `abort()` 导致进程终止
**解决方案**:
```cmake
# 在 CMakeLists.txt 中添加
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
endif()
```
**或在 cmake 命令中指定**:
```bash
cmake .. -DCMAKE_CXX_FLAGS="-fexceptions"
```
> ⚠️ **重要**: `-fexceptions` 是 GCC 标准选项,不是临时 hack。ZLMediaKit 大量使用 C++ 异常,在 ARM 上编译**必须**显式启用。
---
**Issue #2728 - ARM 内存"泄漏"问题**
| 项目 | 详情 |
|------|------|
| **平台** | ARM (aarch64), Ubuntu 18, 内存 4G |
| **现象** | 调用 `getStatisticJson` 接口时系统卡死;开启 `ENABLE_MEM_DEBUG` 后机器完全卡住 |
| **本质** | **内存碎片**,非真正泄漏 |
**详细分析**:
1. **内存碎片问题**:
- ZLMediaKit 调用 `free()` 将内存返还给 glibc 的 ptmalloc
- 但 ptmalloc **不会立即将内存返还给操作系统**(出于性能考虑)
- 导致 `RSS` 内存居高不下,看起来像泄漏
2. **`ENABLE_MEM_DEBUG` 的陷阱**:
```cmake
# ZLMediaKit 使用链接器 wrap 机制拦截内存分配
if(ENABLE_MEM_DEBUG)
update_cached_list(MK_LINK_LIBRARIES
"-Wl,-wrap,free;-Wl,-wrap,malloc;-Wl,-wrap,realloc;-Wl,-wrap,calloc")
endif()
```
- 在 ARM 平台上,`-Wl,-wrap` 拦截每次 malloc/free**性能开销极大**
- 高并发场景下会导致系统完全卡死
- **生产环境切勿开启 ENABLE_MEM_DEBUG**
3. **解决方案 - 使用 tcmalloc**:
```cmake
# 编译时启用 tcmalloc
cmake .. -DENABLE_TCMALLOC=ON
```
- tcmalloc 采用 **per-CPU 缓存** 机制,更好地管理内存碎片
- 在 RTP 断流重连场景下,内存可以稳定复用
**tcmalloc 静态库编译注意事项**:
```bash
# 编译 gperftools 时需要加 -fPIC
./configure CFLAGS="-fPIC" CXXFLAGS="-fPIC"
make
```
**运行时加载**:
```bash
LD_PRELOAD=libtcmalloc.so.4 ./MediaServer
```
4. **替代方案 - jemalloc**:
```cmake
# ZLMediaKit 默认优先链接 jemalloc
find_package(JEMALLOC QUIET)
if(JEMALLOC_FOUND)
update_cached_list(MK_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
add_definitions(-DUSE_JEMALLOC)
endif()
```
---
**Issue #2043 - RK3568 拉流断开问题**
| 项目 | 详情 |
|------|------|
| **硬件** | RK3568 |
| **信号** | `SIGSEGV` (signal 11) |
| **版本** | git hash `b3fd74c` |
| **触发条件** | 拉流后很快断开 |
**错误日志**:
```
## signal: 11
[0]: ./MediaServer() [0x995710] sig_crash(int)
[1]: /lib/arm-linux-gnueabihf/libc.so.6(+0x25260)
```
**可能原因**:
1. **RK 系列网卡驱动 bug**(与 RK3399 类似)
> "rk3339 的网卡驱动是有 bug 的!如果是从上面往别处 tcp 发送大的数据包,在 tcp 的 ip 数据报分片以后会出现校验和计算错误"
2. 交叉编译环境配置问题
3. 缺少必要的系统库
**状态**: Issue 已关闭,标题显示"问题已经解决,谢谢",但未详细说明解决方案。
**建议**: 如遇到类似问题,优先尝试:
1. 更新到最新代码
2. 检查网卡驱动版本
3. 在 GDB 下调试获取完整堆栈
---
#### 7.7.9 ARM64 编译优化建议
**必加编译选项**:
| 选项 | 用途 | 必要性 |
|------|------|--------|
| `-fexceptions` | 启用 C++ 异常处理 | **必须** |
| `-pthread` | 线程支持 | **必须** |
| `-fPIC` | 位置无关代码(动态库需要) | **推荐** |
| `-faligned-new` | 对齐内存分配 | **推荐** |
**完整编译命令示例**:
```bash
cd /usr/src/ZLMediaKit
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC -faligned-new" \
-DENABLE_WEBRTC=ON \
-DENABLE_FFMPEG=ON \
-DENABLE_TCMALLOC=ON
make -j$(nproc)
```
**交叉编译示例飞腾S5000C**:
```bash
# 创建工具链文件 /tmp/toolchain.cmake
cat > /tmp/toolchain.cmake << 'EOF'
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
EOF
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC" \
-DENABLE_TCMALLOC=ON
make -j$(nproc)
```
#### 7.7.10 官方态度与未来展望
**官方维护者 (@xia-chu) 的态度**:
- 承认 ARM64 支持,但认为问题多源于**用户环境/编译方式**
- 对于崩溃问题,往往归结为:端口占用、编译器选项问题 (`-fexceptions`)、Android 限制等
- **没有看到系统性的 ARM64 修复计划公告**
**已有的 ARM64 修复**:
- **PR #2479** (2023-05): 修复 ARM 内存对齐问题
- Commit `7cb772c`: "On arm need align, without this the application crashed after SIGBUS"
- **PR #2800** (2023-08): 修复 `close_stream` 与 `getMediaList` 并发崩溃
- **PR #4582** (2025-12): 修复 RtspSession/RtspPusher 空指针崩溃
**未来计划**:
- 2024 年 12 月,@xia-chu 表示:"后面我会考虑添加下 arm64 的 ci 自动编译并发布二进制包"
- 但截至 2026 年 4 月,**尚未实现** ARM64 CI 自动编译和二进制发布
**Issue #483 预编译二进制包**:
- 这是官方发布预编译二进制的位置
- 目前仅有 macOS ARM64 包,**Linux ARM64 包链接已失效**
- 下载地址: https://github.com/ZLMediaKit/ZLMediaKit/issues/483
---
## 八、附录
### 附录A: 端口清单
| 端口 | 协议 | 服务 | 说明 |
|------|------|------|------|
| 80 | TCP | ZLMediaKit | HTTP 服务 |
| 443 | TCP | ZLMediaKit | HTTPS 服务 |
| 15123 | TCP | GoWVP | Web 管理界面 |
| 15060 | UDP/TCP | GoWVP | GB28181 SIP 信令 |
| 1935 | TCP | ZLMediaKit | RTMP 推流/播放 |
| 554 | TCP | ZLMediaKit | RTSP 服务 |
| 8000 | UDP/TCP | ZLMediaKit | WebRTC |
| 9000 | UDP | ZLMediaKit | SRT 协议 |
| 10000 | UDP | ZLMediaKit | RTP 代理 |
| 20000-20100 | UDP | GoWVP | GB28181 媒体流传输 |
| 30000-30500 | UDP | ZLMediaKit | RTP 端口范围 |
### 附录B: 源码编译 ZLMediaKit备用方案
如果 Docker 方案不可用或需要针对飞腾S5000C优化可以选择源码编译
```bash
# 1. 安装编译依赖
# yum 系统:
sudo yum install -y gcc gcc-c++ cmake git openssl-devel
# apt 系统:
sudo apt-get install -y build-essential cmake git libssl-dev
# 2. 下载源码(联网环境直接克隆)
cd /usr/src
sudo git clone --depth 1 https://github.com/ZLMediaKit/ZLMediaKit.git
cd ZLMediaKit
sudo git submodule update --init --recursive
# 3. 编译(针对 ARM64 添加必要参数)
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC -faligned-new" \
-DENABLE_WEBRTC=ON \
-DENABLE_FFMPEG=ON \
-DENABLE_TCMALLOC=ON
make -j$(nproc)
# 4. 运行
sudo ./release/linux/Release/MediaServer -d &
```
> **注意**: WebRTC 功能需要 libsrtp 2.5.0,编译前请确保已安装。
### 附录C: 源码编译 GoWVP备用方案
```bash
# 1. 安装 Go 环境1.20+
# 下载 ARM64 版本 Go
cd /tmp
wget https://go.dev/dl/go1.22.0.linux-arm64.tar.gz
sudo tar -C /usr/local -xzf go1.22.0.linux-arm64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# 2. 下载并编译 GoWVP
cd /usr/src
git clone https://github.com/gowvp/owl.git
cd owl
make build
# 3. 运行
./bin/owl-server &
```
> 或者使用预编译二进制(联网环境可直接下载):
> ```bash
> wget https://github.com/gowvp/owl/releases/download/v1.3.0/owl_linux_arm64.tar.gz
> tar xzf owl_linux_arm64.tar.gz -C /usr/local/
> /usr/local/owl/owl-server &
> ```
### 附录D: 防火墙配置
```bash
# 如果使用 firewalld
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=15123/tcp
sudo firewall-cmd --permanent --add-port=15060/tcp
sudo firewall-cmd --permanent --add-port=15060/udp
sudo firewall-cmd --permanent --add-port=1935/tcp
sudo firewall-cmd --permanent --add-port=554/tcp
sudo firewall-cmd --permanent --add-port=8000/tcp
sudo firewall-cmd --permanent --add-port=8000/udp
sudo firewall-cmd --permanent --add-port=9000/udp
sudo firewall-cmd --permanent --add-port=10000/udp
sudo firewall-cmd --permanent --add-port=20000-20100/udp
sudo firewall-cmd --permanent --add-port=30000-30500/udp
sudo firewall-cmd --reload
# 如果使用 iptables
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 15123 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 15060 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 15060 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 1935 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 554 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 8000 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 9000 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 10000 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 20000:20100 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 30000:30500 -j ACCEPT
```
### 附录E: 参考链接
| 资源 | 地址 |
|------|------|
| ZLMediaKit GitHub | https://github.com/ZLMediaKit/ZLMediaKit |
| ZLMediaKit 文档 | https://docs.zlmediakit.com/ |
| ZLMediaKit Docker Hub | https://hub.docker.com/r/zlmediakit/zlmediakit |
| GoWVP (Owl) GitHub | https://github.com/gowvp/owl |
| GoWVP Docker Hub | https://hub.docker.com/r/gospace/gowvp |
| Docker CE 下载 | https://download.docker.com/linux/static/stable/aarch64/ |
| Docker Compose 下载 | https://github.com/docker/compose/releases |
| libsrtp 下载 | https://github.com/cisco/libsrtp/releases |
### 附录F: ARM64 架构问题速查表
> 本附录汇总 ZLMediaKit 在 ARM64 架构上的所有已知问题、症状和解决方案,方便快速定位。
#### F.1 信号类型速查
| 信号 | 名称 | 常见原因 | 解决方案 |
|------|------|----------|----------|
| **Signal 6** | SIGABRT | C++ 异常被禁用abort() 被调用 | 编译时加 `-fexceptions` |
| **Signal 7** | SIGBUS | 内存未对齐访问 | 已于 PR #2479 修复 (2023-05),更新代码 |
| **Signal 11** | SIGSEGV | 内存访问违规/空指针 | 更新代码,检查 PS 流格式GDB 调试 |
#### F.2 Issue 汇总表
| Issue | 硬件 | 信号 | 根本原因 | 解决方案 | 状态 |
|-------|------|------|----------|----------|------|
| #3466 | 多种 ARM | SIGSEGV | PS 流解析异常 + 内存问题 | 更新代码 + 自动重启 | 已关闭 |
| #3202 | RK3588 | SIGABRT | 编译器关闭异常处理 | `-fexceptions` | 已解决 |
| #2728 | 多种 ARM | - | 内存碎片 + MEM_DEBUG 性能问题 | tcmalloc/jemalloc | 已规避 |
| #2043 | RK3568 | SIGSEGV | 可能网卡驱动 bug | 更新代码 | 已关闭 |
| #4037 | aarch64 | system_error | 端口占用/系统限制 | GDB 调试排查 | 已关闭 |
#### F.3 编译参数速查
**必须添加**:
```bash
cmake .. -DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC"
```
**推荐添加**:
```bash
cmake .. -DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC -faligned-new" \
-DENABLE_TCMALLOC=ON
```
**调试编译**:
```bash
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-fexceptions -pthread -fPIC" \
-DENABLE_ASAN=ON
```
#### F.4 运行时问题速查
| 现象 | 排查命令 | 可能原因 | 解决方案 |
|------|----------|----------|----------|
| 容器频繁重启 | `docker logs zlmediakit` | Signal 11 崩溃 | 更新镜像/源码编译 |
| 内存只增不减 | `cat /proc/$(pidof MediaServer)/status` | 内存碎片 | 使用 tcmalloc |
| 流播放卡顿 | `top`, `iostat` | CPU/IO 瓶颈 | 关闭转码,限制并发 |
| GB28181 无法注册 | `netstat -ulnp \| grep 15060` | 端口未监听 | 检查防火墙,重启容器 |
| WebRTC 无法播放 | `netstat -ulnp \| grep 8000` | UDP 端口被阻 | 检查防火墙规则 |
#### F.5 Docker vs 源码编译选择建议
| 场景 | 推荐方式 | 理由 |
|------|----------|------|
| 快速验证/测试 | Docker | 简单快捷,自动重启可缓解崩溃 |
| 生产环境(关键业务) | 源码编译 | 可针对具体 CPU 优化,稳定性更好 |
| 频繁崩溃 | 源码编译 | 可添加 `-fexceptions` 等必要参数 |
| 资源受限 | Docker | 无需编译环境,节省磁盘空间 |
#### F.6 官方 ARM64 修复时间线
| 时间 | 修复内容 |
|------|----------|
| 2023-05 | PR #2479: 修复 ARM 内存对齐 SIGBUS 问题 |
| 2023-08 | PR #2800: 修复 close_stream 与 getMediaList 并发崩溃 |
| 2024-12 | @xia-chu 表示考虑添加 ARM64 CI 自动编译 |
| 2025-12 | PR #4582: 修复 RtspSession/RtspPusher 空指针崩溃 |
| 2026-04 | **尚未实现** ARM64 CI 自动编译和二进制发布 |
#### F.7 社区已知兼容硬件
| 芯片 | 型号 | 系统 | 状态 | 备注 |
|------|------|------|------|------|
| 瑞芯微 | RK3568 | 多种 Linux | ✅ 基本稳定 | 更新代码后正常 |
| 瑞芯微 | RK3588 | Ubuntu 20.04 | ⚠️ 需注意 | 需加 `-fexceptions` |
| 飞腾 | S5000C | 统信UOS20 | ⚠️ 待验证 | 本手册目标平台 |
| 鲲鹏 | 920 | Ubuntu 20.04 | ✅ 正常 | 社区反馈良好 |
| 树莓派 | 4B | Raspberry Pi OS | ⚠️ 偶发崩溃 | 建议源码编译 |
---
> **文档结束**
> 如有问题,请参考各项目的官方文档或 GitHub Issues。
> **文档版本**: v1.0
> **最后更新**: 2026-04-29