在Kubernetes上部署FreeSWITCH是一个常见的场景,但由于FreeSWITCH处理SIP和RTP流量的特性,网络配置是其中的关键部分。以下是详细的步骤和网络模式的讨论:
Kubernetes部署FreeSWITCH的详细步骤
1. 前提条件
- 一个运行中的Kubernetes集群。
kubectl命令行工具已配置并连接到你的集群。- (可选)了解Helm或Kustomize,这能简化复杂应用的部署和管理。
- FreeSWITCH Docker镜像(可以使用官方的
freeswitch/freeswitch,或者自己构建一个定制镜像)。
2. 准备FreeSWITCH配置
FreeSWITCH的大部分配置都是XML文件。为了在Kubernetes中管理这些配置,我们通常使用ConfigMap。
示例:vars.xml配置
创建一个名为freeswitch-vars-config.yaml的文件:
# freeswitch-vars-config.yamlapiVersion:v1kind:ConfigMapmetadata:name:freeswitch-vars-configdata:vars.xml:|<include> <!-- 主机名,这会影响内部SIP注册等 --> <X-PRE-PROCESS cmd="set" data="internal_hostname=$${hostname}"/> <!-- 内部SIP IP,通常是Pod的IP,但可能需要外部映射 --> <X-PRE-PROCESS cmd="set" data="internal_sip_ip=$${local_ip_v4}"/> <!-- 内部RTP IP,同上 --> <X-PRE-PROCESS cmd="set" data="internal_rtp_ip=$${local_ip_v4}"/> <!-- **关键:外部SIP IP和RTP IP** --> <!-- 如果FreeSWITCH在NAT后面,这两个变量至关重要。 --> <!-- 它们应该设置为外部可访问的IP地址。 --> <!-- 可以是负载均衡器的IP,或者Kubernetes Node的公共IP。 --> <!-- 后面会在网络模式中详细讨论如何设置。 --> <X-PRE-PROCESS cmd="set" data="external_sip_ip=YOUR_EXTERNAL_IP_OR_DNS"/> <X-PRE-PROCESS cmd="set" data="external_rtp_ip=YOUR_EXTERNAL_IP_OR_DNS"/><!--更多变量,如数据库连接、端口等--><X-PRE-PROCESS cmd="set" data="default_areacode=555"/> <X-PRE-PROCESS cmd="set" data="default_country_code=1"/> <X-PRE-PROCESS cmd="set" data="dialplan=XML"/> <X-PRE-PROCESS cmd="set" data="timezone=America/Chicago"/> <X-PRE-PROCESS cmd="set" data="rtp_start_port=10000"/> <X-PRE-PROCESS cmd="set" data="rtp_end_port=20000"/> <!-- ... 其他 FreeSWITCH 配置 ... --></include>其他配置:
同样地,你可以为sip_profiles、dialplan、modules.conf等创建单独的ConfigMap,或者将它们打包到一个ConfigMap中,并在FreeSWITCH Pod中作为文件挂载。对于敏感信息(如数据库密码、SIP用户密码),应使用Secret。
kubectl apply -f freeswitch-vars-config.yaml# 为其他配置文件创建并应用 ConfigMap/Secret3. 创建持久化存储 (PersistentVolumeClaim)
FreeSWITCH需要存储日志、录音文件、数据库(如果使用SQLite)等。为这些数据创建持久化存储至关重要。
示例:freeswitch-pvc.yaml
# freeswitch-pvc.yamlapiVersion:v1kind:PersistentVolumeClaimmetadata:name:freeswitch-pvcspec:accessModes:-ReadWriteOnce# 或 ReadWriteMany,取决于你的存储类型和需求resources:requests:storage:10Gi# 根据需要调整存储大小# storageClassName: your-storage-class # 如果集群有特定的存储类,请指定kubectl apply -f freeswitch-pvc.yaml4. 创建FreeSWITCH部署 (Deployment)
定义FreeSWITCH Pod的部署,包括容器镜像、端口映射、卷挂载和资源限制。
示例:freeswitch-deployment.yaml
# freeswitch-deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:freeswitchlabels:app:freeswitchspec:replicas:1# FreeSWITCH通常运行单个实例,除非有高级高可用或集群方案selector:matchLabels:app:freeswitchtemplate:metadata:labels:app:freeswitchspec:containers:-name:freeswitchimage:freeswitch/freeswitch:latest# 使用官方或你的定制镜像imagePullPolicy:IfNotPresentports:# SIP UDP/TCP-name:sip-udpcontainerPort:5060protocol:UDP-name:sip-tcpcontainerPort:5060protocol:TCP# RTP 范围 (UDP)# 注意:Kubernetes Service Port Range 比较复杂,通常Service只映射单个端口。# RTP范围需要在FreeSWITCH配置中定义,然后通过Service/LoadBalancer转发# 这里仅声明容器内部监听的RTP端口范围,Service无法直接映射范围# 通常做法是让Service暴露一个大范围的UDP端口,或者依赖外部负载均衡器-name:rtp-startcontainerPort:10000protocol:UDP-name:rtp-endcontainerPort:20000protocol:UDP# ESL (Event Socket Library)-name:eslcontainerPort:8021protocol:TCP# WebRTC WSS (如果启用)-name:webrtc-wsscontainerPort:7443protocol:TCPvolumeMounts:# 挂载ConfigMap作为文件-name:freeswitch-config-varsmountPath:/etc/freeswitch/vars.xml# 根据FreeSWITCH配置路径调整subPath:vars.xml# 如果有其他ConfigMap,也类似挂载# - name: freeswitch-config-sip-profiles# mountPath: /etc/freeswitch/sip_profiles/internal.xml# subPath: internal.xml# 挂载持久卷-name:freeswitch-datamountPath:/usr/local/freeswitch/log# 日志-name:freeswitch-recordingsmountPath:/usr/local/freeswitch/recordings# 录音# 根据需要挂载更多路径,例如 /usr/local/freeswitch/dbresources:requests:memory:"1Gi"cpu:"500m"limits:memory:"2Gi"cpu:"1000m"# Liveness和Readiness探针livenessProbe:tcpSocket:port:8021# 检查ESL端口是否开放initialDelaySeconds:30periodSeconds:10readinessProbe:tcpSocket:port:8021initialDelaySeconds:10periodSeconds:5volumes:-name:freeswitch-config-varsconfigMap:name:freeswitch-vars-config# - name: freeswitch-config-sip-profiles# configMap:# name: freeswitch-sip-profiles-config-name:freeswitch-datapersistentVolumeClaim:claimName:freeswitch-pvc-name:freeswitch-recordingspersistentVolumeClaim:claimName:freeswitch-pvc# 可以共享PVC,或者为不同类型的数据创建不同的PVCkubectl apply -f freeswitch-deployment.yaml5. 暴露FreeSWITCH服务 (Service)
这是处理FreeSWITCH网络模式的关键一步。FreeSWITCH需要暴露以下端口:
- SIP 信令: 5060 (UDP 和 TCP)
- RTP 媒体流: 默认 10000-20000 (UDP)
- ESL (Event Socket Library): 8021 (TCP)
- WebRTC WSS: 7443 (TCP, 如果启用)
由于RTP需要一个很大的UDP端口范围,这在Kubernetes Service中直接映射比较困难。
示例:freeswitch-service.yaml
# freeswitch-service.yamlapiVersion:v1kind:Servicemetadata:name:freeswitchlabels:app:freeswitchspec:selector:app:freeswitchtype:LoadBalancer# 或者 NodePort, 或 ClusterIP(如果仅集群内部访问)externalTrafficPolicy:Local# 保持客户端源IP,但可能影响调度ports:# SIP UDP-name:sip-udpprotocol:UDPport:5060targetPort:5060# SIP TCP-name:sip-tcpprotocol:TCPport:5060targetPort:5060# ESL-name:eslprotocol:TCPport:8021targetPort:8021# WebRTC WSS (如果启用)-name:webrtc-wssprotocol:TCPport:7443targetPort:7443# RTP 媒体流:这是最复杂的部分。# 负载均衡器通常不支持映射大范围的UDP端口。# 以下是一种可能的妥协方案:# 1. 如果你的云提供商的LoadBalancer支持UDP端口范围,可以直接在这里定义。# 2. 否则,可能需要通过NodePort暴露节点上的UDP范围,或者使用HostNetwork模式。# 这里我们只映射一个示例RTP端口,实际需要根据云厂商能力或解决方案调整。# 在实际生产中,通常需要一个外部的Session Border Controller (SBC)# 或者配置FreeSWITCH使用STUN/TURN服务器。# 这里为了演示,我们假设LoadBalancer能够处理UDP。# 注意:在很多云提供商的LoadBalancer上,你可能需要为每个RTP端口定义一个单独的条目,这是不现实的。# 因此,更常见的做法是:# a) 使用NodePort Service,然后配置外部防火墙/路由器转发UDP范围到Node。# b) 使用一个云提供商特定的负载均衡器配置(如AWS NLB),它可以支持UDP范围。# c) 在FreeSWITCH配置中,将 `external_rtp_ip` 指向一个STUN/TURN服务器或一个外部可路由的IP地址。# d) 启用 FreeSWITCH 的 STUN 支持。# e) 如果您的FreeSWITCH是与外部SIP终端通信,通常会有一个外部的防火墙/NAT规则将RTP范围映射到FreeSWITCH所在的Pod/Node。# 为了简化,这里我们仅列出SIP和ESL。RTP的具体处理方法见下文网络模式讨论。# - name: rtp-range # 这是一个概念性的名字,不代表Service可以直接映射范围# protocol: UDP# port: 10000 # 假设我们将外部的10000-20000转发到容器的10000-20000# targetPort: 10000 # Service通常只能映射单个targetPortkubectl apply -f freeswitch-service.yaml6. 验证部署
kubectl get pods -lapp=freeswitch kubectl get svc freeswitch kubectl logs<freeswitch-pod-name># 检查FreeSWITCH日志# 通过FreeSWITCH CLI(通过`kubectl exec`进入Pod或通过ESL)验证SIP注册和呼叫。FreeSWITCH的网络模式
FreeSWITCH的网络配置是其在Kubernetes中部署时最复杂的部分,主要涉及SIP信令和RTP媒体流。
1. 关键端口和协议
- SIP 信令: 5060 UDP 和 5060 TCP。
- RTP 媒体流: 通常是 10000-20000 UDP 端口范围。
- ESL (Event Socket Library): 8021 TCP。用于外部应用与FreeSWITCH交互(如拨号控制、事件监听)。
- WebRTC WSS: 7443 TCP。用于WebRTC客户端连接FreeSWITCH。
2. Kubernetes Service 类型选择
ClusterIP: 仅在集群内部可访问。如果FreeSWITCH只服务于集群内部的应用(例如,后端的代理或服务),可以使用此类型。NodePort: 将Service暴露在每个Kubernetes Node的特定端口上。外部流量可以通过NodeIP:NodePort访问。- 优点: 简单,适用于测试和小型部署。
- 缺点: Node的IP可能会改变,端口范围有限制(通常30000-32767),且RTP范围处理依然复杂。不适合生产环境的外部访问。
LoadBalancer:推荐用于外部访问。云提供商会创建一个外部负载均衡器,将流量转发到FreeSWITCH Pod。- 优点: 提供稳定的外部IP或DNS名称,可以处理高流量。
- 缺点:RTP端口范围的挑战。大多数云提供商的四层负载均衡器(如AWS NLB, GCP Network Load Balancer)可能支持UDP,但对映射一个大范围的UDP端口通常不够灵活,或者需要单独的配置。有些云服务可能需要为每个端口单独配置转发规则,这对于10000个RTP端口来说是不切实际的。
HostNetwork: true(在Pod配置中): 让FreeSWITCH Pod直接使用宿主机的网络命名空间。- 优点: FreeSWITCH直接监听宿主机的IP和端口,网络穿透问题(NAT)会大大简化,可以直接配置
external_sip_ip和external_rtp_ip为宿主机的公共IP。RTP端口范围问题也迎刃而解。 - 缺点: 丧失了Kubernetes网络隔离的很多优势,如端口冲突风险、网络策略失效。一个节点只能运行一个使用相同端口的FreeSWITCH Pod。这通常不被推荐,除非你有特殊且强烈的理由。
- 优点: FreeSWITCH直接监听宿主机的IP和端口,网络穿透问题(NAT)会大大简化,可以直接配置
3. NAT 穿越和外部IP配置 (最重要)
FreeSWITCH是一个媒体服务器,对网络环境特别是NAT非常敏感。当FreeSWITCH运行在Kubernetes Pod中时,它处于多层NAT后面(Pod IP -> Node IP -> 公共IP)。
你需要告诉FreeSWITCH它自己的外部可访问IP地址,以便它在SIP SDP消息中通告正确的IP。这通过FreeSWITCH的vars.xml或SIP Profile中的参数完成:
external_sip_ip: SIP 信令的外部IP。external_rtp_ip: RTP 媒体流的外部IP。
如何获取这些外部IP?
使用
LoadBalancerService:- 如果你使用
LoadBalancerService,它的EXTERNAL-IP就是你通常可以配置为external_sip_ip和external_rtp_ip的地址。 - 然而,由于RTP端口范围的限制,你可能需要一个更高级的负载均衡器或STUN/TURN服务器。
- 如果你的云提供商的负载均衡器允许配置UDP端口范围(例如,AWS NLB可以使用目标组来转发UDP流量范围),那么你可以配置LoadBalancer Service来处理RTP,并将LoadBalancer的外部IP作为
external_rtp_ip。 - 如果LoadBalancer不支持RTP范围,则你可能需要:
- STUN/TURN 服务器: 在FreeSWITCH配置中启用STUN/TURN。让外部客户端通过STUN/TURN服务器发现自己的公共IP和端口,并与FreeSWITCH协商媒体流。FreeSWITCH本身也可以作为STUN/TURN客户端。
- RTP代理/SBC (Session Border Controller): 部署一个SBC作为FreeSWITCH的前端,它负责处理NAT穿越,并将媒体流代理到FreeSWITCH。SBC会在FreeSWITCH Pod的IP和公共IP之间进行转换。
- 如果你使用
使用
NodePortService + 外部防火墙/NAT:- 将
NodePortService用于SIP和ESL。 - 手动配置外部防火墙/路由器,将公共IP上的RTP端口范围转发到运行FreeSWITCH Pod的Kubernetes Node的IP和对应的端口范围。
external_sip_ip和external_rtp_ip设置为Node的公共IP。
- 将
使用
HostNetwork: true:- 如果你在Pod中使用
hostNetwork: true,那么external_sip_ip和external_rtp_ip可以直接设置为该Node的公共IP地址。这是最直接处理NAT的方式,但如前所述,不推荐。
- 如果你在Pod中使用
auto-nat和nat-type(FreeSWITCH内部配置):- FreeSWITCH的SIP配置文件中可以设置
auto-nat=true,nat-type=stun等参数,让FreeSWITCH尝试自行进行NAT检测和穿透。但这些通常需要结合external_sip_ip和external_rtp_ip才能更好地工作。
- FreeSWITCH的SIP配置文件中可以设置
总结网络模式
- FreeSWITCH本身处理的是SIP和RTP协议,需要UDP和TCP端口。
- Kubernetes Service主要用于将容器端口暴露给集群外部。
- 最大的挑战在于RTP的UDP端口范围和NAT穿越。
- 推荐方案(生产环境):
- 使用
LoadBalancerService 暴露 SIP (5060 UDP/TCP) 和 ESL (8021 TCP)。 - 对于 RTP 媒体流:
- 如果云提供商的LoadBalancer能支持UDP端口范围映射,则使用它,并将LoadBalancer的外部IP配置为
external_rtp_ip。 - 否则,考虑部署一个SBC/RTP代理在FreeSWITCH前面处理媒体流和NAT。
- 或者配置FreeSWITCH使用STUN/TURN服务器来协助NAT穿越。
- 在
vars.xml中正确设置external_sip_ip和external_rtp_ip是强制性的。- 这些IP通常是你的Kubernetes集群前方的负载均衡器或网络出口的公共IP。
- 你可以通过一个脚本在部署时动态获取LoadBalancer的外部IP并注入到ConfigMap中。
- 如果云提供商的LoadBalancer能支持UDP端口范围映射,则使用它,并将LoadBalancer的外部IP配置为
- 使用
部署FreeSWITCH在Kubernetes上需要仔细规划其网络,尤其是涉及到外部呼叫时。我建议从LoadBalancerService开始,并重点关注RTP媒体流的路由和NAT穿越方案。