1. Te damos la bienvenida
Gracias por unirte a nosotros en el codelab de Istio Multi Cloud Burst de Google.Para realizar este codelab, debes tener experiencia práctica a nivel principiante con Kubernetes, Node y Go. Requisitos
|
|
Qué aprenderá
- Cómo crear un clúster de Kubernetes en GKE
- Cómo instalar Istio en un clúster de Kubernetes con Helm
- Cómo instalar Istio multiclúster con Helm
- Implementa una aplicación web desde la fuente a Kubernetes
- Cómo escribir y aplicar reglas de enrutamiento de tráfico a Istio
- Métricas de Prometheus
- Compila y envía imágenes de contenedores dentro de un clúster de Kubernetes
2. Cómo prepararte
Puedes seguir este codelab en cualquiera de los siguientes entornos:
- Google Cloud Shell (recomendado): Shell integrado en el navegador, viene con herramientas instaladas
- tu laptop (sigue las instrucciones que se indican a continuación)
Comienza con Google Cloud Platform
- Si no tienes una cuenta de GCP, pide al instructor que te entregue la tarjeta de cuenta de usuario gratuita.
- Ve a la consola de Google Cloud y haz clic en "Seleccionar un proyecto":

- Toma nota del "ID" del proyecto en algún lugar y, luego, haz clic en el proyecto para elegirlo:

Opción 1: Usa Google Cloud Shell (recomendado)
Cloud Shell proporciona una shell de línea de comandos dentro de tu navegador con las herramientas que necesitas instaladas y autenticadas automáticamente en tu cuenta de Google Cloud Platform. (Si no deseas ejecutar este ejercicio en Cloud Shell, ve a la siguiente sección).
Ve a Cloud Console y haz clic en "Activar Cloud Shell" en la barra de herramientas de la esquina superior derecha:

Agrega herramientas a Cloud Shell
- Instala
kubectx****: Descarga las secuencias de comandos de Bash desde aquí a una ubicación en $PATH. - Instala
helm****: Sigue estas instrucciones.
Como alternativa, ejecuta estos comandos para instalar ambos en ~/.bin y agregarlos a tu $PATH:
mkdir -p ~/.bin && \
cd ~/.bin && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubectx && \
chmod +x kubectx && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubens && \
chmod +x kubens && \
curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz && \
tar xzf helm-v2.12.0-linux-amd64.tar.gz && \
rm helm-v2.12.0-linux-amd64.tar.gz && \
mv linux-amd64/helm ./helm && \
rm -r linux-amd64 && \
export PATH=${HOME}/.bin:${PATH}
Estas son algunas sugerencias rápidas que pueden facilitar el uso de Cloud Shell:
1. Separa la shell en una ventana nueva: |
|
2. Con el editor de archivos: Haz clic en el ícono de lápiz en la parte superior derecha para iniciar un editor de archivos en el navegador. Esto te resultará útil, ya que copiaremos fragmentos de código en archivos. |
|
3. Iniciar pestañas nuevas: Si necesitas más de una instrucción de la terminal. |
|
4. Agrandar el texto: El tamaño de fuente predeterminado en Cloud Shell puede ser demasiado pequeño para leerlo. | Ctrl + en Linux o Windows, ⌘ + en macOS. |
Opción 2: Configura tu laptop (no recomendado)
Si te sientes más cómodo usando tu propio entorno de estación de trabajo que Cloud Shell, configura las siguientes herramientas:
- Instala
gcloud:(preinstalado en Cloud Shell). Sigue las instrucciones para instalargclouden tu plataforma. Lo usaremos para crear un clúster de Kubernetes. - Instala
kubectl:(preinstalado en Cloud Shell). Ejecuta el siguiente comando para instalar:
gcloud components install kubectl
Ejecuta el siguiente comando para autenticar gcloud. Se te pedirá que accedas con tu Cuenta de Google. Luego, elige el proyecto creado previamente (que se muestra arriba) como el proyecto predeterminado. (Puedes omitir la configuración de una zona de procesamiento):
gcloud init
- Instala
curl:. Está preinstalado en la mayoría de los sistemas Linux/macOS. Es probable que ya lo tengas. De lo contrario, busca en Internet cómo instalarlo. - Instala
kubectx****: Descarga las secuencias de comandos de Bash desde aquí a una ubicación en $PATH. - Instala
helm****: Sigue estas instrucciones.
3. Configura el proyecto de GCP
Habilita las APIs de GKE (Google Kubernetes Engine), GCR (Google Container Registry) y GCB (Google Cloud Build) en tu proyecto:
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
Configura las variables de entorno
Trabajaremos mucho con nuestro proyecto de Google Cloud durante la configuración. Establezcamos una variable de entorno para consultarla rápidamente.
export GCLOUD_PROJECT=$(gcloud config get-value project)
Crearemos algunos archivos de código y configuración durante este taller, así que crearemos un directorio de proyecto y lo cambiaremos.
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. Crea un clúster de Kubernetes "principal"
Puedes crear fácilmente un clúster de Kubernetes administrado con Google Kubernetes Engine (GKE).
El siguiente comando creará un clúster de Kubernetes:
- llamado "primary",
- en la zona us-west1-a,
- La versión más reciente de Kubernetes disponible
- con 4 nodos iniciales
export cluster=primary
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(Este proceso puede tardar alrededor de 5 minutos. Puedes observar cómo se crea el clúster en Cloud Console.
Después de crear el clúster de Kubernetes, gcloud configura kubectl con las credenciales que apuntan al clúster.
gcloud container clusters get-credentials $cluster --zone=$zone
Ahora deberías poder usar kubectl con tu clúster nuevo.
Ejecuta el siguiente comando para obtener una lista de los nodos de Kubernetes de tu clúster (deberían mostrar el estado "Listo"):
kubectl get nodes
Modifica los nombres de Kubeconfig para facilitar su uso
Cambiaremos de contexto con frecuencia, por lo que es útil tener un alias corto para nuestros clústeres.
Este comando cambiará el nombre de la entrada de kubeconfig que acabas de crear a primary.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Establece permisos:
Para implementar Istio, debes ser administrador del clúster. Este comando establecerá el correo electrónico asociado con tu cuenta de Google Cloud como el administrador del clúster.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
5. Crea un clúster "burst"
El siguiente comando creará un clúster de Kubernetes:
- llamada "burst",
- en la zona us-west1-a,
- La versión más reciente de Kubernetes disponible
- Con 1 nodo inicial
- Ajuste de escala automático habilitado para hasta 5 nodos
export cluster=burst
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "1" --enable-autoscaling --min-nodes=1 --max-nodes=5 \
--network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(Este proceso puede tardar alrededor de 5 minutos. Puedes observar cómo se crea el clúster en Cloud Console.
Después de crear el clúster de Kubernetes, gcloud configura kubectl con las credenciales que apuntan al clúster.
gcloud container clusters get-credentials $cluster --zone=$zone
Ahora deberías poder usar kubectl con tu clúster nuevo.
Ejecuta el siguiente comando para obtener una lista de los nodos de Kubernetes de tu clúster (deberían mostrar el estado "Listo"):
kubectl get nodes
Modifica los nombres de Kubeconfig para facilitar su uso
Este comando modificará la entrada de kubeconfig que acabas de crear en burst.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
Establece permisos:
Para implementar Istio Remote, debes ser administrador del clúster. Este comando establecerá el correo electrónico asociado con tu cuenta de Google Cloud como el administrador del clúster.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. Aplica reglas de firewall
Para que nuestros dos clústeres se comuniquen entre sí, necesitaremos crear una regla de firewall.
Ejecuta los siguientes comandos para crear una regla de firewall en Google Cloud Platform que permita que nuestros clústeres se comuniquen.
function join_by { local IFS="$1"; shift; echo "$*"; }
ALL_CLUSTER_CIDRS=$(gcloud container clusters list \
--filter="(name=burst OR name=primary) AND zone=$zone" \
--format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list \
--filter="(metadata.cluster-name=burst OR metadata.cluster-name=primary) AND metadata.cluster-location=us-west1-a" \
--format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
gcloud compute firewall-rules create istio-multicluster-test-pods \
--allow=tcp,udp,icmp,esp,ah,sctp \
--direction=INGRESS \
--priority=900 \
--source-ranges="${ALL_CLUSTER_CIDRS}" \
--target-tags="${ALL_CLUSTER_NETTAGS}" --quiet
Tenemos ambos clústeres configurados y listos para implementar nuestra aplicación y Istio en ellos.
7. Introducción a Istio
¿Qué es Istio?
Istio es un plano de control de malla de servicios que tiene como objetivo "conectar, proteger, controlar y observar servicios". Lo hace de varias maneras, pero principalmente agregando un contenedor de proxy ( Envoy) a cada uno de tus pods de Kubernetes implementados. El contenedor de proxy controla toda la comunicación de red entre microservicios en conjunto con un centro de telemetría y una política de uso general ( Mixer).

Estas políticas se pueden aplicar independientemente de tus implementaciones y servicios de Kubernetes, lo que significa que el operador de red puede observar la actividad de la red, restringir, redireccionar o reescribir las políticas de red sin volver a implementar las aplicaciones asociadas.
Estas son algunas de las funciones de administración de tráfico que admite Istio:
- Disyuntores
- División de tráfico basada en el porcentaje
- Reescritura de URL
- finalización de TLS
- Verificaciones de estado
- Balanceo de cargas
A los efectos de este taller, nos enfocaremos en la división del tráfico basada en porcentajes.
Términos de Istio con los que trabajaremos
VirtualService
Un VirtualService define un conjunto de reglas de enrutamiento de tráfico que se aplican cuando se dirige un host.
Puerta de enlace
Una puerta de enlace es un balanceador de cargas que opera en el perímetro de la malla que recibe conexiones HTTP/TCP entrantes o salientes. Las puertas de enlace pueden especificar puertos, configuraciones de SNI, etcétera.
Regla del destino
Un DestinationRule define las políticas que se aplican al tráfico destinado a un servicio después de que se produce el enrutamiento. Especifican la configuración para el balanceo de cargas, el tamaño del grupo de conexiones del sidecar y la configuración de detección de valores atípicos.
Istio multiclúster
Es posible que hayas notado cuando creamos nuestros dos clústeres que nuestro clúster de primary tenía 4 nodos sin ajuste de escala automático y nuestro clúster de burst tenía 1 nodo con ajuste de escala automático de hasta 5 nodos.
Existen dos motivos para esta configuración.
Primero, queremos simular una migración de "local" a Cloud. En un entorno local, no tienes acceso a los clústeres de ajuste de escala automático, ya que tienes una infraestructura fija.
En segundo lugar, una configuración de 4 nodos (como se definió anteriormente) es el requisito mínimo para ejecutar Istio. Esto plantea la pregunta: si Istio requiere un mínimo de 4 nodos, ¿cómo puede nuestro clúster de burst ejecutar Istio con 1 nodo? La respuesta es que Istio Multicluster instala un conjunto mucho más pequeño de los servicios de Istio y se comunica con la instalación de Istio en el clúster principal para recuperar las reglas de políticas y publicar información de telemetría.
8. Descripción general de la arquitectura de la aplicación
Descripción general de los componentes
Implementaremos una aplicación de tres niveles con NodeJS y Redis.
Trabajador
La aplicación de trabajo está escrita en NodeJS y escuchará las solicitudes HTTP POST entrantes, realizará una operación de hash en ellas y, si se define una variable de entorno llamada PREFIX, agregará el hash con ese valor al principio. Una vez que se calcula el hash, la aplicación envía el resultado en el canal "calculation" en el servidor de Redis especificado.
Más adelante, usaremos la variable de entorno PREFIX para demostrar la funcionalidad de varios clústeres.
A modo de referencia, estos son los paquetes que usa la aplicación.
body-parser:nos permite analizar nuestras solicitudes HTTP.cors:Permite el uso del uso compartido de recursos entre dominios.dotenv:Análisis sencillo de variables de entornoexpress:Hosting de sitios web fácilioredis:Biblioteca cliente para comunicarse con bases de datos de Redismorgan:Proporciona un registro estructurado agradable.
Frontend
Nuestro frontend también es una aplicación de NodeJS que aloja una página web con Express. Toma una frecuencia ingresada por el usuario y envía solicitudes a nuestra aplicación worker a esa velocidad. Esta aplicación también se suscribe a mensajes en un canal de Redis llamado "calculation" y muestra los resultados en una página web.
La aplicación usa las siguientes dependencias.
body-parser:nos permite analizar nuestras solicitudes HTTP.dotenv:Análisis sencillo de variables de entornoexpress:Hosting de sitios web fácilioredis:Biblioteca cliente para comunicarse con bases de datos de Redismorgan:Proporciona registros estructurados agradables.request:Permite realizar solicitudes HTTP.socket.io:Permite la comunicación bidireccional de la página web al servidor.
Esta página web usa Bootstrap para aplicar diseño y, cuando se ejecuta, se ve de la siguiente manera:

Diagrama de arquitectura

Diagrama de implementación
Implementaremos nuestra aplicación final en los dos clústeres que creamos. El clúster de primary tendrá todos los componentes (frontend, worker y Redis) implementados, pero el clúster de burst solo tendrá implementada la aplicación worker.
A continuación, se muestra un diagrama que describe los dos clústeres. Los cuadros delineados en rojo son los servicios de Kubernetes, y los delineados en azul son las implementaciones de Kubernetes. Los cuadros amarillos representan nuestra instalación de Istio.
Observa cómo el clúster burst aún tiene un servicio para Redis implementado, a pesar de que no hay ninguna implementación para Redis en el clúster. Necesitamos tener este servicio en el clúster para que el DNS de Kubernetes pueda resolver la solicitud, pero cuando se realice la solicitud, el proxy de Istio redireccionará la solicitud a la implementación de Redis en el clúster primary.
La aplicación final tendrá una implementación adicional que se ejecutará en el clúster primary llamado istiowatcher.. Esto nos permitirá redireccionar el tráfico de forma dinámica a burst automáticamente cuando nuestro tráfico supere un umbral determinado.

9. Crea archivos de implementación de la aplicación
Necesitamos crear un conjunto de manifiestos de Kubernetes para implementar nuestra aplicación.
Cambia al directorio raíz del proyecto y crea una carpeta nueva llamada kubernetes.
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
Escribe frontend.yaml
Esto creará un objeto Deployment y un objeto Service de Kubernetes para acceder a nuestra imagen de frontend.
Inserta lo siguiente en frontend.yaml.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend-deployment
labels:
app: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: gcr.io/istio-burst-workshop/frontend
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PROCESSOR_URL
value: "http://worker-service"
- name: REDIS_URL
value: "redis-cache-service:6379"
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
Aspectos clave que debes tener en cuenta en Deployment
- Especificamos que el puerto en el que se ejecutará la aplicación sea
8080. - Establecimos la dirección del trabajador como “
http://worker-service” y usaremos la función de DNS integrada de Kubernetes para resolver el servicio resultante. - Establecimos la dirección de nuestro
REDIS_URLcomo "redis-cache-service:6379" y usaremos la función de DNS integrada de Kubernetes para resolver las direcciones IP resultantes. - También configuramos los sondeos
livenessyreadinessen el contenedor para ayudar a informar a Kubernetes cuando el contenedor está en funcionamiento.
Escribe worker-service.yaml
Escribimos la definición del servicio de Kubernetes en un archivo independiente de la definición de Deployment, ya que volveremos a usar este servicio en varios clústeres, pero escribiremos un Deployment diferente para cada clúster.
Inserta lo siguiente en worker-service.yaml
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
Escribe worker-primary.yaml
Esta será la implementación de worker que enviaremos al clúster principal.
Inserta lo siguiente en worker-primary.yaml.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: primary-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
Ten en cuenta que, en este caso, seguimos el mismo patrón de proporcionar sondas liveness y readiness, así como especificar las variables de entorno PORT y REDIS_URL para que las use nuestra aplicación.
Otro aspecto que se debe tener en cuenta en esta implementación es la falta de la variable de entorno PREFIX. Esto significa que los resultados de nuestro cálculo serán valores hash sin procesar (sin prefijos).
El punto clave final de esta implementación es la etiqueta cluster-type: primary-cluster. Lo usaremos más adelante cuando realicemos el enrutamiento de tráfico en Istio multiclúster.
Escribe redis.yaml
La comunicación de nuestro trabajador al frontend se realiza a través de un canal de Redis y, por lo tanto, debemos implementar una aplicación de Redis en nuestro clúster.
Inserta lo siguiente en redis.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
template:
metadata:
labels:
app: redis-cache
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
Esta es una implementación semiestándar de una aplicación de Redis. Inicia un contenedor basado en la imagen redis:alpine, expone los puertos adecuados y establece límites de recursos razonables.
Escribe redis-service.yaml
Necesitamos un servicio de Kubernetes para comunicarnos con nuestra aplicación de Redis.
Inserta lo siguiente en redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
Esto proporciona un servicio llamado redis-cache-service para acceder a nuestra implementación de Redis.
10. Implementa la aplicación
Con nuestras imágenes enviadas a GCR y nuestros manifiestos de Kubernetes escritos, este es un buen momento para implementar nuestra aplicación y ver cómo funciona.
Ejecuta los siguientes comandos para implementar la aplicación.
- Asegúrate de que estamos en el clúster correcto
kubectx primary
- Implementa Redis Cache
kubectl apply -f redis.yaml
- Implementa el servicio de Redis
kubectl apply -f redis-service.yaml
- Implementa el frontend
kubectl apply -f frontend.yaml
- Implementa el trabajador
kubectl apply -f worker-primary.yaml
- Implementa el servicio de trabajador
kubectl apply -f worker-service.yaml
Ya implementamos nuestra aplicación en GKE. ¡Felicitaciones!
Prueba
Espera a que los pods estén en línea.
kubectl get pods -w
Una vez que todos los pods estén en "Running", presiona Ctrl + C.
NAME READY STATUS RESTARTS AGE frontend-deployment-695d95fbf7-76sd8 1/1 Running 0 2m redis-cache-7475999bf5-nxj8x 1/1 Running 0 2m worker-deployment-5b9cf9956d-g975p 1/1 Running 0 2m
Notarás que no expusimos nuestro frontend a través de un LoadBalancer. Esto se debe a que más adelante accederemos a la aplicación a través de Istio. Para probar que todo esté en funcionamiento, usaremos kubectl port-forward. Ejecuta el siguiente comando para reenviar el puerto 8080 de tu máquina local (o Cloud Shell) al puerto 8080 que ejecuta la implementación de frontend.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
Si ejecutas la app de forma local, abre un navegador web y dirígete a http://localhost:8080.
Si ejecutas la app en Cloud Shell: Haz clic en el botón "Vista previa en la Web" y selecciona "Vista previa en el puerto 8080".

Deberías ver el frontend. Si ingresas un número en el cuadro "frecuencia", deberías ver que comienzan a aparecer los valores hash.

¡Felicitaciones! Ya está todo listo.
Presiona Ctrl+C para dejar de redirigir el puerto.
11. Limpieza de la aplicación implementada
Aplicaremos Istio a nuestro clúster y, luego, volveremos a implementar nuestra aplicación. Por lo tanto, primero debemos limpiar nuestra aplicación actual.
Ejecuta los siguientes comandos para borrar todas las implementaciones y los servicios que acabas de crear.
- Borrar
redis-cache-service
kubectl delete -f redis-service.yaml
- Borrar
redis
kubectl delete -f redis.yaml
- Borrar
frontend
kubectl delete -f frontend.yaml
- Borrar
worker
kubectl delete -f worker-primary.yaml
- Borrar
worker-service
kubectl delete -f worker-service.yaml
12. Instala Istio en el clúster principal
Obtén Istio
Las versiones de Istio se alojan en GitHub. Los siguientes comandos descargarán la versión 1.0.0 de istio y la descomprimirán.
- Cambia a la raíz de tu proyecto
cd ${proj}
- Descarga el archivo
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- Extrae y quita el archivo
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
Crea una plantilla de Istio
Si ejecutas el siguiente comando de Helm, se creará la plantilla para instalar Istio en tu clúster.
helm template istio-1.0.0/install/kubernetes/helm/istio \ --name istio --namespace istio-system \ --set prometheus.enabled=true \ --set servicegraph.enabled=true > istio-primary.yaml
Se creará un archivo llamado istio-primary.yaml en tu directorio actual que contiene todas las definiciones y especificaciones necesarias para implementar y ejecutar Istio.
Observa los dos parámetros --set. Estos agregan compatibilidad con Prometheus y ServiceGraph al sistema de Istio. Más adelante en el lab, usaremos el servicio de Prometheus.
Implementa Istio
Para implementar Istio, primero debemos crear un espacio de nombres llamado istio-system en el que se puedan ejecutar las implementaciones y los servicios de Istio.
kubectl create namespace istio-system
Por último, aplica el archivo istio-primary.yaml que creamos con Helm.
kubectl apply -f istio-primary.yaml
Espacio de nombres predeterminado de la etiqueta
Istio funciona inyectando un servicio de proxy de sidecar en cada una de tus implementaciones. Esto se hace de forma optativa, por lo que debemos etiquetar nuestro espacio de nombres default con istio-injection=enabled para que Istio pueda insertar automáticamente el sidecar por nosotros.
kubectl label namespace default istio-injection=enabled
¡Felicitaciones! Tenemos un clúster en funcionamiento con Istio listo para implementar nuestra aplicación.
13. Implementa nuestra aplicación con la administración de tráfico de Istio
Crea archivos de configuración de la administración de tráfico de Istio
Istio funciona de manera similar a Kubernetes, ya que usa archivos yaml para la configuración. En ese sentido, debemos crear un conjunto de archivos que le indiquen a Istio cómo exponer y enrutar nuestro tráfico.
Crea un directorio llamado istio-manifests y cámbialo
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
Escribe frontend-gateway.yaml
Este archivo expondrá nuestro clúster de Kubernetes de una manera similar a un LoadBalancer de GKE y enrutará todo el tráfico entrante a nuestro servicio de frontend.
Crea un archivo llamado frontend-gateway.yaml y, luego, inserta lo siguiente:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: frontend-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress-virtual-service
spec:
hosts:
- "*"
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend-service
port:
number: 80
Escribe redis-virtualservice.yaml
Crea un archivo llamado redis-virtualservice.yaml y, luego, inserta lo siguiente:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: redis-virtual-service
spec:
hosts:
- redis-cache-service
gateways:
- mesh
tcp:
- route:
- destination:
host: redis-cache-service.default.svc.cluster.local
Escribe worker-virtualservice.yaml
Crea un archivo llamado worker-virtualservice.yaml y, luego, inserta lo siguiente:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
port:
number: 80
Implementa políticas de administración de tráfico de Istio
La implementación de las políticas de Istio se realiza de la misma manera que otros recursos de Kubernetes, con kubectl apply.
- Aplica nuestra puerta de enlace
kubectl apply -f frontend-gateway.yaml
- Aplica nuestro VirtualService de Redis
kubectl apply -f redis-virtualservice.yaml
- Aplica nuestro VirtualService de trabajador
kubectl apply -f worker-virtualservice.yaml
Implementa la aplicación
- Regresa a nuestro directorio
kubernetes
cd ${proj}/kubernetes
- Implementa Redis Cache
kubectl apply -f redis.yaml
- Implementa el servicio de Redis
kubectl apply -f redis-service.yaml
- Implementa el frontend
kubectl apply -f frontend.yaml
- Implementa el trabajador
kubectl apply -f worker-primary.yaml
- Implementa el servicio de trabajador
kubectl apply -f worker-service.yaml
Verificar
En este punto, volvimos a implementar nuestra aplicación en un clúster con Istio y políticas de administración de tráfico.
Esperemos a que todas nuestras cargas de trabajo estén en línea
Una vez que estén todos en línea, obtén la puerta de enlace de Ingress que configuramos en frontend-ingressgateway.yaml.
$ kubectl -n istio-system get svc istio-ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.36.3.112 35.199.158.10 80:31380/TCP,
Navega a la dirección <EXTERNAL-IP> o usa curl y deberías ver el frontend.
$ curl 35.199.158.10
<!doctype html>
<html>
<head>
<title>String Hashr</title>
<!-- Bootstrap -->
...
14. Instala Istio en un clúster "burst"
Pasamos mucho tiempo configurando y realizando implementaciones en nuestro clúster de primary, pero tenemos otro clúster completo en el que implementar.
En esta sección, necesitaremos obtener variables de configuración de ambos clústeres, así que presta mucha atención al clúster al que nos dirigimos para cada comando.
Crea el manifiesto remoto de Istio
Al igual que cuando implementamos Istio en el clúster primary, usaremos Helm para crear una plantilla de nuestra implementación de Istio remoto en el clúster burst. Sin embargo, antes de hacerlo, necesitamos obtener información sobre nuestro clúster de primary.
Cómo recopilar información del clúster principal
Cambia al clúster primary
kubectx primary
Los siguientes comandos recuperan las direcciones IP de varios pods en el clúster principal. Istio Remote las usa para comunicarse con el clúster principal.
export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')
Crea una plantilla remota
Ahora, usaremos helm para crear un archivo llamado istio-remote-burst.yaml, que luego podremos implementar en el clúster burst.
Cómo cambiar a la raíz del proyecto
cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \
--name istio-remote \
--set global.remotePilotAddress=${PILOT_POD_IP} \
--set global.remotePolicyAddress=${POLICY_POD_IP} \
--set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set global.proxy.envoyStatsd.enabled=true \
--set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \
--set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml
Instala Istio Remote en el clúster de ráfaga
Para instalar Istio en nuestro clúster burst, debemos seguir los mismos pasos que cuando lo instalamos en el clúster primary, pero debemos usar el archivo istio-remote-burst.yaml.
Cómo cambiar kubecontext a burst
kubectx burst
Crea el espacio de nombres istio-system
kubectl create ns istio-system
Aplica istio-burst.yaml
kubectl apply -f istio-remote-burst.yaml
Espacio de nombres predeterminado de la etiqueta
Una vez más, debemos etiquetar el espacio de nombres default para que se pueda insertar automáticamente el proxy.
kubectl label namespace default istio-injection=enabled
¡Felicitaciones! En este punto, configuramos Istio Remote en el clúster burst. Sin embargo, en este punto, los clústeres aún no pueden comunicarse. Necesitamos generar un archivo kubeconfig para el clúster burst que podamos implementar en el clúster primary para vincularlos.
Crea un archivo kubeconfig para el clúster "burst"
Cambia al clúster de ráfaga
kubectx burst
Configura el entorno
Necesitamos recopilar información sobre el clúster para crear un archivo kubeconfig para él.
- Obtén el nombre del clúster
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- Obtén el nombre del servidor del clúster
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
- Obtén el nombre del secreto de la AC de la cuenta de servicio
istio-multi
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- Obtén los datos de la AC almacenados en el secreto anterior
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- Obtén el token almacenado en el secreto anterior
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
Crea un archivo kubeconfig
Con todas esas variables de entorno configuradas, debemos crear nuestro archivo kubeconfig.
cat <<EOF > burst-kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${CA_DATA}
server: ${SERVER}
name: ${CLUSTER_NAME}
contexts:
- context:
cluster: ${CLUSTER_NAME}
user: ${CLUSTER_NAME}
name: ${CLUSTER_NAME}
current-context: ${CLUSTER_NAME}
kind: Config
preferences: {}
users:
- name: ${CLUSTER_NAME}
user:
token: ${TOKEN}
EOF
Se creará un archivo nuevo llamado burst-kubeconfig en tu directorio actual que el clúster de primary podrá usar para autenticar y administrar el clúster de burst.
Cómo volver al clúster principal
kubectx primary
Aplica el kubeconfig para "burst". Para ello, crea un secreto y etiquétalo.
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
Etiqueta el secreto para que Istio sepa que debe usarlo para la autenticación de varios clústeres
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
¡Felicitaciones! Tenemos ambos clústeres autenticados y comunicándose entre sí a través de Istio Multicluster. Implementemos nuestra aplicación en varios clústeres
15. Implementa una aplicación entre clústeres
Crea implementaciones
Cambia al directorio kubernetes.
cd ${proj}/kubernetes
Crea una implementación de trabajador para el clúster "burst": worker-burst.yaml
Crea un archivo llamado worker-burst.yaml y, luego, inserta el siguiente contenido:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: burst-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
Observa que esto es casi idéntico al archivo worker-primary.yaml que creamos antes. Existen dos diferencias clave.
La primera diferencia clave es que agregamos la variable de entorno PREFIX con el valor "bursty-".
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
Esto significa que nuestro trabajador en el clúster burst agregará el prefijo "bursty-" a todos los valores hash que envíe. Podemos usar esto para saber que nuestra aplicación es realmente multiclúster.
La segunda diferencia clave es que cambiamos la etiqueta cluster-type de esta implementación de primary-cluster a burst-cluster.
labels:
app: worker
cluster-type: burst-cluster
Usaremos esta etiqueta más adelante cuando actualicemos nuestro VirtualService.
Cómo modificar los servicios de Istio
En este momento, nuestros servicios de Istio no aprovechan ambas implementaciones. El 100% de nuestro tráfico se enruta al clúster "principal". Cambiemos eso.
Cambia al directorio istio-manifests
cd ${proj}/istio-manifests
Edita worker-virtualservice.yaml para incluir DestinationRules
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 50
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 50
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
Puedes ver que agregamos un segundo destino a nuestro VirtualService. Aún hace referencia al mismo host (worker-service.default.svc.cluster.local)), pero el 50% del tráfico se enruta al subconjunto primary y el otro 50% al subconjunto burst.
Definimos el subconjunto primary como las implementaciones que tienen la etiqueta cluster-type: primary-cluster y el subconjunto burst como las implementaciones que tienen la etiqueta cluster-type: burst-cluster.
Esto divide nuestro tráfico de manera eficaz en partes iguales entre los dos clústeres.
Implementa en el clúster
Implementa redis-service.yaml en el clúster de aumento
Cambia a kubeconfig de burst
kubectx burst
Cambia a la raíz de nuestro proyecto
cd ${proj}
Luego, implementa
Implementa redis-service.yaml en el clúster de aumento
kubectl apply -f kubernetes/redis-service.yaml
Implementa worker-burst.yaml en el clúster de aumento
kubectl apply -f kubernetes/worker-burst.yaml
Implementa worker-service.yaml en el clúster de aumento
kubectl apply -f kubernetes/worker-service.yaml
Aplica VirtualServices de Istio
Cambia a kubeconfig de primary
kubectx primary
Luego, implementa
kubectl apply -f istio-manifests/worker-virtualservice.yaml
Verifica que funcione
Para verificar que funcione, navega a tu punto de entrada de Istio y observa que alrededor del 50% de los valores hash tienen el prefijo “burst-”.

Esto significa que estamos hablando correctamente entre clústeres. Intenta cambiar los pesos en los diferentes servicios y aplicar el archivo worker-virtualservice.yaml. Esta es una excelente manera de equilibrar el tráfico entre los clústeres, pero ¿qué sucede si podemos hacerlo automáticamente?
16. Aprovecha las métricas de Prometheus
Introducción a Prometheus
Prometheus es un kit de herramientas de alerta y supervisión de sistemas de código abierto que se compiló originalmente en SoundCloud. Mantiene un modelo de datos multidimensional con datos de series temporales identificados por nombre de métrica y pares clave-valor.
A modo de referencia, este es el diagrama de la arquitectura de Prometheus:

Cuando se implementa con Prometheus, Istio informa automáticamente varias métricas al servidor de Prometheus. Podemos usar estas métricas para administrar nuestros clústeres sobre la marcha.
Explorando nuestras métricas de Prometheus
Para comenzar, debemos exponer la implementación de Prometheus.
Navega a la pestaña Cargas de trabajo en GKE y desplázate hasta la carga de trabajo "prometheus".

Una vez que veas los detalles de la implementación, ve a Acciones -> Exponer.

Elige reenviar al puerto 9090 y escribe "Balanceador de cargas".

Y elige "Exponer".
Se creará un servicio en una dirección IP de acceso público que podemos usar para explorar nuestras métricas de Prometheus.
Espera a que el extremo esté en funcionamiento y, luego, haz clic en la dirección IP junto a "Extremos externos". 
Ahora deberías ver la IU de Prometheus.

Prometheus proporciona suficientes métricas para ser su propio taller. Por ahora, comenzaremos por explorar la métrica istio_requests_total.
Si ejecutas esa consulta, se mostrarán muchos datos. Son métricas de todas las solicitudes que pasan por la malla de servicios de Istio, y eso es mucho. Cambiaremos nuestra expresión para filtrar lo que realmente nos interesa:
Solicitudes en las que el servicio de destino es worker-service.default.svc.cluster.local y cuya fuente es frontend-deployment limitada a los últimos 15 segundos
Esa consulta se ve de la siguiente manera:
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
Y nos brinda un conjunto de datos mucho más manejable con el que trabajar.

Pero aún es un poco densa. Queremos conocer las solicitudes por segundo, no todas las solicitudes.
Para obtener eso, podemos usar la función rate integrada.
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

Esto nos acerca más, pero debemos reducir esas métricas un poco más en un grupo lógico.
Para ello, podemos usar las palabras clave sum y by para agrupar y sumar nuestros resultados.
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)

¡Perfecto! Podemos obtener las métricas exactas que necesitamos de Prometheus.
Nuestra consulta final de Prometheus
Con todo lo que aprendimos, la consulta final que debemos hacer a Prometheus es
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)
Ahora podemos usar su API de HTTP para obtener la métrica.
Podemos consultar su API con nuestra consulta si realizamos una solicitud HTTP GET de la siguiente manera. Reemplaza <prometheus-ip-here>
curl http://<prometheus-ip-here>/api/v1/query?query=sum\(rate\(istio_requests_total%7Breporter%3D%22destination%22%2C%0Adestination_service%3D%22worker-service.default.svc.cluster.local%22%2C%0Asource_workload%3D%22frontend-deployment%22%7D%5B15s%5D\)\)%20by%20\(source_workload%2C%0Asource_app%2C%20destination_service\)
Esta es una respuesta de ejemplo:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"destination_service": "worker-service.default.svc.cluster.local",
"source_app": "frontend",
"source_workload": "frontend-deployment"
},
"value": [
1544404907.503,
"18.892886390062788"
]
}
]
}
}
Ahora, podemos extraer nuestro valor de métrica del JSON.
Haz limpieza
Debemos borrar el servicio que acabamos de usar para exponer Prometheus. En la consola de Google Cloud, ve a la parte superior del servicio que acabamos de crear y haz clic en "Borrar".

Próximos pasos:
Después de encontrar una forma de descubrir cómo se mueve el tráfico a través del clúster y a qué velocidad, nuestro siguiente paso es escribir un pequeño objeto binario que consulte Prometheus de forma periódica y, si las solicitudes por segundo a worker superan un umbral determinado, aplique diferentes pesos de destino en nuestro servicio virtual de trabajador para enviar todo el tráfico al clúster burst. Una vez que las solicitudes por segundo sean inferiores a un umbral inferior, vuelve a enviar todo el tráfico a primary.
17. Crea un aumento entre clústeres
Configuración
Establece todo el tráfico del servicio de trabajo en el clúster principal
Consideraremos que todo el tráfico destinado a worker-service que se enruta al clúster primary es el estado “predeterminado” de nuestra aplicación.
Edita $proj/istio-manifests/worker-virtualservice.yaml para que se vea de la siguiente manera:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
Asegúrate de estar conectado al clúster de primary.
kubectx primary
Aplica istio-manifests/worker-virtualservice.yaml
kubectl apply -f istio-manifests/worker-virtualservice.yaml
Escribe el daemon de istiowatcher
Usaremos Go para escribir este servicio por su velocidad y portabilidad. El flujo general de la aplicación será iniciarse y, cada segundo, consultar Prometheus.
Crea un directorio nuevo en src llamado istiowatcher.
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
Llamaremos a istioctl desde nuestro contenedor para manipular el plano de control de Istio desde el clúster.
Escribe istiowatcher.go
Crea un archivo en ese directorio llamado istiowatcher.go y, luego, insértale lo siguiente:
package main
import (
"github.com/tidwall/gjson"
"io/ioutil"
"log"
"net/http"
"os/exec"
"time"
)
func main() {
//These are in requests per second
var targetLow float64 = 10
var targetHigh float64 = 15
// This is for the ticker in milliseconds
ticker := time.NewTicker(1000 * time.Millisecond)
isBurst := false
// Our prometheus query
reqQuery := `/api/v1/query?query=sum(rate(istio_requests_total{reporter="destination",destination_service="worker-service.default.svc.cluster.local",source_workload="frontend-deployment"}[15s]))by(source_workload,source_app,destination_service)`
for t := range ticker.C {
log.Printf("Checking Prometheus at %v", t)
// Check prometheus
// Note that b/c we are querying over the past 5 minutes, we are getting a very SLOW ramp of our reqs/second
// If we wanted this to be a little "snappier" we can scale it down to say 30s
resp, err := http.Get("http://prometheus.istio-system.svc.cluster.local:9090" + reqQuery)
if err != nil {
log.Printf("Error: %v", err)
continue
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
val := gjson.Get(string(body), "data.result.0.value.1")
log.Printf("Value: %v", val)
currentReqPerSecond := val.Float()
log.Printf("Reqs per second %f", currentReqPerSecond)
if currentReqPerSecond > targetHigh && !isBurst {
applyIstio("burst.yaml")
log.Println("Entering burst mode")
isBurst = true
} else if currentReqPerSecond < targetLow && isBurst {
applyIstio("natural.yaml")
log.Println("Returning to natural state.")
isBurst = false
}
}
}
func applyIstio(filename string) {
cmd := exec.Command("istioctl", "replace", "-f", filename)
if err := cmd.Run(); err != nil {
log.Printf("Error hit applying istio manifests: %v", err)
}
}
Escribe el Dockerfile
Crea un archivo nuevo llamado Dockerfile y, luego, inserta el siguiente contenido en él.
FROM golang:1.11.2-stretch as base
FROM base as builder
WORKDIR /workdir
RUN curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
RUN tar xzf istio-1.0.0-linux.tar.gz
RUN cp istio-1.0.0/bin/istioctl ./istioctl
FROM base
WORKDIR /go/src/istiowatcher
COPY . .
COPY --from=builder /workdir/istioctl /usr/local/bin/istioctl
RUN go get -d -v ./...
RUN go install -v ./...
CMD ["istiowatcher"]
Este Dockerfile de varias etapas descarga y extrae la versión 1.0.0 de Istio en la primera etapa. La segunda etapa copia todo de nuestro directorio en la imagen y, luego, copia istioctl de la etapa de compilación a /usr/local/bin (para que nuestra aplicación pueda llamarlo), obtiene las dependencias, compila el código y establece CMD como "istiowatcher".
Escribe burst.yaml
Este es el archivo que istiowatcher aplicará cuando las solicitudes por segundo a worker desde frontend superen las 15.
Crea un archivo nuevo llamado burst.yaml y, luego, inserta el siguiente contenido en él.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 0
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 100
Escribe natural.yaml
Consideraremos este el estado "natural" al que volveremos cuando las solicitudes por segundo de frontend a worker disminuyan a menos de 10. En este estado, el 100% del tráfico se enruta al clúster primary.
Crea un archivo nuevo llamado natural.yaml y, luego, inserta el siguiente contenido en él:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
Cómo compilar y enviar istiowatcher
Ejecuta el siguiente comando para enviar el directorio actual a Google Cloud Build (GCB), que compilará y etiquetará la imagen en GCR.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
Implementa istiowatcher
Cambia al directorio kubernetes
cd ${proj}/kubernetes/
Escribe un archivo de implementación: istiowatcher.yaml
Crea un archivo llamado istiowatcher.yaml y, luego, inserta el siguiente contenido (reemplaza <your-project-id>).
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: istiowatcher-deployment
labels:
app: istiowatcher
spec:
replicas: 1
selector:
matchLabels:
app: istiowatcher
template:
metadata:
labels:
app: istiowatcher
spec:
serviceAccountName: istio-pilot-service-account
automountServiceAccountToken: true
containers:
- name: istiowatcher
image: gcr.io/<your-project-id>/istiowatcher
imagePullPolicy: Always
Implementación
Asegúrate de que estemos ejecutando en el clúster principal
kubectx primary
Implementa istiowatcher.yaml en el espacio de nombres istio-system
kubectl apply -n istio-system -f istiowatcher.yaml
Es importante tener en cuenta las directivas serviceAccountName y automountServiceAccountToken en el archivo yaml. Esto nos brinda las credenciales necesarias para ejecutar istioctl desde el clúster.
También debemos implementar esto dentro del espacio de nombres istio-system para asegurarnos de tener las credenciales para istio-pilot-service-account. (no existe en el espacio de nombres default).
Mira cómo se cambia el tráfico automáticamente.
Ahora llega el momento mágico. Vayamos a nuestro frontend y aumentemos la cantidad de solicitudes por segundo a 20.
Observa que tarda unos segundos, pero se acelera y todos nuestros valores hash tienen el prefijo “bursty”.
Esto se debe a que estamos tomando muestras de Prometheus en el rango 15s, lo que hace que nuestro tiempo de respuesta se retrase un poco. Si quisiéramos una banda mucho más ajustada, podríamos cambiar nuestra consulta a prometheus para que sea 5s..
18. Próximos pasos
Haz limpieza
No es necesario que realices la limpieza si usas una cuenta temporal proporcionada para este taller.
Puedes borrar tus clústeres de Kubernetes, la regla de firewall y las imágenes de GCR.
gcloud container clusters delete primary --zone=us-west1-a
gcloud container clusters delete burst --zone=us-west1-a
gcloud compute firewall-rules delete istio-multicluster-test-pods
gcloud container images delete gcr.io/$GCLOUD_PROJECT/istiowatcher
Qué sigue
- Asiste a algunas charlas de Istio.
- Obtén la certificación: Compila tu próxima app con Kubernetes y Istio
- Conferencia magistral: Kubernetes, Istio, Knative: The New Open Cloud Stack - Aparna Sinha, Group Product Manager for Kubernetes, Google
- Instructivo: Cómo usar Istio - Lee Calcote y Girish Ranganathan, SolarWinds
- Istio: la vista desde el ojo del paquete - Matt Turner, Tetrate
- ¿Es Istio el firewall de nueva generación más nuevo que se haya creado? - John Morello, Twistlock
- Lee la documentación de Istio.
- Únete a los grupos de trabajo de Istio.
- Sigue a @IstioMesh en Twitter.




