ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Docker部署SRS流媒体服务器实战:从RTMP到WebRTC全链路配置与踩坑记录

Docker部署SRS流媒体服务器实战:从RTMP到WebRTC全链路配置与踩坑记录 我刚用 Docker 把 SRS 流媒体服务器从头到尾部署了一遍整个流程比想象中顺畅太多。今天把完整过程写出来包括我踩过的坑、调过的参数、验证过的推拉流路径一次性讲清楚。不管你是想自建直播服务、做视频监控平台、还是搞 WebRTC 低延迟通话这篇文章都能帮你少走弯路。SRS 全称是 Simple Realtime Server目前已经是 4.0 版本一个非常成熟的开源实时音视频服务器。它原生支持 RTMP、HTTP-FLV、HLS、WebRTC、SRT、GB28181 等一堆协议意味着你可以用它接收 OBS 的 RTMP 推流也可以让浏览器通过 WebRTC 直接连上来低延迟观看甚至对接海康、大华摄像头做 GB28181 国标接入能力覆盖得非常广。用 Docker 部署 SRS 最大的好处就是不用自己折腾编译环境、依赖库和系统服务配置。SRS 源码编译并不算轻松依赖关系多参数调起来也麻烦而官方 Docker 镜像把这些脏活累活都处理好了。你只需要把镜像拉下来把配置文件和端口对好一条命令就能启动一个功能完整的流媒体服务这对快速验证场景和生产环境落地都很友好。1. 部署前必须搞清楚的事动手之前我建议你先想明白自己到底要用 SRS 做什么这直接决定你选哪个镜像版本、开哪些端口、用哪种配置模板。1.1 SRS 能解决什么问题SRS 本质上是一个媒体分发中枢。你可以把摄像头、电脑屏幕、手机画面推到 SRS 上SRS 再把这些流转换协议、分发到不同的终端。它解决的几个核心痛点我用自己的话总结一下第一协议转换。推流端通常用 RTMP因为 RTMP 在复杂网络下更稳定但浏览器原生不支持 RTMP。SRS 收到 RTMP 流后可以转成 HTTP-FLV 或 HLS 给浏览器播放这就打通了采集端和播放端之间的协议壁垒。第二低延迟分发。如果做直播连麦、远程操控这种场景延迟必须控制在几百毫秒以内SRS 的 WebRTC 能力就是干这个的配合 WHIP/WHEP 协议可以轻松实现浏览器直接推拉流。第三多协议覆盖。一套服务同时支持 HLS 切片用于 Apple 生态播放器支持 SRT 协议用于弱网环境下的稳定传输支持 GB28181 用于安防摄像头接入相当于一台设备顶多台专用服务器。1.2 Docker 部署相对于源码编译的优势我之前在 CentOS 上源码编译过 SRS印象太深刻了。依赖下载慢、编译时间动辄半小时起步、不同系统之间的兼容性问题折磨死人。后来切到 Docker 部署最直观的感受就是版本切换变得非常简单今天用 4.0.2 验证功能明天换成 5.0 版本做测试改个镜像标签就行宿主机上一点残留都不会有。另外 Docker 对系统环境是隔离的。SRS 运行时依赖特定的 glibc、openssl 库版本如果用源码编译这些依赖可能和系统上的其他应用产生冲突。容器化之后所有的依赖都封装在镜像里和宿主机环境解耦安全性也更高不会因为 SRS 的某个配置失误直接破坏宿主机的网络栈。1.3 确定你的使用场景和性能预期SRS 的性能和你的硬件配置、网络带宽强相关。单核 CPU、1GB 内存的小鸡鸡跑一个转发 RTMP 到 HLS 的小型直播场景几十路并发没问题。但如果要做 WebRTC 大规模会议就需要多核 CPU 和充足的内存因为 WebRTC 的编码交换非常吃 CPU 资源。我这次部署的目标场景是OBS 推 RTMP 流经过 SRS 转成 HTTP-FLV 和 HLS用于网页和手机端播放同时验证 WebRTC 低延迟播放路径。所以我选的是 SRS 4.0 稳定版镜像端口规划上预留了 1935RTMP、8080HTTP API 和 HTTP-FLV、1985HTTP API、8000WebRTC over UDP。如果你还要做 GB28181得额外开放 9000 端口给 SIP 信令用。注意Docker 端口映射有一个容易忽略的坑WebRTC 是 UDP 协议必须在 docker run 或者 docker-compose 里同时映射 UDP 端口只映射 TCP 端口的话WebRTC 推拉流会失败。2. 环境准备与镜像拉取这次部署我用的是一台 2 核 4G 的云服务器操作系统是 Ubuntu 22.04Docker 版本是 24.0.5。下面我把环境准备的关键步骤拆开讲每个步骤都说清楚为什么这么做。2.1 安装 Docker 环境如果你服务器上还没有 Docker先把基础环境装好。Ubuntu 系统推荐用官方脚本安装又快又省事。curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun这个命令会自动配置好软件源和 Docker 服务。如果是 CentOS 或者 Windows 系统直接去 Docker 官网下载对应安装包即可Windows 上记得装 WSL2 后端。装完之后先验证一下sudo docker info能看到 System Info 和 Server Version 等信息就说明 Docker 正常工作了。我建议顺手把当前用户加入 docker 用户组这样后面执行 docker 命令就不用每次都加 sudo。sudo usermod -aG docker $USER这条命令之后需要重新登录终端才会生效。2.2 解决 Docker 镜像拉取慢的问题国内拉取 Docker Hub 镜像经常遇到超时和极慢的情况这也是部署 SRS 最常见的卡点之一。SRS 官方镜像比较大不配镜像加速器的话拉取过程可能持续几十分钟甚至直接失败。我习惯在/etc/docker/daemon.json里配置镜像加速地址。文件内容大概长这样{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.mirrors.ustc.edu.cn ] }配置完成之后重启 Docker 服务sudo systemctl restart docker。这里提醒一句不同的加速地址稳定性不一样如果某个加速源拉取速度不理想换一个再试。实测下来拉取 SRS 镜像加上它的基础镜像文件总共大概几百兆加速正常的话五分钟以内能完成。2.3 拉取 SRS 官方镜像基础环境就绪后开始拉 SRS 镜像。我用的是带完整功能的 ossrs/srs:4 标签这个镜像内置了 FFmpeg 和 SRS 主程序对于验证业务完全够用。docker pull ossrs/srs:4如果希望用最新开发版或者准备跑 SRS 5.0 的 WebRTC 增强功能可以拉取ossrs/srs:5。不过我建议生产环境优先用 4.x 稳定版本5.0 虽然是当前主推的版本API 改动更多社区资料相对少一些。我这次就是为了完全求稳选择了 4.0。拉取完成后可以用docker images查看镜像看到 ossrs/srs 出现就说明成功了。3. 容器化部署 SRS 的完整实操环境准备好了接下来就是最关键的部署环节。我按两种方式讲先讲直接用 docker run 快速启动验证再讲用 docker-compose 做正式部署。两条路都走一遍你根据自己的习惯选。3.1 快速启动一条命令跑起来如果你只是想在本地快速验证 SRS 能不能用直接执行这条命令docker run --rm -d \ -p 1935:1935 \ -p 1985:1985 \ -p 8080:8080 \ -p 8000:8000/udp \ -p 8000:8000/tcp \ ossrs/srs:4启动之后检查一下容器状态docker ps看到 srs 容器状态为 Up 就说明 SRS 已经运行了。然后打开浏览器访问http://你的服务器IP:8080如果能看到 SRS 的欢迎页和控制台界面就说明 Web 服务已经正常启动。这一条命令背后做了几件事映射 RTMP 端口 1935让推流端能连上来映射 1985 给 HTTP API 使用映射 8080 提供 HTTP-FLV 播放和网页控制台映射 8000 的 TCP/UDP 给 WebRTC 传输数据。理解每个端口的用途很重要后面排查问题的时候你就知道该查哪个口了。3.2 正式部署docker-compose 方案用 docker run 直跑适合临时测试但正式的部署我强烈推荐用 docker-compose。好处有两个一是配置可维护环境变量、端口映射、数据卷都在一个文件里团队协作和二次部署都方便二是可以统一管理重启策略和网络模式。我的 docker-compose.yml 内容如下version: 3.8 services: srs: image: ossrs/srs:4 container_name: srs-server restart: always ports: - 1935:1935 - 1985:1985 - 8080:8080 - 8000:8000/tcp - 8000:8000/udp volumes: - ./srs.conf:/usr/local/srs/conf/srs.conf - ./logs:/usr/local/srs/objs environment: - TZAsia/Shanghai这个配置有几个细节值得展开说restart: always解决了服务崩溃或服务器重启后的自愈问题。流媒体服务通常要求 7x24 小时在线有这一行至少不用担心宕机了没人管。volumes 挂载把宿主机上的 srs.conf 配置文件和容器内的配置关联起来这样我改完配置只需要docker restart srs-server就行不用重新打镜像。日志目录也挂出来排查问题的时候直接从宿主机查看不用进容器。启动命令就是标准的 compose 流程docker compose up -d3.3 自定义配置文件把控制权拿回来默认配置其实已经能让 SRS 跑起来但要做真实业务最好还是自己写配置文件。默认配置走的是 docker 镜像里的 srs.conf没有针对具体场景优化。我使用的配置文件核心段落如下listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; } rtc_server { enabled on; listen 8000; # 生产环境请改为实际公网 IP candidate $CANDIDATE; } vhost __defaultVhost__ { tcp_nodelay on; min_latency on; play { gop_cache off; queue_length 10; } publish { mr on; mr_latency 350; } hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 2; hls_window 6; } http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } rtc { enabled on; rtmp_to_rtc on; rtc_to_rtmp on; } }我解释一下几个关键配置项的用途daemon off这个必须保持开启状态Docker 容器需要前台进程存活如果配置成 daemon on容器会启动后马上退出。我一开始就踩过这个坑容器起来之后几秒钟就死了检查日志才发现是 daemon 配置的问题。srs_log_tank console同理让 SRS 日志输出到标准输出这样docker logs srs-server才能看到日志。http_remux开启后SRS 就能把 RTMP 流转成 HTTP-FLV 流播放器可以通过http://IP:8080/live/livestream.flv这样的地址直接播放。hls配置我设成了 2 秒一个切片6 秒窗口这是延迟和流畅性都比较均衡的组合。rtc 配置块里开启了 rtmp_to_rtc 和 rtc_to_rtmp支持 RTMP 推流转 WebRTC 播放以及 WebRTC 推流转 RTMP 播放双向打通。这里有一个容易踩坑的地方rtc_server 里的 candidate 参数。WebRTC 建立连接时要进行 NAT 穿透需要知道服务器的公网地址。如果 candidate 配错了客户端能连接服务器但媒体数据传不回来表现为一直黑屏无法出流。我一开始没配这个参数局域网内测试一切正常换到公网服务器就不行了排查很久才找到是这个参数的问题。生产部署时我建议把它改成你的服务器公网 IP或者用环境变量注入的方式动态配置。3.4 配置文件的生效与验证配置文件写好之后修改 docker-compose.yml 挂载的配置文件路径然后重启docker compose down docker compose up -d查看启动日志docker logs -f srs-server看到日志里出现SRS is running或者类似的关键字就说明服务已经正常启动。接下来推荐用 SRS 自带的 API 做一个快速验证请求http://IP:1985/api/v1/versions如果能返回 JSON 数据说明 HTTP API 正常。再请求http://IP:1985/api/v1/summaries能看到当前的连接数、带宽等运行时状态也可以顺便确认流媒体引擎检测正常。4. 推流与拉流全链路实测服务端配置好了必须实际推拉流来验证整条链路。我用 OBS 和 FFmpeg 各推了一路流分别用 HTTP-FLV、HLS 和 WebRTC 播放结果都正常出流。下面是具体的操作过程。4.1 使用 OBS 推送 RTMP 流OBS 的配置很简单。打开 OBS进入「设置」→「直播」服务选「自定义」服务器地址填rtmp://你的服务器IP/live推流码填livestream然后点击开始推流。这里的解析一下推流 URL 的结构/live是应用名Stream 名称livestream是流名。SRS 默认的 vhost 是__defaultVhost__所有没有匹配到特定 vhost 的流都会走这个默认配置。推流成功后播放地址对应的就是HTTP-FLVhttp://你的服务器IP:8080/live/livestream.flvHLShttp://你的服务器IP:8080/live/livestream.m3u8WebRTCwebrtc://你的服务器IP/live/livestream需要注意的是OBS 推流走的是 RTMP 协议端口是 1935如果你在本地防火墙或者云安全组里只开放了 8080 而忘了 1935OBS 会一直显示连接失败。4.2 使用 FFmpeg 模拟推流如果你没有 OBS用 FFmpeg 推流也一样方便还方便做自动化测试。我用了系统自带的测试视频源ffmpeg -re -f lavfi -i testsrcsize1280x720:rate30 -f lavfi -i sinefrequency1000:sample_rate44100 \ -vcodec libx264 -preset veryfast -tune zerolatency -acodec aac \ -f flv rtmp://your-server-ip/live/test这条命令用的是 FFmpeg 内置的 testsrc 视频源和 sine 音频源不用准备实际的视频文件。推流后同样可以通过http://IP:8080/live/test.flv播放。这里多说一句-tune zerolatency参数它能让编码器牺牲一点压缩率来换取最低的编码延迟对实时流非常重要。如果是普通的短视频转码不需要加这个参数但直播场景一定得加不然累积延迟会越来越大。4.3 各协议播放效果实测我分别用三种方式验证了播放效果HTTP-FLV 播放延迟最低实测大约在 1-3 秒之间兼容性也比较好支持 flv.js 的浏览器都能播放。我在浏览器里用 flv.js 播放拉流地址http://IP:8080/live/test.flv画面清晰流畅音画同步正常。HTTP-FLV 是目前国内直播站点最主流的低延迟播放方案推荐优先使用。HLS 播放兼容性最好iOS Safari、Android Chrome 原生支持但延迟也比较高在 5-10 秒之间。我用 VLC 播放了http://IP:8080/live/test.m3u8正常出流。HLS 适合对延迟要求不高的点播回看场景不适合实时性要求强的互动直播。WebRTC 播放延迟最低实测在 500ms 以内几乎无感知。WebRTC 播放通过webrtc://IP/live/test地址拉起具体用 WHIP/WHEP 客户端接入。我用浏览器直接走 WHEP 会话拉流从 OBS 推流到浏览器出画面延迟的体感就和看本地摄像头差不多。如果做视频连麦、远程手术示教这类场景WebRTC 是唯一的正经选择。4.4 用 SRS 控制台观察运行状态SRS 自带一个简单的 HTTP 控制台地址是http://IP:8080/console/在里面可以看到当前的推流状态、播放连接数、带宽数据。如果觉得控制台功能太简单也可以直接调用 HTTP API比如curl http://IP:1985/api/v1/streams/这个接口返回一个 JSON 数组里面包含当前所有的推流流信息包括流名、客户端IP、视频编码、分辨率、码率等。我自己写了个小脚本每分钟拉一次这个接口如果流中断了马上通过钉钉群机器人告警省了不少事。5. 常见问题与排查经验部署和测试过程中我遇到了好几个问题这里逐个记录都是可以用最短时间解决的但没经验的话可能会卡一整天。5.1 容器启动后马上退出这个问题的典型表现是docker ps看不到容器或者容器状态是 Exited。先用docker logs srs-server看日志我遇到的情况是日志里报signal: killed或者Segmentation Fault最后定位到是配置文件的 daemon 参数问题。SRS 在 Docker 里必须以daemon off前台模式运行默认配置里如果写的是daemon on容器启动后 SRS 自己 fork 到后台Docker 找不到前台进程就把容器杀了。还有一种情况是端口被占用。如果 1935 端口已经被宿主机上的其他程序占用了SRS 启动时绑定端口失败也会直接退出。解决方法是换一个端口映射比如-p 19350:1935前提是你理解这时外部推流地址要改成rtmp://IP:19350/live/xxx。5.2 推流成功但播放黑屏或卡顿这类问题最常见的原因是 GOP 缓存配置。在 SRS 默认配置里客户端的播放可能要从关键帧开始才能解码出画面如果播放器恰好错过了关键帧就会一直黑屏等待下一个关键帧。可以通过把 HTTP 播放器配置里的gop_cache打开来解决但这会增加一点延迟。我自己的做法是在 vhost 里保持gop_cache off因为我的场景对延迟更敏感。另外推流端和播放端的编码参数不一致也会导致花屏或卡顿。比如视频源是 H.264 High Profile某些老客户端只支持 Baseline Profile播放就会出问题。建议推流端统一使用 H.264 Main Profile AAC 音频这是兼容性最好的组合。5.3 WebRTC 无法连接一直显示连接中遇到 WebRTC 连接不上九成是 candidate 配置或者端口开放问题。先检查云服务商的安全组是否放行了 8000 端口的 UDP 和 TCP再检查系统防火墙sudo ufw status。这两个地方都确认没问题之后再看 SRS 日志里有没有candidate相关的报错。还有一个隐蔽的坑如果你服务器上有多个网卡或者用了 NAT 网关SRS 会自动探测本机 IP但探测到的可能是内网 IP这个 IP 公网访问不到。这种情况必须手动指定 candidate 为公网地址或者使用ifconfig那个有公网 IP 的网卡来监听。5.4 常见问题速查表问题现象可能原因排查命令 / 解决方案容器启动后秒退daemon 未设置为 off或端口被占用检查 srs.conf 中daemon off执行netstat -tlnp | grep 1935查端口占用推流连接失败1935 端口未在云安全组和防火墙放行检查安全组/防火墙telnet IP 1935测试连通性播放 HTTP-FLV 黑屏gop_cache 配置关闭导致等待关键帧播放器多次重连或开启 gop_cache确认推送流编码参数HLS 播放延迟过高切片时长设置过大hls_fragment 调小到 1-2 秒hls_window 设为 3-6 秒WebRTC 一直连接中candidate 配置错误/端口未放行检查http://IP:1985/api/v1/rtc返回确认 8000 TCP/UDP 放行公网访问 8080 不通云安全组未放行 HTTP 端口检查云控制台入方向规则放行 8080 TCP5.5 性能调优与稳定性经验如果你准备把 SRS 用于正式生产环境这几个经验点可以参考关于内核参数调优。高并发场景下可以适当调整 Linux 内核参数比如net.core.rmem_max和net.core.wmem_max增大 Socket 缓冲区处理大码率流时能降低丢包率。不过这些调整在容器里需要特权模式才能生效我的做法是在宿主机上直接配置容器启动时加--network host让 SRS 直接使用宿主机的网络栈。这个方案在性能要求高的场景下推荐使用但需要注意端口冲突管理的复杂度会增加。关于日志轮转。SRS 在 console 模式下日志量挺大的长时间运行不处理会吃掉大量磁盘空间。我写了个简单的 logrotate 脚本每天对/var/lib/docker/containers/*/*-json.log做切分和压缩保留最近 7 天日志这个操作帮我避免了好几次磁盘空间告警。关于版本选择。SRS 4.0 和 5.0 我都试过5.0 在 WebRTC 的 SFU 能力和 API 设计上有不少改进但社区参考资料确实比 4.0 少。个人建议如果你不是特别需要 5.0 的新特性4.0 已经足够稳定遇到问题也好搜资料。等你的主要功能在 4.0 上验证通了再计划性地迁移到 5.0 也不迟。6. 进阶玩法SRS 与其他服务的组合SRS 不只是单独运行一个流媒体服务它和很多其他开源组件配合起来可以搭建更完整的音视频平台。这里简单聊几个我验证过的组合方案。6.1 结合服务端录制做点播回看SRS 原生支持 DVR 录制功能把直播流直接写成 FLV 文件存到磁盘。我的配置文件里加了一段vhost __defaultVhost__ { dvr { enabled on; dvr_path ./objs/nginx/html/record/[app]/[stream]/[2006-01-15]/[2006-01-15]_[15-04-05].flv; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; } }这样直播的同时就能生成回放文件之后可以把这些文件接入到点播服务或者定期转码成 MP4 存档。6.2 与 FFmpeg 集群协同做转码SRS 本身不做视频转码但可以通过 HTTPCallback 对接 FFmpeg 集群。当 SRS 收到一个推流回调通知转码服务FFmpeg 拉取原始流做转码后再推回给 SRS 分发不同的清晰度。我在实际项目中这样实现过原始流默认 1080P 推到 SRSFFmpeg 收到回调后把流拉下来转成 720P 和 480P 两路重新推回 SRS 的同一个 vhost 下播放端根据带宽和终端类型选择对应清晰度的播放地址。如果你对延迟要求不高这个方案完全可以替代商业转码服务。6.3 与监控系统集成SRS 的 HTTP API 数据可以非常方便地接入 Prometheus 这类监控系统。我在服务器上跑了 node-exporter 加 Prometheus通过脚本定期抓取 SRS 的/api/v1/summaries数据把推流数、播放数、总带宽这些指标转换成 Prometheus 格式。再配合 Grafana 的仪表盘实时看到整个平台的运行状态比手动登录服务器查看高效太多了。这类实践在真实运维中价值极高所有涉及音视频线上业务的团队我都很建议把监控体系搭起来否则每路流的故障定位都会非常被动。我个人在实际操作中的体会是Docker 部署 SRS 真正的难点不在 Docker 命令而在对流媒体协议和 SRS 配置项的理解Docker 只是帮你省去了环境搭建的麻烦。这篇内容从镜像准备、配置文件、推流验证到问题排查都覆盖了按着一步步操作应该很快能跑通。最后再分享一个小技巧SRS 的docker exec -it srs-server ./objs/srs -v命令可以查看当前版本而遇到疑难杂症时用docker logs --tail200 srs-server拉出最近 200 行日志绝大多数问题都能从里面找到线索。祝你顺利搭建出自己的实时音视频平台。
返回列表