chore: 初始化仓库基线(AGENTS.md、git 规范、敏感文件排除)

This commit is contained in:
weijuesen
2026-08-10 22:30:53 +08:00
commit 84abf4454c
358 changed files with 75993 additions and 0 deletions
+880
View File
@@ -0,0 +1,880 @@
# 部署指南(物理机)
## 一、环境信息
| 项目 | 值 |
|------|-----|
| 机器 | Acer TravelMate P249-G2-MG(物理机) |
| OS | Ubuntu 22.04.5 LTS |
| 内核 | 6.8.0-124-generic |
| 磁盘 | 387GB/dev/sda6),可用 356GB |
| 内存 | 16GB |
| 网络 | 192.168.1.4(物理网卡 enp4s0+ 100.83.103.1WireGuard VPN wt0 |
| SSH | pan@100.83.103.1 密码 pan |
> 与 WSL2 部署的关键区别:无需 portproxy、无需 WSL2 IP 修复、文件系统不会变只读、Ceph 需从头配置。
## 二、服务架构
```
浏览器
├── http://100.83.103.1:5174 → 前端 (Node.js server.cjs)
├── http://100.83.103.1:3000 → Go 后端 API
├── http://100.83.103.1:7480 → Ceph S3 RGW
├── http://100.83.103.1:18080 → WVP 管理界面
物理机 (100.83.103.1)
├── sshd :22 SSH 服务
├── Docker
│ ├── polaris-wvp :18080/:18978/:8116 GB28181 信令(18080管理界面/18978HTTP API/8116 SIP
│ ├── polaris-media :8081/:10000 ZLMediaKit 流媒体
│ ├── polaris-mysql :3306 WVP 数据库
│ ├── polaris-redis WVP 缓存(Docker 内部网络)
│ └── silk-redis :6379 Go 后端缓存(密码 pan)
├── Ceph
│ ├── Monitor (a)
│ ├── Mgr (a)
│ ├── OSD 0/1 (loop device, 各 50GB, 共 100GB)
│ └── RGW :7480 S3 兼容存储
├── PostgreSQL 16 :5432 业务数据库
├── IoTDB 2.0.8 :18081 时序数据库
├── VerneMQ :1883 MQTT broker
├── Go 后端 :3000 silk-server-go
├── Go 录制服务 :9090 recorder-go
└── 前端 :5174 server.cjs
```
## 三、全新部署步骤
### 1. 安装系统依赖
```bash
# SSH 到服务器
ssh pan@100.83.103.1
# 更新 apt
sudo apt update
# 基础工具
sudo apt install -y curl wget git
# ffmpeg(视频转码)
sudo apt install -y ffmpeg
# PostgreSQL
sudo apt install -y postgresql postgresql-contrib
# JDK 17IoTDB 依赖)
sudo apt install -y openjdk-17-jdk-headless
# Docker(阿里云镜像源)
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Docker 镜像加速
sudo mkdir -p /etc/docker
cat << 'EOF' | sudo tee /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.1panel.live", "https://hub.rat.dev"]
}
EOF
sudo systemctl restart docker
# 将 pan 加入 docker 组
sudo usermod -aG docker pan
# Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Go 1.23
cd /tmp
wget https://golang.google.cn/dl/go1.23.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
```
### 2. 拉取 Docker 镜像
```bash
sudo docker pull mysql:8
sudo docker pull redis:latest
sudo docker pull zlmediakit/zlmediakit:master
```
### 3. 启动 Docker 容器
```bash
# 创建网络
sudo docker network create media-net
# MySQLWVP 数据库)
sudo docker run -d --name polaris-mysql --network media-net --restart unless-stopped \
-e MYSQL_DATABASE=wvp -e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_USER=wvp_user -e MYSQL_PASSWORD=wvp_password -e TZ=Asia/Shanghai \
-v /home/pan/silk/wvp/volumes/mysql/data:/var/lib/mysql \
-p 3306:3306 \
mysql:8 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --default-time-zone=+8:00 --lower-case-table-names=1
# RedisWVP 缓存,Docker 内部网络)
sudo docker run -d --name polaris-redis --network media-net --restart unless-stopped \
-e TZ=Asia/Shanghai \
redis:latest redis-server --appendonly yes --requirepass root
# ZLMediaKit
mkdir -p /home/pan/silk/wvp/media /home/pan/silk/wvp/volumes/video /home/pan/silk/wvp/logs/media
cat > /home/pan/silk/wvp/media/config.ini << 'EOF'
[api]
apiDebug=1
secret=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf
[http]
port=80
charSet=utf-8
[rtsp]
port=5540
[rtmp]
port=10935
[rtp_proxy]
port=10000
[record]
appName=record
sampleMS=100
[hls]
segDur=2
segNum=3
[hook]
enable=0
EOF
sudo docker run -d --name polaris-media --network media-net --restart always \
-e TZ=Asia/Shanghai \
-p 8081:80 -p 5540:5540 -p 10935:10935 -p 10000:10000 -p 10000:10000/udp \
-v /home/pan/silk/wvp/volumes/video:/opt/media/bin/www/record/ \
-v /home/pan/silk/wvp/logs/media:/opt/media/log/ \
-v /home/pan/silk/wvp/media/config.ini:/conf/config.ini \
zlmediakit/zlmediakit:master MediaServer -c /conf/config.ini -l 0
# RedisGo 后端缓存,端口 6379,密码 pan)
sudo docker run -d --name silk-redis --restart always \
-p 6379:6379 \
redis:latest redis-server --requirepass pan --appendonly yes
```
### 4. 配置 PostgreSQL
```bash
sudo service postgresql start
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'pan';"
sudo -u postgres psql -c "CREATE DATABASE silk;"
```
### 5. 安装 Ceph
参考[Ceph 安装文档](https://docs.ceph.net.cn/en/latest/install/get-packages/)
#### 添加APT密钥
要安装 release.asc 密钥,请执行以下操作
```bash
wget -q -O- 'https://download.ceph.com/keys/release.asc' | sudo tee /etc/apt/trusted.gpg.d/ceph.asc
```
#### 添加软件源
将 Ceph 软件包仓库添加到系统的 APT 源列表中。对于较新版本的 Debian/Ubuntu,在命令行上调用 lsb_release -sc 以获取短代号,并替换以下命令中的 {codename}
```bash
sudo apt-add-repository 'deb https://download.ceph.com/debian-tentacle/ {codename} main'
```
#### 安装
```bash
# 安装 CephUbuntu 默认源,Quincy 17.2
sudo apt install -y ceph ceph-common radosgw ceph-volume
# 生成配置
FSID=$(uuidgen)
sudo bash -c "cat > /etc/ceph/ceph.conf << EOF
[global]
fsid = $FSID
mon initial members = a
mon host = 127.0.0.1:6789
osd pool default size = 1
osd pool default min size = 1
osd crush chooseleaf type = 0
mon allow insecure global id reclaim = true
auth_cluster_required = none
auth_service_required = none
auth_client_required = none
[mon.a]
host = localhost
mon addr = 127.0.0.1:6789
[mgr.a]
host = localhost
[client.rgw.a]
host = localhost
rgw frontends = beast port=7480
EOF"
# 创建 Monitor
sudo ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon "allow *"
sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon "allow *" --cap osd "allow *" --cap mds "allow *" --cap mgr "allow *"
sudo ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring
sudo monmaptool --create --add a 127.0.0.1:6789 --fsid $FSID /tmp/monmap
sudo mkdir -p /var/lib/ceph/mon/ceph-a
sudo chown -R ceph:ceph /var/lib/ceph/mon/ceph-a
sudo ceph-mon --mkfs -i a --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring
sudo ceph-mon -i a
sleep 10
# 创建 Manager
sudo mkdir -p /var/lib/ceph/mgr/ceph-a
sudo chown -R ceph:ceph /var/lib/ceph/mgr/ceph-a
sudo bash -c 'ceph auth get-or-create mgr.a mon "allow profile mgr" osd "allow *" mds "allow *" > /var/lib/ceph/mgr/ceph-a/keyring'
sudo ceph-mgr -i a
sleep 3
# 创建 OSDloop device 方式)
for i in 0 1; do
sudo fallocate -l 50G /var/lib/ceph/osd-data-$i
LOOP_DEV=$(sudo losetup -f --show /var/lib/ceph/osd-data-$i)
sudo pvcreate -f $LOOPfd _DEV
sudo vgcreate ceph-osd-vg-$i $LOOP_DEV
sudo lvcreate -l 100%FREE -n osd-$i ceph-osd-vg-$i
sudo ceph-volume lvm prepare --bluestore --data ceph-osd-vg-$i/osd-$i
done
sudo ceph-volume lvm activate --all
sleep 15
# 启动 RGW
sudo mkdir -p /var/lib/ceph/radosgw/ceph-rgw.a
sudo chown -R ceph:ceph /var/lib/ceph/radosgw/ceph-rgw.a
sudo bash -c 'ceph auth get-or-create client.rgw.a osd "allow rwx" mon "allow rw" -o /var/lib/ceph/radosgw/ceph-rgw.a/keyring'
sudo bash -c 'nohup radosgw -n client.rgw.a -k /var/lib/ceph/radosgw/ceph-rgw.a/keyring --rgw-frontends "beast port=7480" > /var/log/ceph/radosgw.log 2>&1 &'
sleep 5
# 创建 S3 用户
sudo radosgw-admin user create --uid=silk-app --display-name="Silk App" \
--access-key=silk-app --secret-key=Silk-App-Secret-2026!
# 验证
sudo ceph -s
curl -s -o /dev/null -w "%{http_code}" http://localhost:7480/ # 应返回 200
```
> **Ceph 关键点**
> - BlueStore 需要块设备,不能直接用目录
> - 用 `fallocate` + `losetup` 创建 loop device,再用 `ceph-volume lvm prepare` 创建 OSD
> - `auth_*_required = none` 简化认证(单节点测试环境)
> - `osd pool default size = 1` 适配单节点(默认 3 副本会导致 PG 一直 inactive
### 6. 安装 VerneMQ
```bash
# 上传 deb 包
# pscp -pw pan e:\silk\tools\vernemq-1.13.0.jammy.x86_64.deb pan@100.83.103.1:/home/pan/
sudo dpkg -i /home/pan/vernemq-1.13.0.jammy.x86_64.deb
# 接受 EULA
sudo sed -i 's/^accept_eula.*/accept_eula = yes/' /etc/vernemq/vernemq.conf
sudo bash -c 'echo "accept_eula = yes" >> /etc/vernemq/vernemq.conf'
# 启动
sudo vernemq start
```
### 7. 安装 IoTDB
```bash
# 上传 IoTDB(含已有数据)
# pscp -r -pw pan e:\silk\tools\iotdb\apache-iotdb-2.0.8-all-bin pan@100.83.103.1:/home/pan/iotdb/
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
# 清理旧锁文件(从 Windows 上传的文件可能需要)
find /home/pan/iotdb/apache-iotdb-2.0.8-all-bin/data -name "*.lock" -delete
# 设置 REST 端口为 18081(避免与 WVP 的 18080 冲突)
IOTDB_CONF=/home/pan/iotdb/apache-iotdb-2.0.8-all-bin/conf/iotdb-system.properties
grep -q "rest_service_port" $IOTDB_CONF && sed -i 's/^rest_service_port.*/rest_service_port=18081/' $IOTDB_CONF || echo "rest_service_port=18081" >> $IOTDB_CONF
# 启动
nohup /home/pan/iotdb/apache-iotdb-2.0.8-all-bin/sbin/start-standalone.sh > /home/pan/iotdb.log 2>&1 < /dev/null &
```
> **Valkey 不可用**`valkey-8.1.2-noble-x86_64.tar.gz` 编译于 Ubuntu 24.04GLIBC 2.38),Ubuntu 22.04 只有 GLIBC 2.35。用 Docker Redis 替代。
### 8. 构建 WVP Docker 镜像
```bash
# 克隆 WVP 源码
cd /home/pan/silk/wvp
git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git wvp-src
cd wvp-src
# 使用自定义 Dockerfile(带 Maven 阿里云镜像加速)
# 从 Windows 上传: pscp -pw pan e:\silk\wvp\Dockerfile pan@100.83.103.1:/home/pan/silk/wvp/wvp-src/Dockerfile
sudo docker build -t docker-polaris-wvp:latest .
# 导入 WVP 数据库初始化 SQL
sudo docker exec -i polaris-mysql mysql -uroot -proot wvp < "数据库/2.7.4/初始化-mysql-2.7.4.sql"
# 授予 MySQL 权限
sudo docker exec polaris-mysql mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wvp_user'@'%'; FLUSH PRIVILEGES;"
```
### 9. 配置并启动 WVP
```bash
# 创建 WVP 配置
mkdir -p /home/pan/silk/wvp/wvp/wvp /home/pan/silk/wvp/logs/wvp
cat > /home/pan/silk/wvp/wvp/wvp/application.yml << 'EOF'
spring:
application:
name: wvp
servlet:
multipart:
max-file-size: 10GB
max-request-size: 10GB
cache:
type: redis
data:
redis:
host: polaris-redis
port: 6379
password: root
timeout: 10000
database: 6
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://polaris-mysql:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
username: wvp_user
password: wvp_password
hikari:
connection-timeout: 20000
maximum-pool-size: 30
minimum-idle: 5
server:
port: 18080
sip:
ip: 0.0.0.0
port: 8116
domain: 3402000000
id: 34020000002000000001
password: 12345678
media:
id:
ip: polaris-media
http-port: 80
secret: su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf
rtp:
enable: true
port-range: 30000,30500
send-port-range: 30000,30500
record-assist-port: 18081
sdp-ip: 100.83.103.1
stream-ip: 100.83.103.1
user-settings:
record-push-live: true
auto-apply-play: true
push-authority: true
use-push-url: false
use-wvp-host: true
enable-fmp4-fallback: true
record-sip: true
enable-audio: true
logging:
level:
root: INFO
EOF
# 启动 WVP 容器
sudo docker run -d --name polaris-wvp --network media-net --restart always \
-p 18080:18080 -p 8116:8116/tcp -p 8116:8116/udp \
-v /home/pan/silk/wvp/wvp/wvp:/opt/ylcx/wvp/ \
-v /home/pan/silk/wvp/logs/wvp:/opt/wvp/logs/ \
-e TZ=Asia/Shanghai \
-e Stream_IP=100.83.103.1 \
-e SDP_IP=100.83.103.1 \
-e ZLM_HOST=polaris-media \
-e ZLM_SERCERT=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf \
-e REDIS_HOST=polaris-redis \
-e DATABASE_HOST=polaris-mysql \
-e SIP_ShowIP=100.83.103.1 \
docker-polaris-wvp:latest
```
> **WVP 端口变更**WVP 2.7.4 的 `server.port` 是 18080(不是之前的 18978)。Go 后端 `.env` 中 `WVP_API_BASE` 需改为 `http://localhost:18080`。
### 10. 部署 Go 后端
```bash
# 在 Windows 上交叉编译
# cd e:\silk\server-go
# $env:GOOS="linux"; $env:GOARCH="amd64"; go build -o silk-server-go-linux ./cmd/server/
# pscp -pw pan silk-server-go-linux pan@100.83.103.1:/home/pan/
chmod +x /home/pan/silk-server-go-linux
# 创建 .env
cat > /home/pan/silk/.env << 'EOF'
PORT=3000
PG=postgresql://postgres:pan@localhost:5432/silk
REDIS=redis://:pan@localhost:6379
MQTT=mqtt://pan:pan@localhost:1883
IOTDB_URL=http://127.0.0.1:18081
S3_ENDPOINT=http://100.83.103.1:7480
S3_ACCESS_KEY=silk-app
S3_SECRET_KEY=Silk-App-Secret-2026!
S3_BUCKET_EVENTS=silk-video-events
S3_BUCKET_ARCHIVE=silk-video-archive
WVP_API_BASE=http://localhost:18080
WVP_USERNAME=admin
WVP_PASSWORD=admin
ZLM_API_BASE=http://localhost:8081
ZLM_SECRET=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf
INTERNAL_API_KEY=silk-internal-2026
RECORDER_API_BASE=http://localhost:9090
EOF
# 启动
cd /home/pan/silk
nohup /home/pan/silk-server-go-linux > server-go.log 2>&1 < /dev/null &
```
### 11. 部署 Go 录制服务
```bash
# 在 Windows 上交叉编译
# cd e:\silk\wvp\recorder-go
# $env:GOOS="linux"; $env:GOARCH="amd64"; go build -o recorder-go-linux .
# pscp -pw pan recorder-go-linux pan@100.83.103.1:/home/pan/
chmod +x /home/pan/recorder-go-linux
nohup /home/pan/recorder-go-linux > /home/pan/recorder.log 2>&1 < /dev/null &
```
### 12. 部署前端
```bash
# 在 Windows 上构建
# cd e:\silk\web; npm run build
# tar -czf dist.tar.gz dist
# pscp -pw pan dist.tar.gz pan@100.83.103.1:/home/pan/
# pscp -pw pan e:\silk\wvp\recorder-go\server.js pan@100.83.103.1:/home/pan/silk/web/server.cjs
mkdir -p /home/pan/silk/web
cd /home/pan/silk/web
tar xzf /home/pan/dist.tar.gz
# 启动
nohup node /home/pan/silk/web/server.cjs > /home/pan/silk/web/web.log 2>&1 < /dev/null &
```
> **server.cjs 命名**`package.json` 中 `"type": "module"` 会导致 `.js` 文件被当作 ES Module 解析。`server.js` 使用 `require()`CommonJS),需重命名为 `server.cjs`。
## 四、验证
```bash
# 检查所有端口
ss -tlnp | grep -E '22|3000|5174|6379|1883|7480|8081|9090|18080|18081|8116'
# Go 后端
curl -s http://localhost:3000/api/v1/health
# 应返回 {"status":"ok"}
# 录制服务
curl -s http://localhost:9090/health
# 应返回 {"status":"ok"}
# 前端
curl -s -o /dev/null -w '%{http_code}' http://localhost:5174/
# 应返回 200
# ZLMediaKit
curl -s -o /dev/null -w '%{http_code}' http://localhost:8081/
# 应返回 200
# WVP
curl -s -o /dev/null -w '%{http_code}' http://localhost:18080/
# 应返回 404(正常,API 在具体路径下)
# Ceph S3
curl -s -o /dev/null -w '%{http_code}' http://localhost:7480/
# 应返回 200
# Docker 容器
sudo docker ps --format "{{.Names}}: {{.Status}}"
# 应显示 5 个容器全部 Up
# Ceph 集群
sudo ceph -s
# 应显示 2 osds: 2 up, 2 in
```
## 五、关键配置文件
### Go 后端 .env (`/home/pan/silk/.env`)
```
PORT=3000
PG=postgresql://postgres:pan@localhost:5432/silk
REDIS=redis://:pan@localhost:6379
MQTT=mqtt://pan:pan@localhost:1883
IOTDB_URL=http://127.0.0.1:18081
S3_ENDPOINT=http://100.83.103.1:7480
S3_ACCESS_KEY=silk-app
S3_SECRET_KEY=Silk-App-Secret-2026!
WVP_API_BASE=http://localhost:18080
ZLM_API_BASE=http://localhost:8081
ZLM_SECRET=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf
RECORDER_API_BASE=http://localhost:9090
```
### WVP application.yml (`/home/pan/silk/wvp/wvp/wvp/application.yml`)
关键配置:
- `sip.port`: 8116
- `sip.domain`: 3402000000
- `sip.id`: 34020000002000000001
- `media.ip`: polaris-mediaDocker 内部网络)
- `media.sdp-ip` / `media.stream-ip`: 100.83.103.1VPN IP,摄像头需要访问)
- `server.port`: 18080
### Ceph (`/etc/ceph/ceph.conf`)
- `auth_*_required = none`(单节点简化认证)
- `osd pool default size = 1`(单副本)
## 六、与 WSL2 部署的差异
| 项目 | WSL2 | 物理机 |
|------|------|--------|
| 文件系统 | ext4 on VHDX(可能变只读) | ext4 on /dev/sda6(稳定) |
| 网络 | 需要 portproxy 转发 | 直连,无需 portproxy |
| IP | 172.18.127.247(可能变化) | 100.83.103.1WireGuard 固定) |
| WVP 端口 | 18978 | 18080 |
| 缓存 | Valkey(裸机安装) | Docker RedisValkey GLIBC 不兼容) |
| Ceph | 已配置(可直接启动) | 需从头配置(loop device OSD |
| WVP 镜像 | 已构建 | 需从 Gitee 克隆源码构建 |
## 七、重启后恢复
物理机重启后,systemd 管理的服务(Docker、PostgreSQL、VerneMQ)会自动启动。需要手动启动的服务:
```bash
# 1. Cephsystemd 管理,但 loop device 需要手动激活)
sudo ceph-mon -i a
sudo ceph-mgr -i a
# loop device 需要重新挂载
for i in 0 1; do
sudo losetup /dev/loop$((i+8)) /var/lib/ceph/osd-data-$i
sudo ceph-volume lvm activate --all
done
# RGW
sudo bash -c 'nohup radosgw -n client.rgw.a -k /var/lib/ceph/radosgw/ceph-rgw.a/keyring --rgw-frontends "beast port=7480" > /var/log/ceph/radosgw.log 2>&1 &'
# 2. IoTDB
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
nohup /home/pan/iotdb/apache-iotdb-2.0.8-all-bin/sbin/start-standalone.sh > /home/pan/iotdb.log 2>&1 < /dev/null &
# 3. Go 后端
cd /home/pan/silk
nohup /home/pan/silk-server-go-linux > server-go.log 2>&1 < /dev/null &
# 4. Go 录制服务
nohup /home/pan/recorder-go-linux > /home/pan/recorder.log 2>&1 < /dev/null &
# 5. 前端
nohup node /home/pan/silk/web/server.cjs > /home/pan/silk/web/web.log 2>&1 < /dev/null &
```
## 摄像头注册信息
摄像头 GB28181 注册参数:
| 参数 | 值 | 说明 |
|------|-----|------|
| SIP 服务器 IP | `100.83.103.1` | WireGuard VPN IP |
| SIP 服务器端口 | `8116` | TCP/UDPDocker 映射 `-p 8116:8116/tcp -p 8116:8116/udp` |
| SIP 域 | `3402000000` | |
| SIP 服务器 ID | `34020000002000000001` | |
| SIP 密码 | `12345678` | |
> 摄像头需能访问 `100.83.103.1`WireGuard VPN)。若摄像头不在 VPN 网络,改用物理网卡 IP `192.168.1.4`,同时修改 WVP 配置中的 `sip.ip`、`media.sdp-ip`、`media.stream-ip`。
## 八、常见问题
### 1. Valkey GLIBC 不兼容
**现象**`valkey-cli: /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.38' not found`
**原因**`valkey-8.1.2-noble-x86_64.tar.gz` 编译于 Ubuntu 24.04Noble),需要 GLIBC 2.38Ubuntu 22.04 只有 2.35。
**解决**:用 Docker Redis 替代(`docker run -d --name silk-redis -p 6379:6379 redis:latest redis-server --requirepass pan`)。
### 2. Ceph OSD 创建失败
**现象**`bluestore _read_bdev_label failed to open /var/lib/ceph/osd/ceph-0/block: (2) No such file or directory`
**原因**:BlueStore 需要块设备,不能直接用目录。
**解决**:用 `fallocate` 创建文件 + `losetup` 创建 loop device + `ceph-volume lvm prepare --bluestore --data <vg/lv>`
### 3. WVP 启动报 `Could not resolve placeholder 'media.id'`
**原因**`application.yml``media``sip` 应在顶层,不是 `user-settings` 下。
**解决**:参考步骤 9 的 `application.yml` 模板。
### 4. WVP 报 `Failed to obtain JDBC Connection`
**原因**MySQL 未导入 WVP 初始化 SQL,或 `wvp_user` 权限不足。
**解决**
```bash
docker exec -i polaris-mysql mysql -uroot -proot wvp < "数据库/2.7.4/初始化-mysql-2.7.4.sql"
docker exec polaris-mysql mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wvp_user'@'%'; FLUSH PRIVILEGES;"
```
### 5. server.js 报 `Cannot use import statement outside a module`
**原因**`package.json``"type": "module"` 导致 `.js` 文件按 ES Module 解析,但 `server.js` 使用 CommonJS (`require()`)。
**解决**:将 `server.js` 重命名为 `server.cjs`
### 6. Docker 镜像拉取失败
**现象**`could not fetch content descriptor ... not found`
**解决**:配置 Docker 镜像加速(`/etc/docker/daemon.json` 中设置 `registry-mirrors`)。
### 7. Ceph OSD 重启后不自动激活
**原因**loop device 重启后需要重新挂载。
**解决**:参考"七、重启后恢复"中的 Ceph 部分。
## 九、前端测试
- 地址:`http://100.83.103.1:5174/`
- 用户名:`admin`
- 密码:`admin123`
- WVP 管理: http://100.83.103.1:18080/
## 十、实时视频"等待视频流"问题排查与修复
### 现象
前端 /videos 页面点击查看实时视频,一直显示"等待视频流...",控制台报 `POST /api/v1/video/cameras/1/live 503`。点击"开始录制"同样报 503。
### 根因(共 4 个问题,需全部修复)
| # | 问题 | 原因 |
|---|------|------|
| 1 | Go 后端调用 WVP 端口错误 | `config.go``envDefault:"http://localhost:18978"`Go 后端用 `caarlos0/env` 读 **OS 环境变量**而非 `.env` 文件,`.env` 未被加载 |
| 2 | ZLMediaKit hooks 指向 `127.0.0.1:18080` | WVP 每次启动时会重置 ZLMediaKit hooks,用 `127.0.0.1`(容器自身)而非 `polaris-wvp`Docker 网络主机名) |
| 3 | ZLMediaKit `mediaServerId` 为空 | WVP 配置 `media.id:` 为空,推流时 `on_publish` hook 报"找不到对应的mediaServer" |
| 4 | 流 URL 含 Docker 内部主机名 | WVP 返回的播放地址用 `polaris-media:80``fixZlmPort` 只替换端口不替换主机名,浏览器无法解析 `polaris-media` |
### 修复方法
#### 1. Go 后端加载 .env 环境变量
Go 后端用 `caarlos0/env` 库读取 OS 环境变量,不自动读 `.env` 文件。启动时必须先 `source .env`
```bash
cd /home/pan/silk
set -a
source .env
set +a
nohup /home/pan/silk-server-go-linux > server-go.log 2>&1 < /dev/null &
```
确保 `.env``WVP_API_BASE=http://localhost:18080`(不是 18978)。
#### 2. 修复 ZLMediaKit hooks(每次 WVP 重启后需重新执行)
WVP 启动时会将 ZLMediaKit hooks 重置为 `127.0.0.1:18080`,需要手动改为 `polaris-wvp:18080`
```bash
SECRET="su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf"
HOOK_BASE="http://polaris-wvp:18080"
curl -s "http://localhost:8081/index/api/setServerConfig?secret=$SECRET" \
--data-urlencode "hook.on_play=$HOOK_BASE/index/hook/on_play" \
--data-urlencode "hook.on_publish=$HOOK_BASE/index/hook/on_publish" \
--data-urlencode "hook.on_record_mp4=$HOOK_BASE/index/hook/on_record_mp4" \
--data-urlencode "hook.on_rtp_server_timeout=$HOOK_BASE/index/hook/on_rtp_server_timeout" \
--data-urlencode "hook.on_send_rtp_stopped=$HOOK_BASE/index/hook/on_send_rtp_stopped" \
--data-urlencode "hook.on_server_keepalive=$HOOK_BASE/index/hook/on_server_keepalive" \
--data-urlencode "hook.on_server_started=$HOOK_BASE/index/hook/on_server_started" \
--data-urlencode "hook.on_stream_changed=$HOOK_BASE/index/hook/on_stream_changed" \
--data-urlencode "hook.on_stream_none_reader=$HOOK_BASE/index/hook/on_stream_none_reader" \
--data-urlencode "hook.on_stream_not_found=$HOOK_BASE/index/hook/on_stream_not_found"
```
> **注意**:每次 WVP 容器重启后都需重新执行此命令。可将此命令加入启动脚本。
#### 3. 设置固定的 mediaServerId
在 WVP `application.yml` 中设置 `media.id`
```yaml
media:
id: silk-media-001 # 不能为空
```
同时通过 ZLMediaKit API 设置:
```bash
curl -s "http://localhost:8081/index/api/setServerConfig?secret=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf" \
--data-urlencode "general.mediaServerId=silk-media-001"
```
#### 4. 修复流 URL 中的 Docker 内部主机名
修改 `server-go/internal/service/media.go` 中的 `fixZlmPort` 函数,增加主机名替换:
```go
func fixZlmPort(u string) string {
if u == "" {
return u
}
// 替换 Docker 内部主机名为外部可访问 IP
u = strings.Replace(u, "polaris-media:", "100.83.103.1:", 1)
u = strings.Replace(u, ":80/", ":8081/", 1)
if strings.HasSuffix(u, ":80") {
u = u[:len(u)-2] + ":8081"
}
return u
}
```
重新交叉编译并部署:
```powershell
cd e:\silk\server-go
$env:GOOS="linux"; $env:GOARCH="amd64"
go build -o silk-server-go-linux ./cmd/server/
$env:GOOS=""; $env:GOARCH=""
pscp -pw pan silk-server-go-linux pan@100.83.103.1:/home/pan/silk-server-go-linux
```
### 验证
修复后 WVP 日志应显示:
```
[ZLM-连接成功] IDsilk-media-001, 地址: polaris-media:80
[ZLM HOOK]推流鉴权-允许-响应:silk-media-001
[ZLM HOOK] 流注册, silk-media-001->rtsp->rtp/...
[点播成功] 设备编号: 34020000002000000001
```
Go 后端日志应显示:
```
INFO 调用 WVP play/start url=http://localhost:18080/api/play/start/...
INFO 请求 method=POST path=/api/v1/video/cameras/1/live status=200 latency=1.7s
```
前端播放器收到的流地址格式:
```
http://100.83.103.1:8081/rtp/34020000002000000001_34020000001310000001.live.flv
```
### WVP 重启后的完整修复脚本
将以下脚本保存为 `/home/pan/fix-hooks.sh`,每次 WVP 重启后执行:
```bash
#!/bin/bash
SECRET="su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf"
HOOK_BASE="http://polaris-wvp:18080"
curl -s "http://localhost:8081/index/api/setServerConfig?secret=$SECRET" \
--data-urlencode "hook.on_play=$HOOK_BASE/index/hook/on_play" \
--data-urlencode "hook.on_publish=$HOOK_BASE/index/hook/on_publish" \
--data-urlencode "hook.on_record_mp4=$HOOK_BASE/index/hook/on_record_mp4" \
--data-urlencode "hook.on_rtp_server_timeout=$HOOK_BASE/index/hook/on_rtp_server_timeout" \
--data-urlencode "hook.on_send_rtp_stopped=$HOOK_BASE/index/hook/on_send_rtp_stopped" \
--data-urlencode "hook.on_server_keepalive=$HOOK_BASE/index/hook/on_server_keepalive" \
--data-urlencode "hook.on_server_started=$HOOK_BASE/index/hook/on_server_started" \
--data-urlencode "hook.on_stream_changed=$HOOK_BASE/index/hook/on_stream_changed" \
--data-urlencode "hook.on_stream_none_reader=$HOOK_BASE/index/hook/on_stream_none_reader" \
--data-urlencode "hook.on_stream_not_found=$HOOK_BASE/index/hook/on_stream_not_found"
echo "Hooks fixed."
```
## 十一、录像片段查不到问题
### 现象
前端 /videos "历史回看"点击"查询录像"看不到任何录像片段。点击"开始录制"后录制服务立即退出,录制 0 段。
### 原因
Ceph RGW 只创建了 S3 用户(`silk-app`),但**没有创建 S3 bucket**。录制服务上传视频片段时 S3 返回 `404 NoSuchBucket`,录制线程立即退出。
录制服务日志:
```
CreateMultipartUpload 失败: operation error S3: CreateMultipartUpload, https response error StatusCode: 404, api error NoSuchBucket: UnknownError
录制线程退出(共完成 0 段)
```
### 修复方法
使用 Python S3 API 创建 bucket`radosgw-admin` 没有 `bucket create` 子命令):
```bash
# 上传 create-buckets.py 到服务器后执行
python3 /home/pan/create-buckets.py
```
`create-buckets.py` 内容:
```python
#!/usr/bin/env python3
import http.client, hashlib, hmac, datetime, base64
host = "localhost:7480"
access_key = "silk-app"
secret_key = "Silk-App-Secret-2026!"
buckets = ["silk-video-archive", "silk-video-events"]
for bucket in buckets:
conn = http.client.HTTPConnection(host)
date = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
string_to_sign = f"PUT\n\n\n{date}\n/{bucket}"
signature = base64.b64encode(
hmac.new(secret_key.encode(), string_to_sign.encode(), hashlib.sha1).digest()
).decode()
conn.request("PUT", f"/{bucket}", headers={
"Date": date,
"Authorization": f"AWS {access_key}:{signature}"
})
resp = conn.getresponse()
print(f"Bucket {bucket}: {resp.status} {resp.reason}")
conn.close()
```
创建后重启录制服务:
```bash
sudo fuser -k 9090/tcp
sleep 2
nohup /home/pan/recorder-go-linux > /home/pan/recorder.log 2>&1 < /dev/null &
```
### 验证
```bash
# 检查 bucket 列表
python3 /home/pan/create-buckets.py # 会列出所有 bucket
# 录制服务日志应显示正常录制
tail -5 /home/pan/recorder.log
# 不应有 NoSuchBucket 错误
```
> **注意**Ceph RGW 的 `radosgw-admin` 不支持 `bucket create` 命令,bucket 必须通过 S3 APIPUT /bucket-name)创建。