Taz TFG 2021 4586
Taz TFG 2021 4586
Taz TFG 2021 4586
Autor
Director
Fernando Orús Morlans
Ponente
Julián Fernández Navajas
Resumen
El uso de las tecnologías que sustentan los servicios de telefonía está sujeto a las
condiciones personales de los clientes que las utilizan y, por tanto, el nivel de carga que
requiere una arquitectura capaz de proveer de estos servicios es igualmente cambiante. Esto
se acentúa en situaciones como días festivos, o en un caso más reciente y generalizado, la
pandemia de COVID-19, durante la cual el uso de estos servicios ha aumentado
considerablemente.
Este Trabajo de Fin de Grado aborda la problemática que reside en el uso de una
plataforma capaz de adaptarse automáticamente a estos cambios, con el objetivo de proveer
de los servicios necesarios a un gran número de usuarios sin hacer un uso innecesario de los
recursos disponibles. Para ello, se va a trabajar sobre un modelo de procesamiento de
llamadas diseñado por la empresa System One Noc & Development Solutions, S.A. (en
adelante SONOC), que hace uso de las tecnologías de voz sobre IP (VoIP), de forma
alternativa a la red telefónica convencional debido a su gran capacidad de integración y
costes reducidos. Esta tecnología surgió con el estándar H.323 para el manejo de llamadas,
pero en la actualidad el protocolo de uso más extendido (y el que vamos a utilizar) es SIP,
que permite el establecimiento, mantenimiento y finalización de sesiones de voz y vídeo
entre varios usuarios. SIP es un protocolo que normalmente se utiliza sobre el protocolo de
transporte UDP, que no ofrece garantías sobre entrega de mensajes y no guarda el estado de
las conexiones establecidas ya que SIP tiene mecanismos propios de mantenimiento de la
sesión. Por otro lado, aunque menos extendido, se puede utilizar sobre TCP, que sí ofrece
dichas características.
3
recursos disponibles. A continuación, se procederá a la implementación de la arquitectura
en el entorno de despliegue de contenedores Kubernetes, el cual es capaz de controlar el
despliegue de las aplicaciones para hacer un uso sostenible de los mismos. Para poder
realizar pruebas sobre el sistema desarrollado, utilizaremos un generador de tráfico SIP
llamado SIPp, en el cual realizaremos escenarios de tráfico cambiante.
4
Índice de contenidos
1. Introducción ................................................................11
1.1. Introducción y motivación .............................................................................. 11
5
5.2. Pruebas de comunicación y carga de tráfico: escenario 2.................................. 54
Bibliografía ....................................................................... 64
6
Índice de figuras
7
FIGURA 32. ESCENARIO 3. ESTADO FINAL .................................................................................................................. 59
FIGURA 33. ESCENARIO 3. AJUSTE DE ESCALA CON SEÑALIZACIÓN UDP........................................................................... 60
FIGURA 34. ESCENARIO 3. AJUSTE DE ESCALA CON SEÑALIZACIÓN TCP ........................................................................... 61
8
Glosario de términos
9
RTP. Real Time Protocol
10
1. INTRODUCCIÓN
11
ejecuta procesos de forma independiente y que se pueden comunicar entre sí haciendo uso
de redes virtuales. El uso de Docker se ha generalizado en la actualidad debido a la
versatilidad de las aplicaciones que implementa. En particular, el uso de Docker sobre
Kubernetes, que es una herramienta que facilita el uso de estos contenedores.
12
Figura 1. Ejemplo de orquestador para servicios web
Para finalizar, diremos que este Trabajo de Fin de Grado se realiza en el contexto de
trabajo de la empresa SONOC, que se encarga, entre otras cosas de proveer servicios de
VoIP. Además de esto, SONOC implementa soluciones de mejora de los servicios que
ofrecen, como herramienta de realce de la voz, funcionalidades mediante marcado de tonos
DTMF, etc. El objetivo de este proyecto es la implementación de una arquitectura de
servicios VoIP que optimice el uso de recursos sin comprometer la calidad de los servicios
que ofrecen.
1.2. OBJETIVOS
El objetivo principal de este Trabajo Fin de Grado es la comparativa entre las distintas
posibilidades planteadas para el diseño de una arquitectura capaz de proveer servicios VoIP
masivos, destacando las ventajas y desventajas de cada una, teniendo en cuenta aspectos
como la escalabilidad, el uso eficiente de los recursos hardware y las posibles problemáticas
que pueden surgir del uso de cada una de ellas.
13
utilizando contenedores de software (Docker con Kubernetes) sin orquestar. Por último
propondremos una implementación que permita la orquestación utilizando Kubernetes.
14
1.3. ORGANIZACIÓN DE LA MEMORIA
Por último, se incluirá una bibliografía con las fuentes utilizadas y anexos que
complementan la información sobre el trabajo realizado.
15
2. ANÁLISIS PREVIO
Protocolos
Lenguajes de programación
Herramientas utilizadas
Servidores
Kamailio
Freeswitch
RTPEngine
Aplicaciones
Docker
16
Kubernetes
SIPp
Zoiper
Wireshark/TCPDump
WinSCP
Github
Dockerhub
Durante la introducción se han mencionado los tres enfoques posibles del problema:
una solución consistente en la separación de los elementos hardware que implementan el
servicio, otra solución basada en el uso de contenedores mediante Docker y Kubernetes, pero
sin hacer uso de la orquestación, y una solución análoga a la anterior, pero usando
orquestación. Estas arquitecturas deben ser capaces de establecer llamadas entre múltiples
usuarios a través de la red VoIP utilizando el protocolo SIP para la señalización de llamadas
y RTP para el tráfico de audio de la llamada.
17
Figura 2. Arquitectura previa
De esta forma, los elementos que vamos a crear en nuestra arquitectura son: PROXY
IN, MEDIA SERVER, POOL B2BUA, SIP ROUTE SERVER y PROXY OUT; elementos
encargados del establecimiento de llamadas mediante SIP y envío de paquetes de datos
mediante RTP, siendo el resto de elementos únicamente necesarios para fines de facturación
y obtención de estadísticas. Finalmente, realizaremos una comparativa entre los protocolos
TCP y UDP según su viabilidad para su uso en un entorno de contenedores orquestados,
siendo necesaria, para ello, la configuración de cada elemento de la arquitectura.
18
Por último, en todas las aproximaciones al problema planteado, se creará una
arquitectura de pruebas, con los elementos más o menos diferenciados, y en todos los casos
la arquitectura se encontrará perfectamente localizada en la nube de Amazon Web Services.
La terminación de las llamadas en el escenario real serán distintos proveedores de servicios
de VoIP, que actúan como pasarelas para la conmutación de llamadas en regiones distintas.
En nuestro trabajo y por simplicidad, trabajaremos con un único proveedor de servicios que
simplemente conteste todas las llamadas. De esta forma, en la Figura 3. Escenario previo,
podemos ver cómo quedaría a grandes rasgos la arquitectura que planteamos en un escenario
de aplicación real.
19
3. IMPLEMENTACIÓN VIRTUALIZADA SIN
CONTENEDORES
La arquitectura más simple que podemos plantear consistiría en sendos elementos que
sirvan como proxy SIP y RTP entre dos usuarios. Para ello, utilizamos Kamailio y
RTPEngine respectivamente. La función de estos proxys es simplemente la de reenviar los
paquetes generados por un extremo hacia el otro. Este acercamiento, que queda representado
en la Figura 4. Esquema simple de plataforma VoIP, es muy limitado y no ofrece ningún
mecanismo de gestión de llamadas, pudiendo únicamente comunicar usuarios registrados en
un mismo dominio. La comunicación entre ambos proxy se hace mediante el protocolo
propio de Sipwise, NGCP. Este protocolo sirve para hacer conocedor a RTPEngine de las
llamadas establecidas por Kamailio y de los usuarios que participan en ellas, a fin de
establecer conexiones RTP con ellos.
20
Figura 4. Esquema simple de plataforma VoIP
Este esquema, si bien puede servir como prueba, sólo ofrece la funcionalidad de
establecimiento de llamadas. Es por ello que en nuestra plataforma añadiremos un softswitch,
que como hemos descrito anteriormente, realizará las funciones de integración, de forma que
no haya problemas entre usuarios que utilicen clientes VoIP diferentes, así como las diversas
funciones adicionales que se quieran incluir (marcación de tonos, buzón de voz, etc.). La
inclusión de este softswitch implica la creación de un segundo proxy SIP, que junto al que
ya teníamos servirán, además, de filtrado de tráfico externo, impidiendo llamadas no
deseadas y maximizando los recursos que ofrece el softswitch a las llamadas aceptadas. Todo
esto queda representado en la Figura 5. Esquema de plataforma VoIP con softswitch. El
tráfico NGCP en este caso se generará desde el Kamailio que actúa como proxy de salida,
puesto que usando la información de las cabeceras es capaz de transmitir la dirección en la
que se encuentran los usuarios que participan de la llamada, permitiendo al proxy RTP
establecer las conexiones con los extremos.
21
Figura 5. Esquema de plataforma VoIP con softswitch
Esta arquitectura nos permite crear sesiones entre usuarios, y además aporta las
funcionalidades de un softswitch. Si bien esto ya es perfectamente funcional, sólo permite
llamadas entre usuarios residentes en un dominio limitado. Esto significa que usuarios de
distintas compañías telefónicas no podrán comunicarse entre sí. Por ello, nuestra plataforma
de VoIP deberá poder enviar las llamadas a distintos proveedores de servicios VoIP remotos
(en distintos lugares y sirviendo a otros usuarios) que se encargarán de terminar las llamadas
usando sus propios switch, y cuyas direcciones obtendremos de un servidor de rutas basado
en reglas mediante Kamailio. En la Figura 6. Esquema de plataforma VoIP con servidor de
rutas, observamos este nuevo acercamiento, que permite el establecimiento de llamadas con
los proveedores conocidos. Las peticiones de ruta se harán en el softswitch, y la información
obtenida del servidor se llevará desde el softswitch hasta el proxy de salida, que encaminará
la llamada al proveedor correspondiente, y a la vez será capaz de comunicar esta información
al proxy RTP, que establecerá conexiones tanto con el usuario llamante como el llamado.
22
Figura 6. Esquema de plataforma VoIP con servidor de rutas
Visto el planteamiento del problema con respecto a los servidores que vamos a utilizar,
el siguiente paso es ubicar dichos servidores en un entorno en el que estos puedan
comunicarse entre sí. Para ello vamos a utilizar la plataforma AWS. En concreto, de la
plataforma de cómputo en la nube EC2, que nos permite crear máquinas virtuales con
recursos variables. En el Anexo B: Amazon Web Services se da más información sobre la
configuración de instancias EC2 y cómo permitir la comunicación entre ellas.
23
Las instancias que crearemos correrán sobre un kernel de Linux, en concreto utilizarán
el sistema operativo Debian 9.13, que ofrece compatibilidad con las herramientas que vamos
a utilizar.
24
3.3. COMUNICACIÓN DE SERVIDORES
Como hemos dicho anteriormente, los servidores que formarán parte de nuestro switch
se encuentran alojados en servidores remotos alojados en AWS, por lo que es necesario
configurar correctamente dichos equipos para obtener un funcionamiento síncrono y
correcto, capaz de servir múltiples llamadas simultáneas.
Dado que las máquinas alojadas en AWS forman parte de redes virtuales privadas
protegidas con firewalls (lo que supone grupos de seguridad), en un escenario por defecto,
el único puerto activo para acceder a los recursos del equipo es el 22 de TCP, usado para
conexiones SSH, y cualquier otra conexión que realicemos será rechazada, por lo que el
primer paso será configurar el firewall de cada equipo para permitir conexiones entrantes y
salientes a través de los puertos correspondientes. Todas las aplicaciones que usamos pueden
configurarse para utilizar los puertos que se deseen para todas las conexiones, pero nosotros,
por conveniencia, haremos uso de los puertos por defecto de cada protocolo.
En el caso de RTP, el proxy abre dos conexiones, una con cada extremo de la
conexión a través de un puerto aleatorio entre el 16384 y el 32768 de UDP, por
lo que los abriremos todos a fin de servir tantas llamadas como sea posible.
En el Anexo B: Amazon Web Services se ofrece información sobre los firewalls de red
y como abrir los puertos indicados. Para comprobar que un determinado puerto se encuentra
abierto podemos hacer uso del siguiente comando desde una terminal de Linux conectada
por SSH al equipo remoto (para más información sobre como realizar este acceso ver Anexo
H: Creación de par de claves y acceso SSH):
25
Figura 8. Comprobación de puertos abiertos usando nmap
Una vez permitidas las conexiones entre equipos a través de los puertos, únicamente
hace falta instalar los servidores correspondientes en los diferentes equipos (ver Anexo D:
Instalación y configuración de servidores para más información) y posteriormente realizar
las modificaciones pertinentes en los ficheros de configuración de cada servidor. Estas
modificaciones se harán usando una conexión SSH remota desde un equipo local utilizando
WinSCP, un cliente que presenta una interfaz gráfica para la transferencia y edición de
ficheros, perfecto para lo que necesitamos. En el Anexo H: Creación de par de claves y
acceso SSH se describe como utilizar este programa. Una vez hecho esto, podemos iniciar
cada aplicación mediante sus servicios, haciendo que estas empiecen a escuchar tráfico en
los puertos correspondientes y a gestionarlo de forma que se ofrezca el servicio que
deseamos. La explicación sobre los ficheros de configuración que vamos a desarrollar se
encuentra en el Anexo C: Desarrollo del sistema.
Por último, vamos a replicar el comportamiento deseado para una llamada cualquiera
(esta explicación no entra en detalle sobre el procesamiento o los mecanismos propios de
SIP para asegurar el establecimiento de las conexiones, lo cual se verá más adelante):
En primer lugar, un usuario envía una petición de llamada al proxy SIP de entrada con
un mensaje “SIP INVITE”, usando una URI compuesta de un nombre de usuario, y el par
26
IP/puerto (5060) donde se aloja el proxy SIP. El destinatario de la llamada es otra URI con
un nombre de usuario y el mismo par IP/puerto, lo cual vemos en la Figura 9. Envío de
mensaje INVITE a proxy SIP.
27
Figura 10. Reenvío de mensajes al softswitch
28
Figura 11. Petición de ruta
29
Figura 12: Finalización del establecimiento de llamada
30
Figura 13. Establecimiento de conexiones RTP
31
Con esto, la configuración del escenario (implementación tradicional) está completo y
estaría listo para recibir llamadas. En el Anexo J: Pruebas de llamada con Zoiper y el Anexo
K: Pruebas de llamada con SIPp se encuentra más información sobre la puesta en marcha
de cada una de las aplicaciones, así como de la forma en la que cada una de ellas gestiona
los mensajes. Adicionalmente, los resultados de dichas pruebas sobre este escenario se
encuentran en el Capítulo 5. Pruebas de comunicación y carga de tráfico.
32
4. IMPLEMENTACIÓN VIRTUALIZADA USANDO
CONTENEDORES MEDIANTE KUBERNETES
En este capítulo vamos a presentar los dos escenarios en los que vamos a usar la
herramienta Kubernetes para el despliegue de aplicaciones en contenedores. En primer lugar,
haremos un escenario sin orquestar y en base a ello, evolucionaremos hacia un escenario
orquestado, presentando las diferencias entre ambas implementaciones. Los elementos de
Docker y Kubernetes que se van a utilizar son comunes entre ambas implementaciones. El
punto de partida de este escenario es una máquina virtual en el que ambas herramientas se
encuentran instaladas, la información al respecto de esta instalación se encuentra en el Anexo
E: Instalación y configuración de otras herramientas.
Las imágenes se crearán a partir de un fichero Dockerfile. Las imágenes que usemos
partirán de una ya creada por las desarrolladoras de las respectivas aplicaciones, por lo que
no tendremos problemas de compatibilidad, y lo único que tendremos que hacer es realizar
los cambios requeridos para que nuestra aplicación funcione como nosotros deseemos,
como, por ejemplo, copiar los ficheros de configuración específicos que hemos desarrollado,
ejecutar comandos o exponer puertos. Todo esto está explicado en el Anexo F: Docker.
Para este escenario se elaborarán imágenes de contenedor para cada uno de los
servidores que anteriormente se encontraban virtualizados, para un total de cuatro ficheros
Dockerfile, cada uno con la configuración de los elementos equivalentes del escenario
anterior, y que luego utilizaremos en la implementación de objetos en Kubernetes, como se
muestra en la Figura 14. Elaboración de ficheros de imagen.
33
Figura 14. Elaboración de ficheros de imagen
Lo cual ejecuta un Shell interactivo dentro del contenedor, de forma que podemos
ejecutar comandos y realizar una comprobación previa de los elementos básicos de la
imagen.
34
4.2. ELEMENTOS DE KUBERNETES
Una vez creadas las imágenes de contenedor que vamos a utilizar, podemos pasar a su
implementación en un entorno de Kubernetes. Como ya se mencionó anteriormente, la
estructura de Kubernetes se basa en objetos de distinta naturaleza que implementan
funciones que forman parte de un todo. Estos objetos se escriben en formato YAML y tienen
una estructura muy concreta. En el Anexo G: Kubernetes, se describe con precisión la
estructura de los distintos objetos.
35
Figura 15. Abstracción de aplicaciones en Kubernetes
36
Figura 16. Servicios en Kubernetes
En la figura vemos que el service que distribuye la carga entre pod se encuentra
distribuido en todos los nodos, de forma que cualquier petición, interna o externa al clúster
pueda ser alcanzada por el service. En el caso de querer servir peticiones se hace uso de un
puerto seleccionado de las interfaces externas de los nodos del clúster para recibir paquetes.
Si se quieren servir peticiones provenientes del interior del clúster, Kubernetes implementa
un servidor de nombres conocido por todos los pod y con una dirección IP estática, y de esta
forma se puede localizar el service sencillamente sin conocer su IP mediante peticiones
DNS.
37
Cada service tiene una dirección IP de la subred 10.96.0.0/16, siendo
seleccionable por el usuario. La única dirección de la subred que no se puede
seleccionar es la 10.96.0.10, donde se aloja el servidor de nombre kube-dns.
Cada vez que queremos hacer una petición dirigida a un pod tenemos que escoger
como dirección IP destino la del service (en caso de escribir el nombre de dominio asociado
al service se acude al kube-dns para resolver la petición). Como todos los elementos del
clúster se encuentran en una red privada compartida, la resolución de direcciones se hace a
nivel de enlace, por lo que es necesario resolver la dirección MAC asociada a una dirección
IP. Esto se hace mediante el protocolo ARP, tras lo cual los paquetes pueden llegar a los
service correspondientes, que ya conociendo las direcciones IP y MAC de los pod a los que
deben hacer llegar el tráfico, realizan las funciones de balanceo de carga. Este
comportamiento puede servir para comprender el funcionamiento global del enrutamiento
de paquetes en el clúster, pero tiene algunas peculiaridades debido al uso de proxy
configurado por Kubernetes. Esto lo veremos en el Capítulo 5. Pruebas de comunicación y
carga de tráfico. Por último, tenemos que hablar de un elemento que va a resultar importante
en la orquestación de contenedores: el HPA (Horizontal Pod Autoscaler), que es un elemento
que toma medidas de uso de los recursos hardware asignados a los pod de un deployment y
los pasa al plano de control de Kubernetes para que este decida si se deben tomar acciones
de escalado de la aplicación. La operación que utiliza Kubernetes para decidir si se deben
crear o eliminar réplicas es la siguiente:
𝑚𝐴
𝑛𝑅 = 𝑛𝑅𝐴 ∗
𝑚𝐷
Donde:
Una vez visto esto, ya hemos abordado todos los elementos importantes en nuestra
implementación de aplicaciones en Kubernetes.
38
4.3. IMPLEMENTACIÓN
Por otra parte, los cuatro service que vamos a implementar permitirán la conexión entre
los cuatro pod que implementamos. En el caso del proxy de entrada, tendremos que hacer
uso de un service tipo “Nodeport”, el cual escucha tráfico en la interfaz externa de los nodos
del clúster y redirige el tráfico a un puerto del pod. En el resto de casos, usaremos un service
de tipo “ClusterIP”, que tienen una IP estática y un nombre de dominio conocido por un
DNS para balancear la carga de tráfico entre los pod. En el caso del escenario sin orquestar,
dicho balanceo de carga no existirá, pues solamente existe una réplica de cada pod para cada
servicio. Aun así, es necesario crearlos ya que la IP de los pod no es estática. En la Figura
17. Implementación en Kubernetes. Escenario sin orquestar se muestra cómo quedaría este
escenario en un clúster distribuido.
39
Figura 17. Implementación en Kubernetes. Escenario sin orquestar
En esta figura se observa que cada pod se puede encontrar en un equipo distinto,
mientras que los servicios se implementan en cada uno de ellos, de forma que cualquier
petición proveniente del clúster pueda ser servida.
40
4.3.2. Escenario orquestado
A continuación, pasaremos a observar el escenario orquestado. Para ello,
necesitaremos: 4 deployment, 4 service y 4 HPA. Como hemos dicho anteriormente, los pod
que implementa un deployment se encuentran distribuidos entre todos los equipos, y los
service se encuentran simultáneamente en todos ellos para servir peticiones y funcionar
como balanceador de carga sobre dichos pod. En este caso, además, necesitaremos 4 HPA,
que se encarguen de tomar medidas de uso de recursos hardware asignados a los pod de un
deployment, para de esta forma tomar decisiones sobre el escalado de los mismos. En la
Figura 18. Implementación en Kubernetes. Escenario orquestado se observa el resultado de
esta implementación.
41
En esta figura se observa, una vez más, cómo los pod de cada deployment (siendo los
pod de cada deployment iguales entre sí, pero diferentes al de los pod de otros deployment
en cuanto a las funciones que implementan) se encuentran distribuidos por los equipos de
forma arbitraria y los service se encuentran en cada nodo. Adicionalmente, los HPA toman
medidas de cada pod, por lo que deben encontrarse también en cada nodo donde haya pod
del respectivo deployment.
42
Dadas las restricciones que presenta Kubernetes para captar tráfico externo, el primer
paso para conmutar una llamada es que los paquetes SIP correspondientes pasen por una
regla de IPTables. El usuario normalmente hará la llamada sobre el puerto 5060, y esta regla
la traducirá al puerto 30100, de forma que el service que hemos establecido para captar el
tráfico externo y enviarlo al proxy de entrada reciba esos paquetes. Esto se ve representado
en la Figura 20. Escenario con Kubernetes. Regla La definición de la regla que hemos
creado se encuentra en el Anexo I: Configuración de IPTables como DNAT.
La forma en la que se procesan los paquetes dentro del clúster a partir de este punto es
similar al escenario sin contenedores, salvo por la existencia de los diversos proxys a los que
43
se envían inicialmente las llamadas y del reparto de carga que estos realizan. En las
siguientes figuras se muestra este proceso, que es análogo a las de las figuras 9, 10, 11, 12 y
13 que representaban el flujo de tráfico en el primer escenario. Además, en un escenario con
un único nodo, las conexiones entre pod son locales, por lo que no salen a la red pública de
Internet. En el caso de que los pod, que deben comunicarse entre sí, se encuentren en nodos
diferentes, el contenido de los paquetes se encapsula y se envía a través de un puerto seguro
(el 6443 de TCP por defecto). En las siguientes figuras, para mayor claridad vamos a suponer
un único nodo.
44
Figura 21. Escenario con Kubernetes. Envío de mensaje INVITE a proxy SIP
En esta figura el service que escucha en el puerto 30100 recibe las llamadas de los
softphones, y distribuye la carga entre los pod que implementan los contenedores del proxy
SIP de entrada, enviándolos al puerto 5060 de cada uno de ellos.
45
Figura 22. Escenario con Kubernetes. Reenvío de mensajes al softswitch
En esta figura el mensaje SIP INVITE recibido por los proxys SIP es reenviado al
service del softswitch, tras lo cual se hace un reparto de carga entre los pod existentes.
46
Figura 23. Escenario con Kubernetes. Petición de ruta
47
Figura 24. Escenario con Kubernetes. Finalización del establecimiento de llamada
Por último, una vez comunicada la ruta, el softswitch envía el mensaje INVITE al
proxy de salida, que genera un paquete INVITE que sale del clúster con la dirección destino
indicada en la cabecera, que se corresponderá con el equipo remoto que se encarga de
terminar las llamadas.
48
Figura 25. Escenario con Kubernetes. Establecimiento de conexiones RTP
49
los pod, no podemos garantizar la existencia de aquellos que están sirviendo una determinada
llamada en el momento de su finalización. Esto implica que no se puede crear un registro de
llamada y la conversación se quedaría “colgada”, al haber flujos constantes RTP, pero no
SIP que indiquen la finalización de la llamada. Esto puede ser solucionado haciendo uso del
protocolo TCP, que establece conexiones entre los pod, impidiendo que estos sean
eliminados mientras tengan conexiones activas correspondientes a las llamadas que cursan.
Esto genera una nueva problemática: el objetivo de Kubernetes es que los recursos de
hardware que se dedican al procesamiento de tráfico (en este caso de llamadas) se ajuste a
las necesidades de cada instante. En el caso de uso de TCP para conexiones de larga duración
podemos vernos en la situación en la que algún pod se encuentre activo debido a una llamada
inusualmente larga. Esto genera una pérdida de eficiencia, pues estamos dedicando una
cantidad de recursos alta al procesamiento de un tráfico ligero en comparación.
50
5. PRUEBAS DE COMUNICACIÓN Y CARGA DE
TRÁFICO
51
5.1. PRUEBAS DE COMUNICACIÓN: ESCENARIO 1
Haremos capturas en las siguientes máquinas: SIP Proxy In, softswitch, SIP Route
Server y SIP Proxy Out. Las comunicaciones entrantes y salientes de cada máquina utilizan
la interfaz de red primaria (por lo general se llama eth0, pero ésta puede variar dependiendo
de la configuración de red de las máquinas), y en ella hacemos las capturas. Si ordenamos
los paquetes capturados en cada máquina, podemos elaborar un diagrama completo del
intercambio de mensajes generado, el cual se muestra en la Figura 26. Escenario 1.
Intercambio de mensajes, y que deberemos comparar con el generado en los escenarios
posteriores.
52
Figura 26. Escenario 1. Intercambio de mensajes
53
5.2. PRUEBAS DE COMUNICACIÓN Y CARGA DE
TRÁFICO: ESCENARIO 2
Prueba de comunicación
Realizando una captura desde el cliente con Zoiper (que actúa como UAC de la
llamada) sobre su interfaz de red primaria obtenemos la siguiente traza:
54
Figura 27. Escenario 2. Intercambio de mensajes. UAC
Como hemos dicho, en el clúster debemos capturar en la interfaz weave. Esta interfaz
no es propia de un contenedor en concreto, sino que muestra todo el tráfico generado en el
clúster. En esencia, la interfaz weave conecta virtualmente las interfaces de red propias de
cada contenedor. Capturar sobre esta interfaz nos permite observar de forma conjunta el
intercambio de mensajes generado, debiendo identificar todos los elementos que intervienen
en cada diálogo SIP.
En las siguientes figuras se han identificado las distintas conexiones generadas a partir
de una única llamada. Estas conexiones se corresponden con la división generada por la
existencia de un B2BUA (que como hemos visto anteriormente, divide la comunicación
entre dos usuarios, actuando como UA simulado que se comunica “back-to-back” y de forma
independiente con los UA reales [ver Anexo A: Protocolo de Iniciación de Sesión para
información más detallada al respecto]) y que hemos llamado “tramo A” y “tramo B” de la
comunicación, y de la conexión entre el softswitch y el SIP Route Server, en la que se
produce la petición de ruta.
Las trazas obtenidas se muestran en las siguientes figuras, las cuales se han ordenado
en el orden lógico en el que las distintas conexiones se producen: en primer lugar, el tramo
A de la comunicación entre el UAC y el softswitch, seguido de la petición de ruta, y por
último el tramo B de la comunicación entre el softswitch y el proveedor.
55
Figura 29. Escenario 2. Clúster tramo A
56
Para una mejor comprensión de las figuras identificamos las siguientes direcciones IP:
10.32.0.1: IP interna del plano de control de Kubernetes que recibe las llamadas
en el clúster, y que envía el tráfico al pod Kamailio proxy-in.
Prueba de carga
57
Usando el escenario desarrollado en los anexos, estableceremos una tasa de 1 nueva
llamada por segundo, con una duración de 15 segundos cada una, e iremos aumentando dicha
tasa hasta que observemos la existencia de errores. Los resultados obtenidos son los
siguientes:
Debido a que los recursos asociados a cada elemento de nuestra arquitectura son
iguales, y es sabido que Freeswitch consume una cantidad de recursos mayor que Kamailio
(debido a aspectos como tener que mantener el estado de las conexiones activas), es
aceptable asumir que dichos errores se producen en este elemento, debido a la falta de
recursos CPU. En nuestro proyecto hemos usado una máquina de AWS t2.medium, con 2
CPU virtuales y 4 GB de memoria RAM, por lo que en un despliegue completo usando este
tipo de máquinas, haciendo la división entre los recursos de CPU de los que hace uso cada
pod (200 milicores o 0.2 CPU) y los recursos totales, el máximo de llamadas nuevas que
calculamos de puedan servir será de aproximadamente 65 por segundo y “worker” (cada
equipo del clúster de Kubernetes que ofrece sus recursos hardware para el despliegue de
aplicaciones en contenedores). Este valor es una aproximación, ya que, en un escenario real,
las comunicaciones activas tienen, por lo general, una mayor duración.
58
a observar las diferencias observadas entre los ajustes de escala mediante señalización SIP
por UDP y TCP. Para ello, haremos uso de SIPp.
En primer lugar, haremos una prueba utilizando una tasa de llamadas por segundo
inferior al límite obtenido en el apartado anterior (9 llamadas por segundo), y veremos el
grado de utilización de cada pod y cómo se crean nuevos debido a la demanda de recursos.
59
5.3.1. Señalización SIP por UDP
Vamos a comprobar el mecanismo de cierre de pod de Kubernetes, para ello, abriremos
dos llamadas servidas por dos pod distintos, y comprobaremos el cierre de éstos pasado un
tiempo. El escenario usado será uno en el que la orquestación sólo se aplique sobre uno de
los tipos de pod, para comprobar mejor los resultados. Para señalización UDP, como ya
dijimos, no detectaría conexiones activas, por lo que se produce dicho cierre generando la
pérdida de la comunicación. Para comprobar el nivel de escala de los deployment en tiempo
real usamos:
En la Figura 33. Escenario 3. Ajuste de escala con señalización UDP observamos este
comportamiento.
En la sección “events” podemos ver en una línea de tiempo (cada línea tiene un valor
“Age” asociado, que indica el tiempo pasado desde que se produjo el evento hasta la
ejecución del comando que los muestra) cómo aumenta el nivel de escala del deployment (es
decir, que aumenta el número de pod del mismo tipo), pero éste disminuye, tiempo después,
debido a la bajada de tráfico que observa el clúster. Hay que precisar que, por defecto, las
acciones que suponen bajar la escala tardan alrededor de unos 5 minutos en surtir efecto.
Este valor puede ser modificado, pero conviene dejar un valor lo suficientemente grande
como para que el sistema no responda inmediatamente a picos de tráfico.
60
5.3.2. Señalización SIP por TCP
Realizaremos la comparación del apartado anterior con el del uso de señalización TCP.
El comportamiento del mismo se ve representado en la Figura 34. Escenario 3. Ajuste de
escala con señalización TCP.
61
6. CONCLUSIONES Y LÍNEAS FUTURAS
Dadas las pruebas realizadas y las diferencias que se pueden observar entre los
escenarios planteados, se concluye que la migración de un switch de comunicaciones VoIP
a Kubernetes es posible, pero su transición no es directa, por lo que harían falta ciertos ajustes
para asegurar la calidad de las llamadas. En este sentido, nos decantamos por una solución
orquestada basada en TCP, que escala mucho mejor en el entorno de Kubernetes. Esto, como
ya hemos dicho, provoca ciertos problemas en la asignación de recursos y la automatización
62
del ajuste de escala, pero es mucho más práctico que el uso de UDP, donde surgen problemas
serios en un caso de aplicación real, con posibles pérdidas imprevistas de llamadas, dificultad
para el registro de las mismas, etc. Todos estos problemas que plantea la señalización UDP
se solucionan automáticamente en el traslado a TCP, debido a las diferencias en su
comportamiento en el contexto del clúster.
También se han observado problemas para realizar balanceo de carga entre elementos
del clúster, lo cual puede deberse a la arquitectura utilizada o a la naturaleza del tráfico
generado. En todo caso, Kubernetes no escala muy bien las conexiones de larga duración,
debido a que no existe un método completamente automatizado (sin herramientas externas)
para trasladar las conexiones entre pod, que acaba en pérdidas de eficiencia por tener
elementos del clúster con una cantidad de recursos asociada que no se equiparan con la
requerida para procesar el tráfico que pasa por ellos, lo cual es otro aspecto sobre el que se
tendría que trabajar para llevar el escenario estudiado a uno real.
Una vez realizado el análisis sobre los resultados obtenidos, se presentan las líneas de
trabajo futuras que servirían como posibles mejoras al trabajo realizado:
63
BIBLIOGRAFÍA
The Kamailio SIP Server Project. (s.f.). [Documentación general sobre la instalación y uso de
Kamailio]. https://www.kamailio.org/w/documentation/
The Kamailio SIP Server Project. (s.f.). [Archivo público de correos electrónicos de usuarios
de Kamailio en el que se describen problemas conocidos]. https://lists.kamailio.org/
Docker, Inc. (s.f.). [Documentación general sobre la instalación y uso de Docker y Docker
Hub]. https://docs.docker.com/
Google, LLC. (s.f.). [Ejemplo práctico para el ajuste de escala automático de pod en
Kubernetes]. https://cloud.google.com/kubernetes-engine/docs/how-to/horizontal-pod-
autoscaling?hl=es-419