K8S
流媒体服务和流媒体服务器的关键差异是什么?高效的运维能力是其中极其关键的差异之一,云计算+Docker+K8S让开源项目也能拥有这种能力,让每个人都能具备互联网流媒体服务能力,正如 :旧时王谢堂前燕,飞入寻常百姓家!
为何要用k8s部署SRS集群?
- Simple(简单有效): 这玩意儿真的非常简单、高效便捷、直击服务部署和维护的痛点。羽扇纶巾,谈笑间强撸灰飞湮灭,不信一起来看QuickStart.
 - Declarative deployment(声明式部署):只需要根据业务量声明需要多少个SRS,自动配置和更新SLB,不用启动服务和看门狗,也不用机器故障时一顿操作猛如虎的迁移和更新。
 - Expand easily(扩容很容易): K8S可以自动扩容底层基础设施,例如可通过ESS自动,而业务集群(如SRS Edge)通过修改Pod数量(或根据策略)实现扩容。
 - Rolling Update(滚动式更新): K8S可以在不中断服务的前提下,实现服务的更新、回滚和灰度发布,这是提供稳定可靠高效服务的大杀器,总不能每次更新就被用户投诉吧?总不能每次都半夜三更提心吊胆吧?
 
本文介绍了,在不同的业务场景下,如何使用ACK(AlibabaCloud Container Service for Kubernetes)构建SRS集群。
- Deploy to Cloud Platforms: 直接部署GitHub项目到云平台K8s。
 - Quick Start: 快速入门,在ACK中部署单SRS源站服务。
 - SRS Shares Volume with Nginx: SRS能分发简单的HTTP,也能和Nginx配合工作提供更强大的HTTP能力,比如:SRS分发RTMP/HTTP-FLV等流协议,Nginx分发HLS。
 - SRS Edge Cluster for High Concurrency Streaming: SRS边缘集群,支持高并发流媒体播放,减轻源站压力,分离源站关键业务,在SLB下自动扩容和更新。
 - SRS Origin Cluster for a Large Number of Streams: SRS源站集群,支持大规模的推流,流的自动发现,以及流的灾备。
 - SRS Cluster Update, Rollback, Gray Release with Zero Downtime: 如何在不中断服务的前提下,实现SRS集群的更新、回滚和灰度发布。
- SRS Cluster Rolling Update: 在平滑退出基础上的滚动更新,集群更新的基础机制。
 - SRS Cluster Rolling Back: 在平滑退出基础上的发布回滚,发布遇到问题首先考虑回滚。
 - SRS Cluster Canary Release: 金丝雀升级,可精确控制的流量控制和回滚。
 
 - Useful Tips: 补充的实用话题和场景
- Create K8S Cluster in ACK: 在阿里云ACK创建你的K8S集群。
 - Publish Demo Streams to SRS: 推送SRS的演示流,可直接推源站,也可以推边缘集群。
 - Cleanup For DVR/HLS Temporary Files: 定期,比如每天凌晨1点,清理临时文件。
 - Use One SLB and EIP for All Streaming Service: 使用一个SLB(EIP)对外提供RTMP、HTTP-FLV、HLS等服务。
 - Build SRS Origin Cluster as Deployment: 除了以StatefulSet有状态应用方式部署Origin Cluster,我们还可以选择Deployment无状态应用方式。
 - Managing Compute Resources for Containers: 资源的申请和限制,以及如何调度和限制如何生效。
 - Auto Reload by Inotify: SRS侦听ConfigMap的变更,并支持自动reload。
 
 
Deploy to Cloud Platforms
SRS提供了一系列的模版项目,可以快速部署到云平台K8s:
Quick Start
假设你有一个k8s集群(如果没有可以从Create K8S Cluster in ACK轻松创建),执行下面的命令应该是成功的:
kubectl cluster-info
基于K8S,我们可以快速构建一个流媒体服务,尽管只有一个SRS源站。
在这个场景下,对比K8S和传统部署方式的差异:
| 对比项 | ECS | K8S | 说明 | 
|---|---|---|---|
| 资源 | 手动 | 自动 | 部署时,传统方式需要手动购买相关资源, K8S自动购买需要的资源比如ECS、SLB和EIP等  | 
| 部署 | 安装包 | 镜像 | Docker镜像可回滚,开发和生产环 境一致,可Cache, 高效率和高密度,高可移植性,资源隔离可预测程序性能  | 
| 看门狗 | 手动 | 自动 | SRS异常退出由看门狗重新拉起,非K8S需要手动安装, K8S自动管理和拉起服务  | 
| 迁移 | 手动 | 自动 | ECS更换时,非K8S需要手动申请,修改SLB,安装服务, K8S自动迁移服务,更新SLB配置监听和保活等  | 
实现该场景的架构图如下所示:

Step 1: 创建一个无状态应用k8s deployment,运行SRS源站服务器:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: srs-deploy
  labels:
    app: srs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: srs
  template:
    metadata:
      labels:
        app: srs
    spec:
      containers:
      - name: srs
        image: ossrs/srs:3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 1935
        - containerPort: 1985
        - containerPort: 8080
EOF
Step 2: 创建一个服务k8s service,自动创建SLB和EIP,对外提供流媒体服务:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: srs-origin-service
spec:
  type: LoadBalancer
  selector:
    app: srs
  ports:
  - name: srs-origin-service-1935-1935
    port: 1935
    protocol: TCP
    targetPort: 1935
  - name: srs-origin-service-1985-1985
    port: 1985
    protocol: TCP
    targetPort: 1985
  - name: srs-origin-service-8080-8080
    port: 8080
    protocol: TCP
    targetPort: 8080
EOF
Note: 如果是自动创建SLB和EIP,那么HLS和RTMP/HTTP-FLV的IP是不一样的,你可以选择手动指定SLB,这两个服务可以用同一个SLB,参考Use One SLB and EIP for All Streaming Service。
Step 3: 大功告成。查询服务的EIP地址,你就可以推拉流了。
执行命令kubectl get svc/srs-origin-service,可以查看服务的ExternalIP,也就是公网IP:
NAME          TYPE           CLUSTER-IP      EXTERNAL-IP
srs-origin-service   LoadBalancer   172.21.12.131   28.170.32.118
例子中的IP是28.170.32.118,就可以推流到这个公网IP地址,也可以从这个地址播放:
- Publish RTMP to 
rtmp://28.170.32.118/live/livestreamor Publish Demo Streams to SRS. - Play RTMP from rtmp://28.170.32.118/live/livestream
 - Play HTTP-FLV from http://28.170.32.118:8080/live/livestream.flv
 - Play HLS from http://28.170.32.118:8080/live/livestream.m3u8
 

SRS Shares Volume with Nginx
本章描述了基于K8S,SRS如何和Nginx配合提供更丰富的HTTP服务。
我们可以用SRS分发RTMP和HTTP-FLV等流媒体,并生成HLS切片到共享Volume,然后Nginx读取Volume并分发HLS。当然SRS也可以直接分发HLS切片,之所以用Nginx,这个场景可以用在:
- 已经有Nginx和Web服务,SRS无法使用80端口,可以选择共享Volume方式给Nginx,当然也可以配置Nginx代理特定的URL。
 - SRS不支持HTTPS。Nginx可以支持HTTPS,配置Nginx支持证书后,可以将SRS生成的HLS,通过HTTPS分发。
 - SRS不支持HLS的鉴权。Nginx或其他Web框架,可以在用户访问HLS文件时,实现鉴权的逻辑。
 - SRS只支持HTTP/1.1部分协议。Nginx有更完善的HTTP功能,比如HTTP/2,完整的HTTP协议支持。
 
在这个场景下,对比K8S和传统部署方式的差异:
| 对比项 | ECS | K8S | 说明 | 
|---|---|---|---|
| 资源 | 手动 | 自动 | 部署时,传统方式需要手动购买相关资源, K8S自动购买需要的资源比如ECS、SLB和EIP等  | 
| 部署 | 安装包 | 镜像 | Docker镜像可回滚,开发和生产环境一致,可Cache, 高效率和高密度,高可移植性,资源隔离可预测程序性能  | 
| 看门狗 | 手动 | 自动 | SRS异常退出由看门狗重新拉起,非K8S需要手动安装, K8S自动管理和拉起服务  | 
| 迁移 | 手动 | 自动 | ECS更换时,非K8S需要手动申请,修改SLB,安装服务, K8S自动迁移服务,更新SLB配置监听和保活等  | 
实现该场景的架构图如下所示:

Step 1: 创建一个无状态应用k8s deployment,运行SRS和Nginx,HLS写入共享Volume:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: srs-deploy
  labels:
    app: srs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: srs
  template:
    metadata:
      labels:
        app: srs
    spec:
      volumes:
      - name: cache-volume
        emptyDir: {}
      containers:
      - name: srs
        image: ossrs/srs:3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 1935
        - containerPort: 1985
        - containerPort: 8080
        volumeMounts:
        - name: cache-volume
          mountPath: /usr/local/srs/objs/nginx/html
          readOnly: false
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: cache-volume
          mountPath: /usr/share/nginx/html
          readOnly: true
      - name: srs-cp-files
        image: ossrs/srs:3
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: cache-volume
          mountPath: /tmp/html
          readOnly: false
        command: ["/bin/sh"]
        args:
        - "-c"
        - >
          if [[ ! -f /tmp/html/index.html ]]; then
            cp -R ./objs/nginx/html/* /tmp/html
          fi &&
          sleep infinity
EOF
Note: Nginx的默认目录是
/usr/share/nginx/html,若不是请改成你自己的目录。
Note: SRS和Nginx挂载了emptyDir Volume共享HLS文件,默认是空目录,会随着Pod的销毁而清空。
Note: 由于共享目录是空目录,我们启动了一个
srs-cp-files的container,拷贝SRS默认的文件,参考#1603.
Step 2: 创建一个服务k8s service,使用SLB对外提供流媒体服务:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: srs-origin-service
spec:
  type: LoadBalancer
  selector:
    app: srs
  ports:
  - name: srs-origin-service-80-80
    port: 80
    protocol: TCP
    targetPort: 80
  - name: srs-origin-service-1935-1935
    port: 1935
    protocol: TCP
    targetPort: 1935
  - name: srs-origin-service-1985-1985
    port: 1985
    protocol: TCP
    targetPort: 1985
  - name: srs-origin-service-8080-8080
    port: 8080
    protocol: TCP
    targetPort: 8080
EOF
Note: 我们通过Service暴露端口,对外提供服务,其中RTMP(1935)/FLV(8080)/API(1985)由SRS提供服务,HLS(80)由Nginx提供服务。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Step 3: 大功告成。你可以推拉流了,其中HLS流可以从SRS(8080)播放,也可以从Nginx(80)播放:
- Publish RTMP to 
rtmp://28.170.32.118/live/livestreamor Publish Demo Streams to SRS. - Play RTMP from rtmp://28.170.32.118/live/livestream
 - Play HTTP-FLV from http://28.170.32.118:8080/live/livestream.flv
 - Play HLS from http://28.170.32.118:8080/live/livestream.m3u8
 - Play HLS from http://28.170.32.118/live/livestream.m3u8
 
Note: 请将上面的EIP换成你自己的,可用命令
kubectl get svc/srs-origin-service查看你的EIP。
SRS Edge Cluster for High Concurrency Streaming
本章描述了基于K8S,如何构建Edge Cluster实现高并发流媒体播放。
Edge Cluster实现了合并回源,对于某一路流,不管有多少客户端播放,Edge Server都只会从Origin Server取一路流,这样可以通过扩展Edge Cluster来增加支持的播放能力,也就是CDN网络具备的重要能力:高并发。
Note: Edge Cluster根据客户端播放的协议不同,可以分为RTMP Edge Cluster或HTTP-FLV Edge Cluster,详细请参考相关Wiki。
对于自建源站,没有那么多播放量,为何不建议使用SRS单源站直接提供服务,而要用Edge Cluster呢?主要场景分析如下:
- 防止Origin过载,即使推流非常少而且播放的流也不多,比如自建源站后使用CDN回源,在多家CDN回源时,也可能一个CDN一条流会有多个回源连接。使用Edge能保护Origin不因为回源造成Origin问题,最多就是某些Edge被回源打挂。
 - 可以使用多个Edge Cluster(只需要再加srs-edge-service就可以),对外用不同的SLB暴露,可以针对每个SLB限流,防止CDN之间互相干扰。这样能保证某些CDN是可用的,而不是Origin挂了后所有CDN都不可用。
 - 分离Origin关键业务,将下行流媒体分发业务交给Edge Cluster,Origin可以做切片、DVR、鉴权等关键业务,避免业务之间互相干扰。
 
在这个场景下,对比K8S和传统部署方式的差异:
| 对比项 | ECS | K8S | 说明 | 
|---|---|---|---|
| 资源 | 手动 | 自动 | 部署时,传统方式需要手动购买相关资源, K8S自动购买需要的资源比如ECS、SLB和EIP等  | 
| 部署 | 安装包 | 镜像 | Docker镜像可回滚,开发和生产环境一致,可Cache, 高效率和高密度,高可移植性,资源隔离可预测程序性能  | 
| 看门狗 | 手动 | 自动 | SRS异常退出由看门狗重新拉起,非K8S需要手动安装, K8S自动管理和拉起服务  | 
| 迁移 | 手动 | 自动 | ECS更换时,非K8S需要手动申请,修改SLB,安装服务, K8S自动迁移服务,更新SLB配置监听和保活等  | 
| 配置 | 文件 | Volume | ECS需要手动管理配置;K8S配置在ConfigMap, 通过Volume挂载为配置文件,扩容时不用变更  |