Prólogo
El siguiente es un ejemplo de integración de Kubernetes con el servicio CDN de Edgio Delivery para profesionales experimentados de Kubernetes. Asume un nivel de conocimiento en Kubernetes y conocimiento de protocolos estándar de Internet como TCP, DNS y HTTP/HTTPS. El objetivo final es demostrar una manera de hacer que el servicio CDN de Edgio Delivery aparezca como entrada estándar. El usuario de Kubernetes puede mantener la configuración de entrada en sistemas familiares como Portainer o Terraform.
Kubernetes
Kubernetes.io define Kubernetes como “un sistema de código abierto para automatizar el despliegue, escalado y gestión de aplicaciones en contenedores”. Hay varias maneras de traer un clúster. La forma más rápida y sencilla es aprovechar uno de los muchos proveedores de nube que permiten implementaciones de “un solo clic”.
Los clusters de Kubernetes contienen muchas partes. En la demo, nos centraremos en un subconjunto del total.
Piezas de Kubernetes
- Nodo: Máquina o VM que aloja las cargas de trabajo y los servicios.
- Carga de trabajo: Aplicación simple o compleja
- Pod: Contenedores en los que se está ejecutando el software de la aplicación. Uno o más pods componen una carga de trabajo.
- Servicio: Un mecanismo que expone una carga de trabajo a otras cargas de trabajo o entradas
- Ingreso: Un mecanismo para exponer los servicios al mundo exterior
Edgio
Edgio hace que la vida conectada sea más rápida, segura y sencilla de administrar al impulsar una velocidad, seguridad y simplicidad inigualables en el perímetro con nuestras soluciones de entrega, aplicaciones y streaming perfectamente integradas. Nuestra tecnología a escala mundial y nuestros servicios expertos impulsan las principales marcas del mundo con la capacidad de ofrecer la educación, entretenimiento, eventos y aplicaciones más rápidas, dinámicas y sin fricciones a cada usuario. Dedicado a proporcionar una atención al cliente sin igual y extender valor en cada paso del camino, Edgio es un socio de elección, impulsando el tráfico de Internet en todo el mundo para apoyar los programas, películas, deportes, juegos y música más populares, y sitios web de carga instantánea.
Arquitectura
Edgio Delivery CDN
Para esta demostración, utilizamos el SDK de Edgio python en GitHub – llnw/llnw-sdk-python: Limelight Networks Python SDK. La configuración básica se mantendrá simple.
Al configurar la CDN, se necesitan los siguientes datos (distintos de la autenticación).
- Shortname: Un identificador único dentro de Edgio Delivery CDN que contiene reglas de CDN.
- Published hostname: El nombre de host que se enfrenta a Internet desde la CDN, en el caso de esta demo, el nombre de host cstradtman.s.llnwi.net fue previamente configurado.
- Ruta de URL publicada: La ruta asignada a la regla específica en cuestión.
- Nombre de host de origen: El nombre de host del origen. En este caso, un registro round-robin apunta al clúster de Kubernetes.
- Ruta de URL de origen: La ruta de destino asociada con el nombre de host. En este caso, estará en blanco ya que lo describimos más adelante en este documento. En esta demo, las cargas de trabajo se diferenciarán por número de puerto y no por ruta.
DNS
La demo utiliza la API de Vultr DNS. Configurar la CDN usando direcciones IP como orígenes no es una buena práctica. La demo utiliza una API para crear o modificar un registro round-robin que apunta a los nodos del clúster.
Grupo temático
La demo está en Vultr en un clúster de tres nodos.
Espacios de nombres
La demo existirá bajo el espacio de nombres predeterminado ya que es lo único que se ejecuta en este clúster
Nodos
- Clúster VKE – 3 nodos con cada uno
- 4G RAM
- Disco 80G
- 2 vCPU
- 1 red G
Cargas de trabajo
La carga de trabajo es un simple programa de Python que devuelve información básica sobre la conexión HTTP. Implementamos esta demo en línea, que no es un método de implementación típico. Sin embargo, permite que la demo sea totalmente autónoma en lugar de tener dependencias externas para construir los contenedores y almacenarlos. El código fuente está en el Apéndice 1. El código de Python real está en cursiva, y el código YAML que describe el despliegue no lo está. La carga de trabajo utiliza el puerto TCP 8000.
Servicios
Hay varios tipos de servicios disponibles. Estamos utilizando el tipo de servicio “NodePort”. Expone el servicio en las direcciones IP externas del clúster en un número de puerto alto seleccionado aleatoriamente. Kubernetes se encarga de la conexión a un nodo donde se ejecuta la carga de trabajo.
Entrada
Kubernetes Ingreso es un objeto de software que describe el comportamiento de una colección de recursos que hacen que un servicio de Kubernetes esté disponible fuera del clúster.
Un controlador Ingress combina software y/o hardware que crea instancias del objeto de software Ingress.
Una CDN es un proxy inverso distribuido rico en características, además de la función de proxy inverso, las CDN suelen tener algoritmos de caché flexibles, diversidad geográfica, características de seguridad (ACL (GEO, método, regex), firewalls de aplicaciones web, marcas de agua y otras características más avanzadas que no se encuentran en proxies inversos simples.
Las API para la monitorización de objetos de Kubernetes están bien definidas, y una serie de proxies inversos HTTP y balanceadores de carga se han ampliado para funcionar como controladores Ingress. Por ejemplo, NGINX y HAProxy son proxies de la vieja escuela que se han extendido para funcionar como controladores de ingreso y otros como Traefik e Itsio se desarrollaron en paralelo a Kubernetes. Una CDN es una progresión natural de proxies inversos simples. En el caso de esta demo, crearemos un controlador de entrada personalizado que controla Edgio Delivery CDN. Los datos normalmente requeridos para describir una Ingress es
- Public Hostname: El nombre de host en el que estará disponible el servicio Kubernetes
- Ruta pública: La ruta asociada al nombre de host público en la que estarán disponibles los servicios de Kubernetes
- Nombre del servicio de backend: Nombre del servicio definido por una estrofa de servicios de Kubernetes
- Puerto de backend: Un nombre que coincide con la descripción del puerto en la descripción del servicio
Edgio Delivery Mappings de activos CDN:
Kubernetes |
Edgio Delivery CDN |
Nombre de host público |
Nombre de host publicado |
Vía pública |
Ruta URL publicada |
Nombre del servicio de backend Único dentro del clúster de Kubernetes No conocido/disponible para el mundo exterior |
Nombre de host fuente Nombre de dominio totalmente cualificado En realidad no uno a uno |
La lógica detrás de esto es:
- Escuche el evento de ingreso de espacio de nombres desde el clúster
- Si el tipo de evento es “Añadido”.
- Obtenga la dirección IP de los nodos en el clúster
- Crear registro DNS en vultr
- Cree reglas de CDN en Edgio CDN que apunten hacia los registros DNS creados y el puerto asignado por el servicio NodePort.
- Si el tipo de evento es “Modificado”.
- Encuentre reglas de CDN en Edgio CDN que coincidan con la entrada existente
- Modifique las reglas en Edgio CDN para reflejar nuevos datos en el evento
- Si el tipo de evento es “Deleted”.
- Encuentra reglas de CDN en Edgio CDN que coincidan con la entrada eliminada
- Eliminar registros DNS en Vultr asociados con esta entrada
- Elimine las reglas de CDN en Edgio que coinciden con la entrada eliminada
Configuración
Objetos
Los objetos de Kubernetes se describen en archivos YAML. En Kubernetes, cada configuración es un objeto. Puede colocar todas las configuraciones de implementación en un solo archivo. Es una práctica común dividirlos en función de qué parte del despliegue describen.
Despliegue
En el Apéndice 1, hay un archivo YAML grande que es una combinación de código Python y YAML. Todo después de “spec.template.spec.containers.command” es el código de Python que se convierte en un contenedor durante el despliegue. Desde el punto de vista del objeto Kubernetes las líneas que nos son importantes para la demo son:
- Kind: Deployment – Describe el objeto como un Deployment
- Metadata.name: Nombre es usado por el objeto service para crear el vínculo entre los dos.
- Spec.selector.matchlabels.app: indica a qué pods se aplicará el despliegue.
- Spec.template.spec.containers.image: Apunta a la imagen oficial de python 3 del hub docker
- Spec.template.spec.containers.ports.name: Una etiqueta para el puerto a ser referenciado en el servicio de otros objetos en este caso
- Spec.template.spec.containers.ports.containerport: Enumera el puerto TCP expuesto desde el contenedor en ejecución
Servicio
- Kind: Deployment – Describe el objeto como un Deployment
- Metadata.name: El nombre es usado por el objeto de ingreso para crear el enlace entre los dos.
- Spec.selector.app: apunta al nombre del despliegue: Pywai-inline-service como se nombra en el objeto de despliegue.
- Spec.selector.type: NodePort Esto define este servicio como el tipo NodePort como se describió anteriormente
- Spec.ports.name: La etiqueta para el puerto a ser referenciado por otros objetos (entrada en este caso)
- Spec.ports.protocol: define el protocolo IP en uso – TCP
- Spec.ports.port: Define el puerto expuesto por este servicio
- Spec.ports.targetPort: Apunta al puerto expuesto por la implementación – pywai-inline-deployment en este caso
Entrada
En el Apéndice 3, verá el archivo YAML que describe el objeto Kubernetes para el controlador Edgio Ingreso. Los objetos que deben interesarse son:
- Kind: Ingreso – Esto le dice a Kubernetes que es un objeto Ingress
- Medatdata.name – Todo en Kubernetes debe tener un nombre
- Metadata.labels.cdn – Esta etiqueta se utiliza para indicar al controlador de entrada que este objeto es para el controlador de entrada de edgio
- Spec.rules.host – nombre de host público para exponer el servicio.
- Spec.rules.http.paths.path – Ruta asociada al servicio.
- Spec.rules.http.paths.backend.service.name – etiqueta del servicio a exponer
- Spec.rules.http.paths.backend.service.port.name – Etiqueta de puerto del servicio a exponer
Configuración de mapas
Secretos
Kubernetes tiene un concepto incorporado de secretos para el almacenamiento de datos sensibles. Esta demostración aprovecha esto para los nombres de usuario y las claves compartidas tanto para Edgio SDK como para la API de Vultr DNS
Ejemplos de código
El código para esta demostración está incluido en los repos git
- Edgio Delivery python SDK
- Despliegue de demostración de Kubernetes
- https://github.com/llnw/edgio-delivery-k8s-demo
- Estos son una serie de objetos Kubernetes descritos como yaml que muestran cómo implementar la integración de Edgio Delivery
- Edgio Delivery Controlador de entrada demo
- https://github.com/llnw/edgio-delivery-k8s-ingress-demo
- Este es el código real que implementa el controlador de ingreso de Edgio Delivery
- A la larga, debe ejecutarse como un servicio dentro de Kubernetes, sin embargo, para mantener la demostración simple, simplemente se ejecuta como un proceso separado
Futuras adiciones y mejoras al diseño actual
En una publicación futura, mostraremos cómo aprovechar otras soluciones de Edgio, por ejemplo, aplicaciones. Podríamos usar el clúster de Kubernetes como una forma de aprovechar y sincronizar configuraciones entre múltiples ofertas de CDN de Edgio para diferentes flujos de trabajo.
Apéndice 1 – pywai-inline-deployment.yaml
ApiVersion: Apps/v1
Tipo: Despliegue
metadatos:
nombre: pywai-inline-deployment
especificaciones:
selector:
MatchLabels:
aplicación: pywai-inline-deployment
réplicas: 1
plantilla:
metadatos:
etiquetas:
aplicación: pywai-inline-deployment
especificaciones:
contenedores:
– nombre: python
imagen: python:3
orden:
– /bin/sh
– “-c”
– |
CAT > /test.py <<EOF
#!/usr/bin/env python3
“””
Servidor HTTP muy simple en python para las solicitudes de registro
Uso::
./server.py [<puerto>]
“””
Desde http.server importa BaseHTTPRequestHandler, HTTPServer
registro de importación
importar pprint
Clase S(BaseHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header(‘Content-type’, «text/html»)
self.end_headers()
def do_GET(self):
logging.info(“GET Request,\nPath: %S\nHeaders:\n%s\n”, str(self.path), str(pprint.pformat(self.headers))
self._set_response()
headerinfo=pprint.pformat(self.headers.items())
clientinfo=pprint.pformat(self.client_address)
lineinfo=pprint.pformat(self.requestline)
versioninfo=pprint.pformat(self.request_version)
self.wfile.write(“<pre> {} </pre>”.format(headerinfo).encode(‘utf-8’))
self.wfile.write(“<pre> {} </pre>”.format(clientinfo).encode(‘utf-8’))
self.wfile.write(“<pre> {} </pre>”.format(lineinfo).encode(‘utf-8’))
self.wfile.write(“<pre> {} </pre>”.format(versioninfo).encode(‘utf-8’))
def run(server_class=HTTPServer, handler_class=S, port=8080):
Logging.basicConfig(level=logging.INFO)
server_address = (”, puerto)
httpd = server_class(server_address, handler_class)
logging.info(‘Starting httpd…\n’)
pruebe:
httpd.serve_forever()
Excepto KeyboardInterrupt:
pase
httpd.server_close()
logging.info(‘Stopping httpd…\n’)
si __name__ == ‘__main___’:
desde sys import argv
si len(argv) == 2:
run(port=int(argv[1]))
de lo contrario:
run()
EOF
exec python /test.py 8000
puertos:
– nombre: http
ContainerPort: 8000
Apéndice 2 – pywai-inline-service.yaml
ApiVersion: v1
Tipo: Servicio
metadatos:
nombre: pywai-inline-service
especificaciones:
selector:
aplicación: pywai-inline-deployment
Tipo: NodePort
puertos:
– nombre: http
protocolo: TCP
puerto: 80
Puerto de destino: 8000
Apéndice 3 – pywai-edgio-ingress.yaml
ApiVersion: Networking.k8s.io/v1
Clase: Ingreso
metadatos:
nombre: externo-pywai-inline-ingress
anotaciones:
kubernetes.io/ingress.class: edgio
etiquetas:
cdn: edgio
especificaciones:
normas:
– Host: <Introduzca el nombre corto único> .s.llnwi.net
http:
rutas:
– ruta: /fred
PathType: Exacto
backend:
servicio:
nombre: external-pywai-inline-service
puerto:
nombre: pywai-port