martes, 31 de octubre de 2017

Usando Ingress en Google Container Engine


Viene de Medium power by Christopher Grant

En este artículo, se cubren una variedad de desafíos a la que se enfrenta  y que soluciones que descubrió al implementar una aplicación real en un clúster Global utilizando el controlador de Ingress GCE. 

Ha cubierto cómo configurar Global Kubernetes en 3 pasos en un artículo separado. Este artículo se centrará en cómo usarlo una vez que esté configurado. En la parte 1, se discutiren los conceptos, y en la parte se realizara una implementación de extremo a extremo con código real.

Contenido:
- Ejemplo simple
- Variaciones
- IP global
- Anotaciones
- Chequeo Health
- Tipo de puerto de nodo y puerto
- Contextos de ruta
- Clúster Equilibrado


Tener varios servicios desplegados que responden bajo un nombre de dominio es una práctica común en aplicaciones más grandes. Con Kubernetes puede exponer Implementaciones como Servicios independientes, utilizando ClusterIPs, NodePort y LoadBalancers. También puede exponer múltiples servicios como una sola entidad virtual utilizando recursos de Ingress.

En teoría, los recursos de Ingress son sencillos y fáciles de usar, pero en la práctica puede haber una curva de aprendizaje más empinada. En este artículo, repasaremos los conceptos básicos de la creación de recursos de Ingress y algunas peculiaridades que se encontraran en la vida real.


Ejemplo simple

Hay tres recursos principales involucrados en este proceso: el despliegue, su servicio y el Ingress en sí. Veamos una simple entrada de Hello World.

De la documentación de Kubernetes para el recurso Ingress, podemos ver muchos de los elementos clave

Ejemplo de  Ingress en formato Yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80

Solo cubriendo lo que está aquí, cualquier solicitud para alojar foo.bar.com será procesada por las reglas contenidas en ese bloque, foo.bar.com/foo enrutará al servicio s1 en el puerto 80, solicitudes a foo.bar.com/bar dirigirá al servicio s2 en el puerto 80.


Variaciones no enumeradas explícitamente en los documentos

Para todos los host

Si no desea tratar con el nombre de host, puede eliminar el valor de host y solo se evaluarán las reglas de ruta para todos los hosts / IP.

Ejemplo de uso

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80

Backend predeterminado

Los documentos muestran una opción de Ingress de Servicio Único y sin reglas. Puede combinar esto con las reglas de ruta para definir su propio back-end predeterminado con reglas adicionales.

Vamos al ejemplo.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: testsvc
    servicePort: 80
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80


Aquí cualquier solicitud a este Ingress con / foo con ir al servicio s1, cualquier solicitud para / bar se enrutará a s2, y todos los demás se enviarán a testsvc

Es importante tener en cuenta que si no define un back-end predeterminado, Kubernetes creará uno detrás de la escena. Además, el backend creado para usted solo existe en un clúster. Lo verá cuando consulte los desarrollos de carga del backend en GCP más adelante.


IP Global

Este es otro punto importante para el Ingress global. Necesitarás crear y usar explícitamente una IP global de Google. Las IP efímeras predeterminadas creadas son solo regionales y no podrán admitir servicios de back-end de diferentes regiones.

Pasé mucho tiempo con esto, NO TE DESPISTES

Desde la línea de comando crea una IP global

gcloud compute addresses create ingress-ip --global

Luego, en tu ficherio ingress.yaml.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    kubernetes.io/ingress.global-static-ip-name: ingress-ip      
    ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: testsvc
    servicePort: 80
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80


Anotaciones en el Ingress

En la sección de metadatos de la definición de Ingress se pueden proporcionar varias anotaciones para ayudar a  kubernetes a comprender mejor sus intenciones.

Controlador de Ingress

Dependiendo de dónde y cómo despliegues kubernetes, puedes elegir qué ejecutará realmente en la definición de ingress yaml que proporciones. Muchos de los documentos se refieren a nginx como el controlador de ingreso, pero para este ejemplo mostraré cómo usar GCE nativo.

Aunque no es obligatorio, es una buena práctica agregar una anotación que indique qué controlador está intentando usar. Esto es útil si hay múltiples opciones dentro de un entorno dado como ejemplo

Como quiero usar GCE para este controlador de Ingress, lo especificaré explícitamente usando la anotación kubernetes.io/ingress.class: “gce” 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
     kubernetes.io/ingress.class: "gce"
    ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: testsvc
    servicePort: 80
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80


Chequeos health

De manera predeterminada, el Ingrees configurará las comprobaciones de estado de loadblancer al hacer ping en la raíz de su servicio. Es importante saber esto en caso de que elija no enrutar "/" en su servicio. Para garantizar que su aplicación registre su estado de health correctamente, proporcione una ruta "/" o configure las sondas Liveness and Readiness para sus necesidades.

Terminé simplemente dejando el contexto root en la aplicación por simplicidad

NodePort

Aquí hay otro elemento que tiene sentido después de trabajarlo. En primer lugar, utilizar el controlador de Ingress GCE requiere un servicio expuesto con NodePort, no puede ser solo ClusterIP. 
En segundo lugar, cuando se despliega en un clúster federado, los puertos de nodo para su contenedor deben ser los mismos en todos los clústeres, por lo que debemos definirlo explícitamente. De forma predeterminada, cada contenedor proporcionaría un puerto aleatorio para el tipo NodePort, pero en un modelo federado, necesitamos que sean iguales para que la verificación de estado sea precisa. Una vez en funcionamiento, verá el chequeo de health consultando el mismo puerto en todos los nodos de su aplicación.

Para definir esto, en la definición del servicio para nuestra implementación, especificaremos los valores exactos que queremos. Aquí hay un ejemplo


apiVersion: v1
kind: Service
metadata:
  name: s1
  labels:
    app: app1
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30041
  selector:
    app: app1


Tendrá que definir un puerto de nodo diferente para cada servicio para que no haya colisiones


Contextos de ruta

Este fue probablemente el problema más complicado al que me enfrenté y solo lo cree con una aplicación real. Hasta ahora, todas las aplicaciones demos y hello world han funcionado bien. / foo rutas a svc1, y / bar a svc2. Cuando desplegué una aplicación real, sin embargo, las cosas no fueron tan claras. 
Me gustaría obtener la página principal para mis servicios, pero todo lo demás volvería al equilibrador de carga predeterminado. Vamos a descubrir que hay una [peculiaridad con ingress] 

(https://github.com/kubernetes/contrib/issues/885) porque los controladores de ingress Nginx y GCE no funcionan igual.

Básicamente en Nginx / foo está buscando cualquier cosa con un prefijo de / foo donde el controlador gce lo vea como un mapeo explícito. Para solucionar esto, necesitamos agregar * mapeos a nuestras rutas de reglas en el ingress.yaml de la siguiente manera:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
     kubernetes.io/ingress.class: "gce"
    ## ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: testsvc
    servicePort: 80
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /foo/*
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80
      - path: /bar/*
        backend:
          serviceName: s2
          servicePort: 80


Al agregar las asignaciones adicionales, cualquier solicitud para /foo o /foo/baz/bar se enrutará correctamente al servicio s1 y las solicitudes para /bar o /bar/baz /foo se enrutarán al servicio s2


Cluster Balancing

En la mayoría de los casos, kubernetes intentará equilibrar los clústeres para que las aplicaciones se distribuyan uniformemente entre los clusters, pero puedes reflejar sus intenciones usando 
federation.kubernetes.io/deployment-preferences:: usando de la siguiente manera

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 4
  template:
    metadata:
      annotations:
        federation.kubernetes.io/deployment-preferences: |
          {
            "rebalance": true,
            "clusters": {
              "east-cluster": {
                  "minReplicas": 1
              },
              "west-cluster": {
                  "minReplicas": 1
              }
            }
          }
      labels:
        app: app1
    spec:
      containers:
        - name: app1
          image: myrepo/appi:v7
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 100Mi



Las anotaciones anteriores le piden a los kubernetes que reequilibren y mantengan un mínimo de una réplica en el este y un mínimo de una réplica en el oeste.

Conclusión

Los controladores de ingreso de Kubernetes son una herramienta poderosa. Con poco conocimiento adicional, se convierten en un recurso simple para administrar también. La utilización del tipo de controlador GCE le permite implementar la entrada rápida y fácilmente en Google Container Engine sin necesidad de recursos adicionales.
Espero que esto haya sido útil y asegúrese de consultar la guía de instalación y la demostración de principio a fin.