1. FreeSWITCH与Kubernetes的适配性分析
FreeSWITCH作为一款开源的软交换平台,其核心功能是处理实时音视频通信。当我们将它部署到Kubernetes环境时,会遇到几个关键的技术适配问题:
首先是网络协议的特殊性。FreeSWITCH同时使用TCP和UDP协议:
- SIP信令:默认使用5060端口(UDP/TCP)
- RTP媒体流:默认使用10000-20000 UDP端口范围
- Event Socket:8021 TCP端口
- WebRTC:7443 TCP端口
这种多协议、多端口的特性使得传统的Kubernetes Service暴露方式面临挑战。特别是RTP需要的UDP端口范围,在标准的Kubernetes Service定义中难以完整映射。
其次是状态保持的需求。虽然FreeSWITCH本身支持集群部署,但单个实例仍然需要保持会话状态。这意味着:
- 需要避免Pod的频繁重启
- 需要确保会话数据持久化
- 需要考虑会话亲和性(Session Affinity)
2. 核心部署架构设计
2.1 基础组件规划
一个完整的FreeSWITCH Kubernetes部署通常包含以下组件:
- FreeSWITCH核心容器:运行主服务进程
- 配置管理系统:使用ConfigMap和Secret管理XML配置文件
- 持久化存储:用于录音、日志和数据库文件
- 网络暴露层:处理SIP和RTP流量
- 监控系统:收集性能指标和日志
2.2 网络拓扑方案
针对网络挑战,我们有三种主流方案可选:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| LoadBalancer + SBC | 生产环境 | 专业SBC处理NAT穿越 | 增加架构复杂度 |
| HostNetwork模式 | 测试环境 | 简化网络配置 | 丧失K8s网络隔离 |
| NodePort + 防火墙规则 | 混合环境 | 平衡复杂度与功能 | 需要维护防火墙规则 |
对于生产环境,我推荐第一种方案。虽然增加了Session Border Controller(SBC)组件,但它能专业处理以下问题:
- SIP和RTP的NAT穿越
- 协议转换和适配
- 安全防护和流量整形
3. 详细部署步骤
3.1 配置准备
FreeSWITCH的配置文件主要采用XML格式,我们需要将其转换为Kubernetes的ConfigMap。关键配置文件包括:
- vars.xml:系统变量定义
- sip_profiles/:SIP接口配置
- dialplan/:拨号计划
- modules.conf:模块加载配置
示例ConfigMap定义:
yaml复制apiVersion: v1
kind: ConfigMap
metadata:
name: freeswitch-config
data:
vars.xml: |
<include>
<X-PRE-PROCESS cmd="set" data="internal_sip_ip=$${local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=${EXTERNAL_IP}"/>
<X-PRE-PROCESS cmd="set" data="rtp_start_port=10000"/>
<X-PRE-PROCESS cmd="set" data="rtp_end_port=20000"/>
</include>
sip_profiles/internal.xml: |
<profile name="internal">
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
</profile>
关键提示:external_sip_ip和external_rtp_ip应该通过环境变量注入,可以使用Downward API获取Service的外部IP。
3.2 持久化存储配置
FreeSWITCH需要持久化的数据包括:
- 录音文件(/usr/local/freeswitch/recordings)
- 日志文件(/usr/local/freeswitch/log)
- 数据库文件(/usr/local/freeswitch/db)
建议使用StatefulSet配合PVC:
yaml复制apiVersion: apps/v1
kind: StatefulSet
metadata:
name: freeswitch
spec:
serviceName: freeswitch
replicas: 1
selector:
matchLabels:
app: freeswitch
template:
metadata:
labels:
app: freeswitch
spec:
containers:
- name: freeswitch
image: freeswitch/freeswitch:1.10
volumeMounts:
- name: data
mountPath: /usr/local/freeswitch/recordings
- name: data
mountPath: /usr/local/freeswitch/log
- name: data
mountPath: /usr/local/freeswitch/db
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 20Gi
3.3 网络暴露实现
3.3.1 SIP服务暴露
对于SIP信令,我们可以使用LoadBalancer Service:
yaml复制apiVersion: v1
kind: Service
metadata:
name: freeswitch-sip
spec:
selector:
app: freeswitch
ports:
- name: sip-udp
protocol: UDP
port: 5060
targetPort: 5060
- name: sip-tcp
protocol: TCP
port: 5060
targetPort: 5060
type: LoadBalancer
externalTrafficPolicy: Local
3.3.2 RTP处理方案
对于RTP流量,推荐以下两种方案:
方案A:使用云厂商的高级负载均衡器
例如AWS NLB支持UDP端口范围:
yaml复制apiVersion: v1
kind: Service
metadata:
name: freeswitch-rtp
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
selector:
app: freeswitch
ports:
- name: rtp-range
protocol: UDP
port: 10000-20000
targetPort: 10000-20000
type: LoadBalancer
方案B:使用NodePort配合防火墙规则
- 创建NodePort Service:
yaml复制apiVersion: v1
kind: Service
metadata:
name: freeswitch-rtp
spec:
selector:
app: freeswitch
ports:
- name: rtp-range
protocol: UDP
port: 10000-20000
targetPort: 10000-20000
type: NodePort
- 在外部防火墙配置规则,将公网IP的10000-20000 UDP端口转发到Kubernetes节点的对应NodePort。
4. 高级配置与优化
4.1 NAT穿越配置
在sip_profiles/internal.xml中添加NAT相关参数:
xml复制<param name="aggressive-nat-detection" value="true"/>
<param name="nat-options" value="stun,auto-nat"/>
<param name="stun-server" value="stun.stunprotocol.org"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
4.2 资源限制与QoS
在Deployment中配置资源限制:
yaml复制resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 2Gi
同时需要在FreeSWITCH配置中调整媒体参数:
xml复制<param name="rtp-timer-name" value="soft"/>
<param name="rtp-rewrite-timestamps" value="true"/>
<param name="enable-3pcc" value="true"/>
4.3 高可用方案
实现FreeSWITCH高可用的几种方式:
-
Active/Standby模式:
- 使用Kubernetes的Readiness Probe检测主实例健康状态
- 通过共享存储实现配置同步
- 使用领导选举机制切换VIP
-
集群模式:
- 配置FreeSWITCH集群
- 使用SIP Presence共享状态
- 通过Redis共享呼叫数据
示例集群配置:
xml复制<configuration name="sofia.conf">
<profiles>
<profile name="internal">
<param name="cluster-ip" value="$${local_ip_v4}"/>
<param name="cluster-port" value="8025"/>
<param name="cluster-shared-key" value="your_shared_secret"/>
</profile>
</profiles>
</configuration>
5. 监控与运维
5.1 健康检查配置
在Deployment中配置Liveness和Readiness探针:
yaml复制livenessProbe:
exec:
command:
- fs_cli
- -x
- "show status"
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
tcpSocket:
port: 8021
initialDelaySeconds: 30
periodSeconds: 10
5.2 指标收集
通过mod_event_socket输出指标到Prometheus:
- 配置Event Socket:
xml复制<configuration name="event_socket.conf">
<settings>
<param name="listen-ip" value="0.0.0.0"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
</settings>
</configuration>
- 使用freeswitch_exporter收集指标:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: freeswitch-exporter
spec:
template:
spec:
containers:
- name: exporter
image: xlab/freeswitch-exporter
env:
- name: FS_HOST
value: "freeswitch-service"
- name: FS_PORT
value: "8021"
- name: FS_PASSWORD
value: "ClueCon"
5.3 日志收集
配置Fluentd收集日志:
yaml复制apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
template:
spec:
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1.11
volumeMounts:
- name: freeswitch-log
mountPath: /var/log/freeswitch
env:
- name: FLUENT_FREESWITCH_LOG_PATH
value: "/var/log/freeswitch/*.log"
6. 安全加固
6.1 网络策略
限制不必要的访问:
yaml复制apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: freeswitch-policy
spec:
podSelector:
matchLabels:
app: freeswitch
ingress:
- ports:
- port: 5060
protocol: UDP
- port: 5060
protocol: TCP
- port: 8021
protocol: TCP
from:
- namespaceSelector: {}
podSelector:
matchLabels:
role: sip-proxy
6.2 TLS配置
启用SIP TLS和SRTP:
xml复制<profile name="external-tls">
<param name="tls" value="true"/>
<param name="tls-cert-dir" value="/etc/freeswitch/tls"/>
<param name="srtp-mode" value="required"/>
</profile>
使用Kubernetes Secret存储证书:
yaml复制apiVersion: v1
kind: Secret
metadata:
name: freeswitch-tls
type: kubernetes.io/tls
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
7. 常见问题排查
7.1 单通/无音频问题
可能原因及解决方案:
-
NAT配置错误:
- 确认external_rtp_ip设置正确
- 检查SDP中的媒体IP是否正确
- 验证STUN服务器可达性
-
防火墙限制:
- 确认UDP端口范围已开放
- 检查云安全组规则
- 验证kube-proxy的转发规则
-
编码协商失败:
- 检查SIP信令中的SDP offer/answer
- 确认双方支持的编码交集
- 查看FreeSWITCH日志中的编码协商过程
7.2 注册失败问题
排查步骤:
-
检查SIP消息流:
bash复制kubectl exec -it <freeswitch-pod> -- fs_cli -x "sofia global siptrace on" -
验证网络连通性:
bash复制kubectl exec -it <freeswitch-pod> -- ping <sip-provider> -
检查认证配置:
bash复制kubectl exec -it <freeswitch-pod> -- fs_cli -x "sofia status profile internal"
7.3 性能问题优化
常见性能瓶颈及优化:
-
CPU限制:
- 调整编码复杂度
- 启用媒体转码缓存
- 优化拨号计划脚本
-
内存不足:
- 限制并发呼叫数
- 调整会话超时时间
- 优化模块加载策略
-
网络延迟:
- 启用媒体流QoS标记
- 调整jitter buffer参数
- 考虑地域部署策略
8. 实际部署经验分享
在多个生产环境部署FreeSWITCH集群后,我总结了以下实战经验:
-
端口分配策略:
- 将RTP端口范围划分为多个区间,分配给不同节点
- 例如:Node1使用10000-15000,Node2使用15001-20000
- 这样可以避免端口冲突,同时简化防火墙规则
-
动态配置注入:
- 使用Init Container在启动时生成配置文件
- 通过Downward API获取Pod IP等信息
- 示例脚本片段:
bash复制EXTERNAL_IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) sed -i "s/\${EXTERNAL_IP}/$EXTERNAL_IP/" /etc/freeswitch/vars.xml
-
优雅终止处理:
- 配置preStop Hook转移呼叫:
yaml复制lifecycle: preStop: exec: command: - fs_cli - -x - "hupall graceful" - 设置terminationGracePeriodSeconds足够长(建议300秒)
- 配置preStop Hook转移呼叫:
-
版本升级策略:
- 采用蓝绿部署方式
- 使用数据库迁移工具处理schema变更
- 保持配置向后兼容
-
压力测试建议:
- 使用sipp工具模拟负载:
bash复制
sipp -sf uac.xml <service-ip> -l 100 -m 500 -r 10 - 监控关键指标:
- 呼叫建立时间
- 媒体延迟和抖动
- 系统资源使用率
- 使用sipp工具模拟负载:
-
灾难恢复方案:
- 定期备份关键配置和数据库
- 准备快速扩容脚本
- 建立跨AZ部署方案
通过以上实践,我们成功在Kubernetes上部署了支持5000并发呼叫的FreeSWITCH集群,平均呼叫建立时间<1s,媒体延迟<150ms,满足了企业级通信需求。