-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
v4_CN_K8S
流媒体服务和流媒体服务器的关键差异是什么?高效的运维能力是其中极其关键的差异之一,云计算+Docker+K8S让开源项目也能拥有这种能力,让每个人都能具备互联网流媒体服务能力,正如:旧时王谢堂前燕,飞入寻常百姓家!
为何要用k8s部署SRS集群?
- Simple(简单有效): 这玩意儿真的非常简单、高效便捷、直击服务部署和维护的痛点。羽扇纶巾,谈笑间强撸灰飞湮灭,不信一起来看QuickStart.
- Declarative deployment(声明式部署):只需要根据业务量声明需要多少个SRS,自动配置和更新SLB,不用启动服务和看门狗,也不用机器故障时一顿操作猛如虎的迁移和更新。
- Expand easily(扩容很容易): K8S可以自动扩容底层基础设施,例如可通过ESS自动,而业务集群(如SRS Edge)通过修改Pod数量(或根据策略)实现扩容。
- Rolling Update(滚动式更新): K8S可以在不中断服务的前提下,实现服务的更新、回滚和灰度发布,这是提供稳定可靠高效服务的大杀器,总不能每次更新就被用户投诉吧?总不能每次都半夜三更提心吊胆吧?
- XXX: Coming soon...
本文介绍了,在不同的业务场景下,如何使用ACK(AlibabaCloud Container Service for Kubernetes)构建SRS集群。
- 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集群的更新、回滚和灰度发布。
-
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无状态应用方式。
- XXX: Coming soon...
假设你有一个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/livestream
or 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
本章描述了基于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/livestream
or 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。
本章描述了基于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挂载为配置文件,扩容时不用变更 |
扩容 | 手动 | 自动 | 需要新开进程时,ECS需要申请部署和配置, K8S只需要修改Replicas数目即可(也可自动扩容) |
发现 | 手动 | 自动 | Origin变更IP时,ECS需要手动修改配置, K8S自动通知边缘和自动发现 |
SLB | 手动 | 自动 | 新增Edge时,ECS需要手动更新SLB配置, K8S自动更新SLB配置 |
实现该场景的架构图如下所示:
Step 1: 创建SRS和Nginx源站应用和服务。
-
srs-origin-deploy
: 创建一个无状态应用k8s deployment,运行SRS Origin Server和Nginx,HLS写入共享Volume: -
srs-origin-service
: 创建一个服务k8s service,基于ClusterIP提供Origin服务,供内部Edge Server调用。 -
srs-http-service
: 创建一个服务k8s service,基于SLB提供HTTP服务,Nginx对外提供HLS服务。
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-origin-deploy
labels:
app: srs-origin
spec:
replicas: 1
selector:
matchLabels:
app: srs-origin
template:
metadata:
labels:
app: srs-origin
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
---
apiVersion: v1
kind: Service
metadata:
name: srs-origin-service
spec:
type: ClusterIP
selector:
app: srs-origin
ports:
- name: srs-origin-service-1935-1935
port: 1935
protocol: TCP
targetPort: 1935
---
apiVersion: v1
kind: Service
metadata:
name: srs-http-service
spec:
type: LoadBalancer
selector:
app: srs-origin
ports:
- name: srs-http-service-80-80
port: 80
protocol: TCP
targetPort: 80
- name: srs-http-service-1985-1985
port: 1985
protocol: TCP
targetPort: 1985
EOF
Note: Origin Server在集群内部提供流媒体源站服务,他的服务类型为ClusterIP,内部域名为
srs-origin-service
,Edge Server会通过该域名连接到Origin Server。
Note: SRS和Nginx挂载了emptyDir Volume共享HLS文件,默认是空目录,会随着Pod的销毁而清空。
Note: 由于共享目录是空目录,我们启动了一个
srs-cp-files
的container,拷贝SRS默认的文件,参考#1603.
Note: 服务
srs-http-service
暴露的是Nginx(80)端口,对外提供HLS服务;以及SRS(1985)端口,对外提供API服务。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Step 2: 创建SRS边缘配置、应用和服务。
-
srs-edge-config
: 创建一个配置k8s ConfigMap,存储了SRS Edge Server使用的配置文件。 -
srs-edge-deploy
: 创建一个无状态应用k8s deployment,运行多个SRS Edge Server。 -
srs-edge-service
: 创建一个服务k8s service基于SLB对外提供流媒体服务。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: srs-edge-config
data:
srs.conf: |-
listen 1935;
max_connections 1000;
daemon off;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
cluster {
mode remote;
origin srs-origin-service;
}
http_remux {
enabled on;
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-edge-deploy
labels:
app: srs-edge
spec:
replicas: 3
selector:
matchLabels:
app: srs-edge
template:
metadata:
labels:
app: srs-edge
spec:
volumes:
- name: config-volume
configMap:
name: srs-edge-config
containers:
- name: srs
image: ossrs/srs:3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 1935
- containerPort: 1985
- containerPort: 8080
volumeMounts:
- name: config-volume
mountPath: /usr/local/srs/conf
---
apiVersion: v1
kind: Service
metadata:
name: srs-edge-service
spec:
type: LoadBalancer
selector:
app: srs-edge
ports:
- name: srs-edge-service-1935-1935
port: 1935
protocol: TCP
targetPort: 1935
- name: srs-edge-service-8080-8080
port: 8080
protocol: TCP
targetPort: 8080
EOF
Note: 我们将Edge Server的配置存储在ConfigMap中,名称为
srs-edge-config
,然后将ConfigMap挂载为配置文件/usr/local/srs/conf/srs.conf
,其中srs.conf
是在ConfigMap的配置项名称。
Note: Edge Server读取配置文件,通过Service注册的内部域名
srs-origin-service
,连接到Origin Server。
Note: 服务
srs-edge-service
暴露的是SRS的1935端口,对外提供RTMP服务;以及SRS的8080端口,对外提供HTTP-FLV服务。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Step 3: 大功告成。你可以推拉流了,其中HLS流可以从Nginx(80)播放,RTMP和HTTP-FLV从SRS播放:
- Publish RTMP to
rtmp://28.170.32.118/live/livestream
or 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/live/livestream.m3u8
Note: 请将上面的EIP换成你自己的,可用命令
kubectl get svc/srs-http-service
或kubectl get svc/srs-edge-service
查看你的EIP。
Note: 如果是自动创建SLB和EIP,那么HLS和RTMP/HTTP-FLV的IP是不一样的,你可以选择手动指定SLB,这两个服务可以用同一个SLB,参考Use One SLB and EIP for All Streaming Service。
本章描述了基于K8S,如何构建Origin Cluster支持超多推流场景。
Origin Cluster通过配置其他源站的信息,在本源站没有流时查询到流的位置,通过RTMP 302定向到指定源站,具体原理可以参考#464。主要应用场景如下:
- 源站灾备:即使流比较少,也可以用两个源站,这样可以将流分散到不同的源站,避免源站出现问题时影响所有的流。
- 海量推流:单源站可以支持1000到3000路流,高码率的流支持的路数更少,有DVR和HLS时支持的路更少,源站集群有多个源站同时接收推流,可以支持10k~100k推流,参考规格。
- 复杂源站业务:源站除了支持推流和拉流,还有重要的功能是DVR、转码、转HLS,DVR和HLS涉及磁盘,转码涉及CPU,都是容易发生瓶颈的资源依赖,源站集群扩展能力更强。
在这个场景下,对比K8S和传统部署方式的差异:
对比项 | ECS | K8S | 说明 |
---|---|---|---|
资源 | 手动 | 自动 | 部署时,传统方式需要手动购买相关资源, K8S自动购买需要的资源比如ECS、SLB和EIP等 |
部署 | 安装包 | 镜像 | Docker镜像可回滚,开发和生产环境一致,可Cache, 高效率和高密度,高可移植性,资源隔离可预测程序性能 |
看门狗 | 手动 | 自动 | SRS异常退出由看门狗重新拉起,非K8S需要手动安装, K8S自动管理和拉起服务 |
迁移 | 手动 | 自动 | ECS更换时,非K8S需要手动申请,修改SLB,安装服务, K8S自动迁移服务,更新SLB配置监听和保活等 |
配置 | 文件 | Volume | ECS需要手动管理配置;K8S配置在ConfigMap, 通过Volume挂载为配置文件,扩容时源站手动更新自动推送, 边缘扩容自动更新 |
扩容 | 手动 | 自动 | 需要新开进程时,ECS需要申请部署和配置, K8S只需要修改Replicas数目即可(也可自动扩容) |
发现 | 手动 | 自动 | Origin变更IP时,ECS需要手动修改配置, K8S在迁移源站Pod时会保持,或自动更新 |
SLB | 手动 | 自动 | 新增Origin时,ECS需要手动安装和更新配置, K8S自动安装,手动更新但自动推送配置 |
存储 | 手动 | 自动 | 扩容存储时,ECS需要手动安装和更新, K8S会自动更新,不影响业务 |
实现该场景的架构图如下所示:
Step 1: 由于SRS和Nginx不在一个Pod可能也不在一个Node,需要创建依赖的PV(Persistent Volume)持久化卷,可购买NAS例如:
- 驱动类型(PV driver):
alicloud/nas
- 挂载点(PV server),可在控制台创建、查看和复制:
1abb5492f7-ubq80.cn-beijing.nas.aliyuncs.com
- NFS版本(PV vers):
3
在NAS基础上可以创建PV,以及PVC:
-
pv-nas
,从NAS存储创建的PV,支持多写和多读,Pod不使用存储后会回收,也就是删除这些数据。 -
pvc-nas
,SRS和Nginx源站使用的PVC,具有读写权限。读取SRS的静态文件和HLS并分发。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nas
labels:
pv: nfs-pv
spec:
capacity:
storage: 100Gi
storageClassName: nas
accessModes:
- ReadWriteMany
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
flexVolume:
driver: "alicloud/nas"
options:
server: "1abb5492f7-ubq80.cn-beijing.nas.aliyuncs.com"
path: "/k8s"
vers: "3"
options: "nolock,tcp,noresvport"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nas
spec:
accessModes:
- ReadWriteMany
storageClassName: nas
resources:
requests:
storage: 100Gi
selector:
matchLabels:
pv: nfs-pv
EOF
Note: 请将上面的挂载点(PV server)替换成你的。
Note: SRS和Nginx使用
pvc-nas
描述自己的存储需求,K8S会绑定和分配存储pv-nas
。
Step 2: 创建SRS源站集群和Nginx源站应用和服务。
-
srs-origin-config
: 创建一个配置k8s ConfigMap,存储了SRS Origin Server使用的配置文件。 -
socs
: 创建一个Headless服务k8s service,基于Headless Service提供Origin服务,每个Origin都有自己的服务地址,例如srs-origin-0.socs
,供内部Edge Server调用。 -
srs-origin
: 创建一个有状态应用k8s StatefulSet,运行SRS Origin Cluster,HLS写入共享存储PV。 -
srs-api-service
: 创建一个服务k8s service,基于SLB提供HTTP服务,SRS第一个源站提供API服务,标签为statefulset.kubernetes.io/pod-name: srs-origin-0
。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: srs-origin-config
data:
srs.conf: |-
listen 1935;
max_connections 1000;
daemon off;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
cluster {
origin_cluster on;
coworkers srs-origin-0.socs srs-origin-1.socs srs-origin-2.socs;
}
http_remux {
enabled on;
}
hls {
enabled on;
}
}
---
apiVersion: v1
kind: Service
metadata:
name: socs
spec:
clusterIP: None
selector:
app: srs-origin
ports:
- name: socs-1935-1935
port: 1935
protocol: TCP
targetPort: 1935
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: srs-origin
labels:
app: srs-origin
spec:
serviceName: "socs"
replicas: 3
selector:
matchLabels:
app: srs-origin
template:
metadata:
labels:
app: srs-origin
spec:
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: pvc-nas
- name: config-volume
configMap:
name: srs-origin-config
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: config-volume
mountPath: /usr/local/srs/conf
---
apiVersion: v1
kind: Service
metadata:
name: srs-api-service
spec:
type: LoadBalancer
selector:
statefulset.kubernetes.io/pod-name: srs-origin-0
ports:
- name: srs-api-service-1985-1985
port: 1985
protocol: TCP
targetPort: 1985
EOF
Note: 配置存储在ConfigMap中
srs-origin-config
,会被以Volume方式挂载成配置文件/usr/local/srs/conf/srs.conf
。
Remark: 源站集群配置,需要配置各个源站的服务地址也就是域名。假设SRS源站有状态服务
srs-origin
配置的Replicas为2,则会生成两个源站srs-origin-0.socs
和srs-origin-1.socs
,若新增了源站比如Replicas为3,则需要在配置中加上srs-origin-2.socs
。
Note: Origin Server在集群内部提供流媒体源站服务,以有状态服务方式提供名字为
socs
,每个源站会自动分配内部域名,内部域名为srs-origin-0.socs
和srs-origin-1.socs
,Edge Server会配置这些域名连接到Origin Server。
Note: 源站对外提供API服务
srs-api-service
,我们选择第一个源站对外提供API服务,实际上源站集群需要改进这点,参考#1607。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
-
nginx-origin-deploy
: 创建一个无状态应用k8s deployment,运行Nginx,将SRS静态文件写入PV,从共享存储PV读取HLS和静态文件。 -
srs-http-service
: 创建一个服务k8s service,基于SLB提供HTTP服务,Nginx对外提供HLS服务。
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-origin-deploy
labels:
app: nginx-origin
spec:
replicas: 1
selector:
matchLabels:
app: nginx-origin
template:
metadata:
labels:
app: nginx-origin
spec:
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: pvc-nas
containers:
- 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
---
apiVersion: v1
kind: Service
metadata:
name: srs-http-service
spec:
type: LoadBalancer
selector:
app: nginx-origin
ports:
- name: nginx-origin-service-80-80
port: 80
protocol: TCP
targetPort: 80
EOF
Note: 由于共享目录是空目录,我们启动了一个
srs-cp-files
的container,拷贝SRS默认的文件,参考#1603.
Note: Nginx通过Shared Volume(PV)读取SRS Origin生成的切片,对外提供HLS服务。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Step 3: 创建SRS边缘配置、应用和服务。
-
srs-edge-config
: 创建一个配置k8s ConfigMap,存储了SRS Edge Server使用的配置文件。 -
srs-edge-deploy
: 创建一个无状态应用k8s deployment,运行多个SRS Edge Server。 -
srs-edge-service
: 创建一个服务k8s service基于SLB对外提供流媒体服务。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: srs-edge-config
data:
srs.conf: |-
listen 1935;
max_connections 1000;
daemon off;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
cluster {
mode remote;
origin srs-origin-0.socs srs-origin-1.socs srs-origin2.socs;
}
http_remux {
enabled on;
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-edge-deploy
labels:
app: srs-edge
spec:
replicas: 4
selector:
matchLabels:
app: srs-edge
template:
metadata:
labels:
app: srs-edge
spec:
volumes:
- name: config-volume
configMap:
name: srs-edge-config
containers:
- name: srs
image: ossrs/srs:3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 1935
- containerPort: 1985
- containerPort: 8080
volumeMounts:
- name: config-volume
mountPath: /usr/local/srs/conf
---
apiVersion: v1
kind: Service
metadata:
name: srs-edge-service
spec:
type: LoadBalancer
selector:
app: srs-edge
ports:
- name: srs-edge-service-1935-1935
port: 1935
protocol: TCP
targetPort: 1935
- name: srs-edge-service-8080-8080
port: 8080
protocol: TCP
targetPort: 8080
EOF
Remark: 假设SRS源站有状态服务
srs-origin
配置的Replicas为2,则会生成两个源站srs-origin-0.socs
和srs-origin-1.socs
,若新增了源站比如Replicas为3,则需要在配置中加上srs-origin-2.socs
。
Note: Edge Server的配置中,通过源站在Headless Service注册的内部域名
srs-origin-0.socs
等等,连接到Origin Server。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Step 4: 大功告成。你可以推拉流了,其中HLS流可以从Nginx(80)播放,RTMP和HTTP-FLV从SRS播放:
- Publish RTMP to
rtmp://28.170.32.118/live/livestream
or 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/live/livestream.m3u8
Note: 请将上面的EIP换成你自己的,可用命令
kubectl get svc/srs-http-service
或kubectl get svc/srs-edge-service
查看你的EIP。
Note: 如果是自动创建SLB和EIP,那么HLS和RTMP/HTTP-FLV的IP是不一样的,你可以选择手动指定SLB,这两个服务可以用同一个SLB,参考Use One SLB and EIP for All Streaming Service。
这里我们选择的是有状态集群方式,也可以选择以无状态应用(Deployment)方式部署源站,参考Build SRS Origin Cluster as Deployment。
Coming soon...
本章补充了一些比较实用的话题,以及前面章节用到的一些工具和场景。
- Create K8S Cluster in ACK: 在阿里云ACK创建你的K8S集群,我们基于ACK构建流媒体服务。
- Publish Demo Streams to SRS: 推送SRS的演示流,可直接推源站,也可以推边缘集群。
- Cleanup For DVR/HLS Temporary Files: 定期清理临时文件,比如每天凌晨1点,删除3天前的临时文件。
- 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无状态应用方式。
Step 1: [可选] 创建k8s集群用的专有网络VPC和交换机。
- 专有网络,名称:
srs-k8s-vpc
,会在这个VPC创建网络资源。 - 交换机,名称:
srs-k8s-node
,创建的Node(ECS)会在这个交换机的网段中。
Step 2: [可选] 创建管理机器的密钥对KeyPair。
- 密钥对名称:
srs-k8s-key
,可以设置ssh配置免密码登陆。
Step 3: [可选] 购买NAS,创建源站集群使用的PV(Persistent Volume)持久化卷,可在NAS控制台创建文件系统
。
- 文件系统类型:可选择
通用型
,或者要求更快的速度可选择极速型
。 - 区域:请选择
华北3(张家口)
,千万注意别选错了,要和ACK集群在同一VPC中。 - 协议类型:选择
NFS
。 - VPC网络:请选择
srs-k8s-vpc
。 - 交换机:请选择
srs-k8s-node
。
Step 4: 进入ACK控制台,新建K8S托管集群。
- 集群名称:
srs
- 地域:
华北3(张家口)
选择专有网络和Node(ECS)的交换机,也可以点新建创建。
选择Worker实例的类型和规格、创建的台数(默认3台)、镜像、密钥对。把相关组件都选择上,尤其是ApiServer公网访问。
点创建集群
,就可以成功创建K8S集群了。
Step 5: 使用kubectl管理集群,进入ACK,点击集群查看基本信息。
配置好kubectl后,执行下面的命令应该是成功的:
kubectl cluster-info
接下来,就可以创建SRS集群了,参考QuickStart.
为了演示用,若存在源站服务srs-origin-service
,也可以创建一个无状态应用k8s deployment,推流到SRS源站:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-demo-deploy
labels:
app: srs-demo
spec:
replicas: 1
selector:
matchLabels:
app: srs-demo
template:
metadata:
labels:
app: srs-demo
spec:
containers:
- name: encoder
image: ossrs/srs:encoder
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args:
- "-c"
- >
while true; do
ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
-c copy -f flv rtmp://srs-origin-service/live/livestream;
sleep 3;
done
EOF
Note: 可以创建多个应用推多个流,记得将推流域名改成你的嗯源站服务的名称。
集群中若已经有Edge(边缘)服务srs-edge-service
,也可以创建无状态应用k8s deployment,推流到SRS边缘:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-demo-deploy
labels:
app: srs-demo
spec:
replicas: 1
selector:
matchLabels:
app: srs-demo
template:
metadata:
labels:
app: srs-demo
spec:
containers:
- name: livestream
image: ossrs/srs:encoder
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args:
- "-c"
- >
while true; do
ffmpeg -re -i ./doc/source.200kbps.768x320.flv -c copy \
-f flv rtmp://srs-edge-service/live/livestream && continue;
sleep 3;
done
- name: avatar
image: ossrs/srs:encoder
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args:
- "-c"
- >
while true; do
ffmpeg -re -i ./doc/source.200kbps.768x320.flv -c copy \
-f flv rtmp://srs-edge-service/live/avatar && continue;
sleep 3;
done
EOF
Note: 若存在源站服务,可以直接推源站,参考Publish Demo Streams to SRS。
可以开启一个K8S CronJob定期清理存储的临时文件:
- 若开启了HLS,推流结束后最后几个切片还会继续存在,当然也可以开启
hls_dispose
清理。 - SRS重启或Crash后,可能有临时文件不会被清理,会不断累积。
- 清理时注意不要删除有用的文件,比如DVR正式文件,或console等静态文件。
建议将清理的目标设置为:
- 只清理3天前的,3天之内的文件可以暂时不用管。
- 扩展名为
*.ts*
或*.m3u8*
或*.flv.tmp
或*.mp4.tmp
文件。 - 清理空目录,空目录一般不影响正常功能,清理不会出现问题。
- 每天凌晨1点运行清理任务,时间是按K8S集群时间,一般国内是北京时间。
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cleanup
spec:
schedule: "15 1 * * *"
jobTemplate:
spec:
template:
spec:
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: pvc-nas
containers:
- name: cleanup
image: centos:7
imagePullPolicy: IfNotPresent
volumeMounts:
- name: cache-volume
mountPath: /tmp/html
readOnly: false
args:
- /bin/sh
- -c
- >
find /tmp/html -mtime +3 -name *.ts* -print -delete &&
find /tmp/html -mtime +3 -name *.m3u8* -print -delete &&
find /tmp/html -mtime +3 -name *.flv.tmp -print -delete &&
find /tmp/html -mtime +3 -name *.mp4.tmp -print -delete &&
find /tmp/html -type d -empty -print -delete &&
echo "Done"
restartPolicy: Never
EOF
Remark: K8S的Cron表达式没有秒,格式是
分 时 日 月 星期
,比如15 1 * * *
表示每天01:15
执行。另外,一般
Remark: 注意find命令的
-nmin
和-mtime
时间限制,是和-name
绑定在一起的,所以每种文件用一个命令删除。
目前ACK还不支持Job完成后自动清理,ttlSecondsAfterFinished,完成后的Pod还会留在系统。 一个可选的办法,是启动一个Deployment后,用脚本循环执行,执行一次后等待1天:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: cleanup
labels:
app: cleanup
spec:
replicas: 1
selector:
matchLabels:
app: cleanup
template:
metadata:
labels:
app: cleanup
spec:
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: pvc-nas
containers:
- name: cleanup
image: centos:7
imagePullPolicy: IfNotPresent
volumeMounts:
- name: cache-volume
mountPath: /tmp/html
readOnly: false
args:
- /bin/sh
- -c
- >
while true; do
find /tmp/html -mtime +3 -name *.ts* -print -delete &&
find /tmp/html -mtime +3 -name *.m3u8* -print -delete &&
find /tmp/html -mtime +3 -name *.flv.tmp -print -delete &&
find /tmp/html -mtime +3 -name *.mp4.tmp -print -delete &&
find /tmp/html -type d -empty -print -delete &&
echo "[`date`] Cleanup done";
sleep 86400;
done
EOF
Note: 一天就是86400秒,注意避开业务高峰期执行。
在例子中,我们默认配置的是自动创建SLB和EIP,这会导致对外提供的EIP是不一样的,比如RTMP/HTTP-FLV是一个EIP,HLS是另外一个IP。
为了使用一个EIP对外提供服务,我们必须在创建Service时指定SLB,这需要一个已经存在的内网SLB(绑定了EIP),你可以从Aliyun组合购买,比如:
然后可以在创建服务时,通过指定Service的metadata.annotations
,指定你自己购买的内网SLB:
metadata:
annotations:
service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet
service.beta.kubernetes.io/alicloud-loadbalancer-force-override-listeners: "true"
service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-2zetmjpao868s9yzvr5ld
例如,我们以Quick Start为例,可以修改Service如下:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet
service.beta.kubernetes.io/alicloud-loadbalancer-force-override-listeners: "true"
service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-2zetmjpao868s9yzvr5ld
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的VPC,要和K8S集群在一个VPC下面。
Note:关于SLB的更多配置,比如保活、计费、证书等等,可以参考SLB for K8S Service。
在源站集群部署中,可以选择StatefulSet(有状态应用)方式部署,参考:SRS Origin Cluster for a Large Number of Streams。 当然也可以选择Deployment(无状态应用)方式部署,这两种方式的差异参考#464。
对比项 | 无状态源站集群 | 有状态源站集群 |
---|---|---|
部署 | 容易,源站只需要创建一个StatefulSet和Service | 复杂,需要几个源站就需要创建几个应用 |
规模 | <30节点,需要将节点写入源站和边缘配置 | <10节点,需要将节点写入源站和边缘配置 |
更新 | 简单,直接修改镜像更新Pod | 复杂,需要再创建源站同等数量的应用,几个源站就几个应用 |
灰度 | 不支持,更新时断流有重推 | 支持灰度,可手动灰度指定的机器, 更新时断流有重推 |
- 新增源站时,都需要修改源站和边缘的配置,修改ConfigMap。
- 灰度时,可以手动更改某些源站的镜像版本,出现问题手动回滚,不适合较多机器的情况。
- 更新和回滚时,都会造成源站重启,由于有边缘作为代理,所以用户不会中断,但边缘会有重试,用户可能会有感知。
Note: 关于Rolling Update,参考SRS Cluster Update, Rollback, Gray Release with Zero Downtime。
我们以部署三个源站为例,全部以无状态应用(Deployment)方式部署:
源站 | Deployment | Service | 域名 |
---|---|---|---|
Origin Server 0 | srs-origin-0-deploy | srs-origin-0-socs | srs-origin-0-socs |
Origin Server 1 | srs-origin-1-deploy | srs-origin-1-socs | srs-origin-1-socs |
Origin Server 2 | srs-origin-2-deploy | srs-origin-2-socs | srs-origin-2-socs |
- 配置
srs-origin-config
,三个源站的配置都是一样的,都是Service的地址例如srs-origin-0-socs
。新增源站时需要更新。 - 配置
srs-edge-config
,边缘集群的配置项也是一样的,都是Service的地址例如srs-origin-0-socs
。新增源站时需要更新。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: srs-origin-config
data:
srs.conf: |-
listen 1935;
max_connections 1000;
daemon off;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
cluster {
origin_cluster on;
coworkers srs-origin-0-socs srs-origin-1-socs srs-origin-2-socs;
}
http_remux {
enabled on;
}
hls {
enabled on;
}
}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: srs-edge-config
data:
srs.conf: |-
listen 1935;
max_connections 1000;
daemon off;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
cluster {
mode remote;
origin srs-origin-0-socs srs-origin-1-socs srs-origin-2-socs;
}
http_remux {
enabled on;
}
}
EOF
第一个源站,服务地址为srs-origin-0-socs
:
- Deployment应用为
srs-origin-0-deploy
,注意Replicas应该为1。 - Service服务为
srs-origin-0-socs
,只挂了一个应用srs-origin-0-deploy
。
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs-origin-0-deploy
labels:
app: srs-origin-0
spec:
replicas: 1
selector:
matchLabels:
app: srs-origin-0
template:
metadata:
labels:
app: srs-origin-0
spec:
volumes:
- name: config-volume
configMap:
name: srs-origin-config
containers:
- name: srs
image: ossrs/srs:3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 1935
- containerPort: 1985
- containerPort: 8080
volumeMounts:
- name: config-volume
mountPath: /usr/local/srs/conf
---
apiVersion: v1
kind: Service
metadata:
name: srs-origin-0-socs
spec:
type: ClusterIP
selector:
app: srs-origin-0
ports:
- name: srs-origin-0-socs-service-1935-1935
port: 1935
protocol: TCP
targetPort: 1935
EOF
Remark: 按照上面的例子,建立第二个源站,服务地址为
srs-origin-1-socs
,Deployment应用为srs-origin-1-deploy
,Service服务为srs-origin-1-socs
。
Remark: 按照上面的例子,建立第三个源站,服务地址为
srs-origin-2-socs
,Deployment应用为srs-origin-2-deploy
,Service服务为srs-origin-2-socs
。
-
srs-api-service
: 创建一个服务k8s service,基于SLB提供HTTP服务,SRS第一个源站提供API服务,标签为srs-origin-0
。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: srs-api-service
spec:
type: LoadBalancer
selector:
app: srs-origin-0
ports:
- name: srs-origin-service-1985-1985
port: 1985
protocol: TCP
targetPort: 1985
EOF
Note: 源站对外提供API服务
srs-api-service
,我们选择第一个源站对外提供API服务,实际上源站集群需要改进这点,参考#1607。
Note: 这里我们选择ACK自动创建SLB和EIP,也可以手动指定SLB,参考Use One SLB and EIP for All Streaming Service。
Winlin 2020.02
Welcome to SRS wiki!
Please select your language:
Please select your language:
Please select your language:
Please select your language:
Please select your language: