diff --git a/chapter-8/README-es.md b/chapter-8/README-es.md new file mode 100644 index 0000000..7902df8 --- /dev/null +++ b/chapter-8/README-es.md @@ -0,0 +1,48 @@ +# Capítulo 8: Facilitando que los equipos experimenten + +— +_🌍 Disponible +en_: [English](README.md) | [中文 (Chinese)](README-zh.md) | [日本語 (Japanese)](README-ja.md) | [Español](README-es.md) +> **Nota:** Presentado por la fantástica comunidad +> de [ 🌟 contribuidores](https://github.com/salaboy/platforms-on-k8s/graphs/contributors) cloud-native! + +--- + +En estos tutoriales, instalarás Knative Serving y Argo Rollouts en un clúster de Kubernetes para implementar +el lanzamiento tipo Canary, pruebas A/B y despliegues Blue/Green. Las estrategias de lanzamiento discutidas aquí tienen +como objetivo brindar a los equipos más control al liberar nuevas versiones de sus servicios. Al aplicar diferentes +técnicas para lanzar software, los equipos pueden experimentar y probar sus nuevas versiones en un entorno controlado, +sin dirigir todo el tráfico en vivo a una nueva versión en un solo momento. + +- [Estrategias de Lanzamiento usando Knative Serving](knative/README-es.md) +- [Estrategias de Lanzamiento usando Argo Rollouts](argo-rollouts/README-es.md) + +## Limpieza + +Si deseas eliminar el clúster KinD creado para este tutorial, puedes ejecutar: + +```shell +kind delete clusters dev +``` + +## Próximos Pasos + +- Revisa el proyecto [Knative Functions](https://knative.dev/docs/functions/) si estás interesado en construir una + plataforma de Function-as-a-Service, ya que esta iniciativa está trabajando en herramientas para facilitar la vida de + los desarrolladores de funciones. + +- Después de probar Argo Rollouts, el siguiente paso es crear un ejemplo de extremo a extremo que muestre el flujo de + Argo CD a Argo Rollouts. Esto requiere crear un repositorio que contenga tus definiciones de Rollouts. Consulta la + sección [FAQ section on the Argo Projects](https://argo-rollouts.readthedocs.io/en/latest/FAQ/) para más detalles + sobre su integración. + +- Experimenta con ejemplos más complejos utilizando `AnalysisTemplates` y `AnalysisRuns`, ya que esta función ayuda a + los equipos a implementar nuevas versiones con mayor confianza. + +- Dado que ambos proyectos pueden funcionar con un Service Mesh como [Istio](https://istio.io/), familiarízate con lo + que Istio puede hacer por ti. + +## Resumen y Contribuir + +¿Quieres mejorar este tutorial? Crea un issue, envíame un mensaje en [Twitter](https://twitter.com/salaboy) o envía un +Pull Request. diff --git a/chapter-8/argo-rollouts/README-es.md b/chapter-8/argo-rollouts/README-es.md new file mode 100644 index 0000000..df93f32 --- /dev/null +++ b/chapter-8/argo-rollouts/README-es.md @@ -0,0 +1,614 @@ +# Estrategias de Lanzamiento con Argo Rollouts + +— +_🌍 Disponible +en_: [English](README.md) | [中文 (Chinese)](README-zh.md) | [日本語 (Japanese)](README-ja.md) | [Español](README-es.md) +> **Nota:** Presentado por la fantástica comunidad +> de [ 🌟 contribuidores](https://github.com/salaboy/platforms-on-k8s/graphs/contributors) cloud-native! + +--- + +En este tutorial, exploraremos los mecanismos integrados de Argo Rollouts para implementar estrategias de lanzamiento. +También examinaremos el panel de control de Argo Rollouts, que permite a los equipos promover nuevas versiones sin +necesidad de usar la terminal (`kubectl`). + +## Instalación + +Necesitas un clúster de Kubernetes para instalar Argo Rollouts [Argo Rollouts](https://argoproj.github.io/rollouts/). +Puedes crear uno usando Kubernetes KinD, como hicimos en +el Capítulo +2 [Capítulo 2](https://github.com/salaboy/platforms-on-k8s/blob/main/chapter-2/README-es.md#creating-a-local-cluster-with-kubernetes-kind) + +Una vez que tengas el clúster, podemos instalar Argo Rollouts ejecutando: + +```shell +kubectl create namespace argo-rollouts +kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml +``` + +o siguiendo la documentación oficial de Argo +Rollouts [official documentation that you can find here](https://argoproj.github.io/argo-rollouts/installation/#controller-installation). + +También necesitas instalar el [Argo Rollouts +`kubectl` plugin](https://argoproj.github.io/argo-rollouts/installation/#kubectl-plugin-installation) + +Una vez que tengas el complemento, puedes iniciar una versión local del panel de control de Argo Rollouts ejecutando el +siguiente comando en una nueva terminal: + +```shell +kubectl argo rollouts dashboard +``` + +Luego, puedes acceder al panel dirigiendo tu navegador +a [http://localhost:3100/rollouts](http://localhost:3100/rollouts) + +![argo rollouts dashboard empty](../imgs/argo-rollouts-dashboard-empty.png) + +## Lanzamientos Canary + +Vamos a crear un recurso de Argo Rollout para implementar un lanzamiento Canary en el Servicio de Notificaciones de la +Aplicación de Conferencias. Puedes encontrarla en [full definition here](canary-release/rollout.yaml) + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: notifications-service-canary +spec: + replicas: 3 + strategy: + canary: + steps: + - setWeight: 25 + - pause: { } + - setWeight: 75 + - pause: { duration: 10 } + revisionHistoryLimit: 2 + selector: + matchLabels: + app: notifications-service + template: + metadata: + labels: + app: notifications-service + spec: + containers: + - name: notifications-service + image: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 + env: + - name: KAFKA_URL + value: kafka.default.svc.cluster.local + ... + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + limits: + cpu: "1" + memory: 256Mi + requests: + cpu: "0.1" + memory: 256Mi + +``` + +The `Rollout` resource replaces our Kubernetes `Deployment` resource. This means we still need to create a Kubernetes +Service and an Ingress Resource to route traffic to our Notification Service instance. Notice that we are defining three +replicas for the Notification Service. + +The previous `Rollout` defines a canary release with two steps: + +El recurso `Rollout` reemplaza nuestro recurso de `Deployment` de Kubernetes. Esto significa que aún necesitamos crear +un +Servicio de Kubernetes y un recurso de Ingress para dirigir el tráfico a nuestra instancia del Servicio de +Notificaciones. Ten en cuenta que estamos definiendo tres réplicas para el Servicio de Notificaciones. + +El Rollout anterior define un lanzamiento canary con dos pasos: + +```yaml +strategy: + canary: + steps: + - setWeight: 25 + - pause: { } + - setWeight: 75 + - pause: { duration: 10 } +``` + +Primero, establecerá la división de tráfico al 25 por ciento y esperará que el equipo pruebe la nueva versión (el paso +de pausa). Luego, después de que señalemos manualmente que queremos continuar, el rollout pasará al 75 por ciento hacia +la nueva versión, para finalmente pausar durante 10 segundos y luego moverse al 100 por ciento. + +Antes de aplicar los recursos de Rollout, Servicio e Ingress ubicados en el directorio `canary-release/`, instalemos +Kafka +para que el Servicio de Notificaciones pueda conectarse. + +```shell +helm install kafka oci://registry-1.docker.io/bitnamicharts/kafka --version 22.1.5 --set "provisioning.topics[0].name=events-topic" --set "provisioning.topics[0].partitions=1" --set "persistence.size=1Gi" + +``` + +Ahora que Kafka está en funcionamiento, apliquemos todos los recursos en el directorio `canary-releases/`: + +```shell +kubectl apply -f canary-release/ +``` + +Usando el plugin de Argo Rollouts, puedes observar el despliegue desde la terminal: + +```shell +kubectl argo rollouts get rollout notifications-service-canary --watch +``` + +Deberías ver algo como esto: + +```shell +Name: notifications-service-canary +Namespace: default +Status: ✔ Healthy +Strategy: Canary + Step: 4/4 + SetWeight: 100 + ActualWeight: 100 +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 (stable) +Replicas: + Desired: 3 + Current: 3 + Updated: 3 + Ready: 3 + Available: 3 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-canary Rollout ✔ Healthy 80s +└──# revision:1 + └──⧉ notifications-service-canary-7f6b88b5fb ReplicaSet ✔ Healthy 80s stable + ├──□ notifications-service-canary-7f6b88b5fb-d86s2 Pod ✔ Running 80s ready:1/1 + ├──□ notifications-service-canary-7f6b88b5fb-dss5c Pod ✔ Running 80s ready:1/1 + └──□ notifications-service-canary-7f6b88b5fb-tw8fj Pod ✔ Running 80s ready:1/1 +``` + +Como puede ver, debido a que acabamos de crear los lanzamientos, se crean tres réplicas y todo el tráfico se enruta a +esta `revision:1` inicial, y el estado se establece en `Healthy`. + +Vamos a actualizar la versión del Servicio de Notificaciones a `v1.1.0` ejecutando: + +```shell +kubectl argo rollouts set image notifications-service-canary \ + notifications-service=salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 +``` + +Ahora puedes ver que se ha creado la segunda revisión (`revision:2`): + +```shell +Name: notifications-service-canary +Namespace: default +Status: ॥ Paused +Message: CanaryPauseStep +Strategy: Canary + Step: 1/4 + SetWeight: 25 + ActualWeight: 25 +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 (stable) + salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 (canary) +Replicas: + Desired: 3 + Current: 4 + Updated: 1 + Ready: 4 + Available: 4 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-canary Rollout ॥ Paused 4m29s +├──# revision:2 +│ └──⧉ notifications-service-canary-68fd6b4ff9 ReplicaSet ✔ Healthy 14s canary +│ └──□ notifications-service-canary-68fd6b4ff9-jrjxh Pod ✔ Running 14s ready:1/1 +└──# revision:1 + └──⧉ notifications-service-canary-7f6b88b5fb ReplicaSet ✔ Healthy 4m29s stable + ├──□ notifications-service-canary-7f6b88b5fb-d86s2 Pod ✔ Running 4m29s ready:1/1 + ├──□ notifications-service-canary-7f6b88b5fb-dss5c Pod ✔ Running 4m29s ready:1/1 + └──□ notifications-service-canary-7f6b88b5fb-tw8fj Pod ✔ Running 4m29s ready:1/1 +``` + +Ahora el Rollout se detiene en el paso 1, donde solo el 25 por ciento del tráfico se dirige a `revision:2` y el estado +está establecido en Pausa. + +Siéntete libre de acceder al endpoint `service/info` para ver qué versión está respondiendo a tus solicitudes: + +```shell +curl localhost/service/info +``` + +Aproximadamente, una de cada cuatro solicitudes debería ser respondida por la versión `v1.1.0`: + +```shell +> curl localhost/service/info | jq + +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-canary-7f6b88b5fb-tw8fj", + "podNamespace":"default", + "podNodeName":"dev-worker2", + "podIp":"10.244.3.3", + "podServiceAccount":"default" +} + +> curl localhost/service/info | jq + +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-canary-7f6b88b5fb-tw8fj", + "podNamespace":"default", + "podNodeName":"dev-worker2", + "podIp":"10.244.3.3", + "podServiceAccount":"default" +} + +> curl localhost/service/info | jq + +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-canary-68fd6b4ff9-jrjxh", + "podNamespace":"default", + "podNodeName":"dev-worker", + "podIp":"10.244.2.4", + "podServiceAccount":"default" +} + +> curl localhost/service/info | jq + +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-canary-7f6b88b5fb-tw8fj", + "podNamespace":"default", + "podNodeName":"dev-worker2", + "podIp":"10.244.3.3", + "podServiceAccount":"default" +} +``` + +También revisa el panel de Argo Rollouts ahora; debería mostrar el lanzamiento Canary: + +![canary release in dashboard](../imgs/argo-rollouts-dashboard-canary-1.png) + +Puedes avanzar con el canary utilizando el comando de promoción o el botón de promoción en el panel. El comando se ve +así: + +```shell +kubectl argo rollouts promote notifications-service-canary +``` + +Esto debería mover a canary al 75% del tráfico y después de 10 segundos más debería estar al 100%, ya que el último +paso de la fase dura solo 10 segundos. Deberías ver en la terminal: + +```shell +Name: notifications-service-canary +Namespace: default +Status: ✔ Healthy +Strategy: Canary + Step: 4/4 + SetWeight: 100 + ActualWeight: 100 +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 (stable) +Replicas: + Desired: 3 + Current: 3 + Updated: 3 + Ready: 3 + Available: 3 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-canary Rollout ✔ Healthy 16m +├──# revision:2 +│ └──⧉ notifications-service-canary-68fd6b4ff9 ReplicaSet ✔ Healthy 11m stable +│ ├──□ notifications-service-canary-68fd6b4ff9-jrjxh Pod ✔ Running 11m ready:1/1 +│ ├──□ notifications-service-canary-68fd6b4ff9-q4zgj Pod ✔ Running 51s ready:1/1 +│ └──□ notifications-service-canary-68fd6b4ff9-fctjv Pod ✔ Running 46s ready:1/1 +└──# revision:1 + └──⧉ notifications-service-canary-7f6b88b5fb ReplicaSet • ScaledDown 16m + +``` + +Y en el Dashboard: +![canary promoted](../imgs/argo-rollouts-dashboard-canary-2.png) + +Ahora todas las solicitudes deberían ser respondidas por `v1.1.0`: + +```shell + +> curl localhost/service/info + +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-canary-68fd6b4ff9-jrjxh", + "podNamespace":"default", + "podNodeName":"dev-worker", + "podIp":"10.244.2.4", + "podServiceAccount":"default" +} + +> curl localhost/service/info + +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-canary-68fd6b4ff9-jrjxh", + "podNamespace":"default", + "podNodeName":"dev-worker", + "podIp":"10.244.2.4", + "podServiceAccount":"default" +} + +> curl localhost/service/info + +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-canary-68fd6b4ff9-jrjxh", + "podNamespace":"default", + "podNodeName":"dev-worker", + "podIp":"10.244.2.4", + "podServiceAccount":"default" +} + +``` + +Antes de avanzar con las implementaciones Blue/Green, limpiemos la implementación canary ejecutando lo siguiente: + +```shell +kubectl delete -f canary-release/ +``` + +## Despliegues Blue/Green + +Con las implementaciones Blue/Green queremos tener dos versiones de nuestro servicio ejecutándose al mismo tiempo. La +versión Blue (activa) a la que accederán todos los usuarios y la versión Green (vista previa) que los equipos internos +pueden usar para probar nuevas funciones y cambios. + +Las implementaciones de Argo brindan una estrategia Blue/Green lista para usar: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: notifications-service-bluegreen +spec: + replicas: 2 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: notifications-service + template: + metadata: + labels: + app: notifications-service + spec: + containers: + - name: notifications-service + image: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 + env: + - name: KAFKA_URL + value: kafka.default.svc.cluster.local + .. + strategy: + blueGreen: + activeService: notifications-service-blue + previewService: notifications-service-green + autoPromotionEnabled: false +``` + +Una vez más, estamos utilizando nuestro Servicio de Notificaciones para probar el mecanismo de despliegue gradual ( +Rollout). Aquí hemos definido un despliegue Blue/Green para el Servicio de Notificaciones que apunta a dos Servicios de +Kubernetes existentes: `notifications-service-blue` y `notifications-service-green`. Tenga en cuenta que la bandera +`autoPromotionEnabled` está configurada como `false`, esto detiene la promoción automática cuando la nueva versión está +lista. + +Verifique que ya tenga Kafka ejecutándose desde la sección anterior (Lanzamientos Canary) y aplique todos los recursos +ubicados dentro del directorio `blue-green/`: + +```shell +kubectl apply -f blue-green/ +``` + +Esto crea el recurso `Rollout`, dos Servicios de Kubernetes y dos recursos de Ingress, uno para el Servicio Blue que +redirige el tráfico desde `/` y otro para el Servicio Green que redirige el tráfico desde `/preview/`. + +Puedes monitorear el Rollout en la terminal ejecutando: + +```shell +kubectl argo rollouts get rollout notifications-service-bluegreen --watch +``` + +Debes ver algo como esto: + +``` +Name: notifications-service-bluegreen +Namespace: default +Status: ✔ Healthy +Strategy: BlueGreen +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 (stable, active) +Replicas: + Desired: 2 + Current: 2 + Updated: 2 + Ready: 2 + Available: 2 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-bluegreen Rollout ✔ Healthy 3m16s +└──# revision:1 + └──⧉ notifications-service-bluegreen-56bb777689 ReplicaSet ✔ Healthy 2m56s stable,active + ├──□ notifications-service-bluegreen-56bb777689-j5ntk Pod ✔ Running 2m56s ready:1/1 + └──□ notifications-service-bluegreen-56bb777689-qzg9l Pod ✔ Running 2m56s ready:1/1 + +``` + +Tenemos dos réplicas de nuestro Servicio de Notificaciones funcionando. Si hacemos curl `localhost/service/info` +deberíamos obtener la información del Servicio de Notificaciones `v1.0.0`: + +```shell +> curl localhost/service/info | jq + +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-canary-7f6b88b5fb-tw8fj", + "podNamespace":"default", + "podNodeName":"dev-worker2", + "podIp":"10.244.3.3", + "podServiceAccount":"default" +} +``` + +Y el panel de control de Argo Rollouts debería mostrarnos nuestro despliegue Blue/Green: + +![blue green 1](../imgs/argo-rollouts-dashboard-bluegree-1.png) + +Al igual que hicimos con el lanzamiento Canary, podemos actualizar nuestra configuración de Rollout, en este caso +configurando la imagen para la versión `v1.1.0`. + +```shell +kubectl argo rollouts set image notifications-service-bluegreen \ + notifications-service=salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 +``` + +Ahora deberías ver en la terminal ambas versiones del Servicio de Notificaciones ejecutándose en paralelo: + +```shell +Name: notifications-service-bluegreen +Namespace: default +Status: ॥ Paused +Message: BlueGreenPause +Strategy: BlueGreen +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 (stable, active) + salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 (preview) +Replicas: + Desired: 2 + Current: 4 + Updated: 2 + Ready: 2 + Available: 2 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-bluegreen Rollout ॥ Paused 8m54s +├──# revision:2 +│ └──⧉ notifications-service-bluegreen-645d484596 ReplicaSet ✔ Healthy 16s preview +│ ├──□ notifications-service-bluegreen-645d484596-ffhsm Pod ✔ Running 16s ready:1/1 +│ └──□ notifications-service-bluegreen-645d484596-g2zr4 Pod ✔ Running 16s ready:1/1 +└──# revision:1 + └──⧉ notifications-service-bluegreen-56bb777689 ReplicaSet ✔ Healthy 8m34s stable,active + ├──□ notifications-service-bluegreen-56bb777689-j5ntk Pod ✔ Running 8m34s ready:1/1 + └──□ notifications-service-bluegreen-56bb777689-qzg9l Pod ✔ Running 8m34s ready:1/1 +``` + +Tanto `v1.0.0` como `v1.1.0` están ejecutándose y en buen estado, pero el estado del despliegue Blue/Green está en +pausa, ya que mantendrá ambas versiones ejecutándose hasta que el equipo responsable de validar la versión `preview` / +`green` esté listo para el prime time. + +Revisa el panel de control de Argo Rollouts, debería mostrar ambas versiones ejecutándose también: + +![blue green 2](../imgs/argo-rollouts-dashboard-bluegree-2.png) + +En este punto, puedes enviar solicitudes a ambos servicios utilizando las rutas de Ingress que definimos. Puedes hacer +curl `localhost/service/info` para acceder al servicio Blue (servicio estable) y curl `localhost/preview/service/info` +para acceder al servicio Green (servicio de previsualización). + +```shell +> curl localhost/service/info + +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-canary-7f6b88b5fb-tw8fj", + "podNamespace":"default", + "podNodeName":"dev-worker2", + "podIp":"10.244.3.3", + "podServiceAccount":"default" +} +``` + +Y ahora verifiquemos el Servicio Verde: + +```shell +> curl localhost/green/service/info + +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-canary-68fd6b4ff9-jrjxh", + "podNamespace":"default", + "podNodeName":"dev-worker", + "podIp":"10.244.2.4", + "podServiceAccount":"default" +} +``` + +Si estamos satisfechos con los resultados, podemos promover nuestro Servicio Green para que sea nuestro nuevo servicio +estable, lo hacemos presionando el botón Promover en el panel de control de Argo Rollouts o ejecutando el siguiente +comando: + +```shell +kubectl argo rollouts promote notifications-service-bluegreen +``` + +Debes ver en la terminal: + +```shell +Name: notifications-service-bluegreen +Namespace: default +Status: ✔ Healthy +Strategy: BlueGreen +Images: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 + salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 (stable, active) +Replicas: + Desired: 2 + Current: 4 + Updated: 2 + Ready: 2 + Available: 2 + +NAME KIND STATUS AGE INFO +⟳ notifications-service-bluegreen Rollout ✔ Healthy 2m44s +├──# revision:2 +│ └──⧉ notifications-service-bluegreen-645d484596 ReplicaSet ✔ Healthy 2m27s stable,active +│ ├──□ notifications-service-bluegreen-645d484596-fnbg7 Pod ✔ Running 2m27s ready:1/1 +│ └──□ notifications-service-bluegreen-645d484596-ntcbf Pod ✔ Running 2m27s ready:1/1 +└──# revision:1 + └──⧉ notifications-service-bluegreen-56bb777689 ReplicaSet ✔ Healthy 2m44s delay:9s + ├──□ notifications-service-bluegreen-56bb777689-k6qxk Pod ✔ Running 2m44s ready:1/1 + └──□ notifications-service-bluegreen-56bb777689-vzsw7 Pod ✔ Running 2m44s ready:1/1 +``` + +Ahora el servicio estable es `revision:2`. Verás que Argo Rollouts mantendrá `revision:1` activo por un tiempo, solo en +caso +de que queramos revertir, pero después de unos segundos, se reducirá. + +Verifica en el panel de control que nuestro despliegue está en `revision:2` también: + +![rollout promoted](../imgs/argo-rollouts-dashboard-bluegree-3.png) + +¡Si llegaste hasta aquí, implementaste Lanzamientos Canary y Despliegues Blue/Green usando Argo Rollouts! + +## Limpieza + +Si deseas eliminar el clúster KinD creado para este tutorial, puedes ejecutar: + +```shell +kind delete clusters dev +``` + diff --git a/chapter-8/knative/README-es.md b/chapter-8/knative/README-es.md new file mode 100644 index 0000000..fd89e7e --- /dev/null +++ b/chapter-8/knative/README-es.md @@ -0,0 +1,569 @@ +# Estrategias de Lanzamiento con Knative Serving + +— +_🌍 Disponible +en_: [English](README.md) | [中文 (Chinese)](README-zh.md) | [日本語 (Japanese)](README-ja.md) | [Español](README-es.md) +> **Nota:** Presentado por la fantástica comunidad +> de [ 🌟 contribuidores](https://github.com/salaboy/platforms-on-k8s/graphs/contributors) cloud-native! + +--- + +Este tutorial creará un clúster de Kubernetes e instalará `Knative Serving` para implementar diferentes estrategias de +lanzamiento. Utilizaremos la división de tráfico basada en porcentajes de Knative Serving y el enrutamiento basado en +etiquetas y encabezados. + +## Creando un Clúster de Kubernetes con Knative Serving + +Necesitas un clúster de Kubernetes para instalar [Knative Serving](https://knative.dev). Puedes crear uno utilizando +Kubernetes KinD, pero en lugar de usar las configuraciones proporcionadas en +el [Capítulo 2](../../chapter-2/README-es.md), usaremos el siguiente +comando: + +```shell +cat <... +``` + +Puedes aplicar este recurso ejecutando: + +```shell +kubectl apply -f knative/notifications-service.yaml +``` + +Knative Serving creará una instancia de nuestro contenedor y configurará todas las configuraciones de red para +proporcionarnos una URL para acceder al servicio. + +Puedes listar todos los Servicios Knative ejecutando el siguiente comando: + +```shell +> kubectl get ksvc +NAME URL LATESTCREATED LATESTREADY READY REASON +notifications-service http://notifications-service.default.127.0.0.1.sslip.io notifications-service-00001 notifications-service-00001 True + +``` + +You can now curl the `service/info` URL of the service to make sure that it is working, we are using [ +`jq`](https://jqlang.github.io/jq/download/) a popular json utility to pretty-print the output: + +Ahora puedes usar curl en la URL `service/info` del servicio para asegurarte de que esté funcionando. Estamos +utilizando [jq](https://jqlang.github.io/jq/download/), una popular utilidad para JSON, para formatear la salida: + +```shell +curl http://notifications-service.default.127.0.0.1.sslip.io/service/info | jq +``` + +Deberías ver la siguiente salida: + +```json +{ + "name": "NOTIFICATIONS", + "podIp": "10.244.0.16", + "podName": "notifications-service-00001-deployment-7ff76b4c77-qkk69", + "podNamespace": "default", + "podNodeName": "dev-control-plane", + "podServiceAccount": "default", + "source": "https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "version": "1.0.0" +} +``` + +Verifica que haya un Pod ejecutando nuestro contenedor: + +```shell +> kubectl get pods +NAME READY STATUS RESTARTS AGE +kafka-0 1/1 Running 0 7m54s +notifications-service-00001-deployment-798f8f79f5-jrbr8 2/2 Running 0 4s +``` + +Observa que hay dos contenedores en ejecución: uno es nuestro Servicio de Notificaciones y el otro es el proxy `queue` +de Knative Serving, que se utiliza para almacenar en búfer las solicitudes entrantes y obtener métricas de tráfico. + +Después de 90 segundos (por defecto), si no estás enviando solicitudes al Servicio de Notificaciones, la instancia del +servicio se reducirá automáticamente. Cada vez que llegue una nueva solicitud entrante, Knative Serving aumentará +automáticamente la escala del servicio y almacenará la solicitud en búfer hasta que la instancia esté lista. + +En resumen, con Knative Serving obtenemos dos beneficios de inmediato: + +- Una forma simplificada de ejecutar nuestras cargas de trabajo sin crear múltiples recursos de Kubernetes. Este enfoque + se asemeja a una oferta de Contenedores como Servicio, que como equipo de Plataforma podrías querer ofrecer a tus + equipos. +- Autoescalado dinámico utilizando el Autoscaler de Knative, que puede utilizarse para reducir a cero tus aplicaciones + cuando no estén en uso. Esto se asemeja a un enfoque de Funciones como Servicio, que como equipo de Plataforma podrías + querer proporcionar a tus equipos. + +## Ejecutar la aplicación Conference con Servicios Knative + +En esta sección implementaremos diferentes estrategias de lanzamiento para nuestra aplicación Conference. Para ello, +desplegaremos todos los demás servicios de la aplicación, también usando Servicios Knative. + +Antes de instalar los otros servicios, necesitamos configurar PostgreSQL y Redis, ya que hemos instalado Kafka +previamente. Antes de instalar PostgreSQL, necesitamos crear un ConfigMap que contenga la instrucción SQL y cree la +tabla Proposals, para que el Helm Chart pueda hacer referencia al ConfigMap y ejecutar la instrucción cuando se inicie +la instancia de la base de datos. + +```shell +kubectl apply -f knative/c4p-sql-init.yaml +``` + +```shell +helm install postgresql oci://registry-1.docker.io/bitnamicharts/postgresql --version 12.5.7 --set "image.debug=true" --set "primary.initdb.user=postgres" --set "primary.initdb.password=postgres" --set "primary.initdb.scriptsConfigMap=c4p-init-sql" --set "global.postgresql.auth.postgresPassword=postgres" --set "primary.persistence.size=1Gi" +``` + +y Redis: + +```shell +helm install redis oci://registry-1.docker.io/bitnamicharts/redis --version 17.11.3 --set "architecture=standalone" --set "master.persistence.size=1Gi" +``` + +Now we can install all the other services (frontend, c4p-service, and agenda-service) by running: + +```shell +kubectl apply -f knative/ +``` + +Verifica que todos los Servicios Knative estén en estado `READY`: + +```shell +> kubectl get ksvc +NAME URL LATESTCREATED LATESTREADY READY REASON +agenda-service http://agenda-service.default.127.0.0.1.sslip.io agenda-service-00001 agenda-service-00001 True +c4p-service http://c4p-service.default.127.0.0.1.sslip.io c4p-service-00001 c4p-service-00001 True +frontend http://frontend.default.127.0.0.1.sslip.io frontend-00001 frontend-00001 True +notifications-service http://notifications-service.default.127.0.0.1.sslip.io notifications-service-00001 notifications-service-00001 True + +``` + +Accede al Frontend de la Aplicación Conference apuntando tu navegador a la siguiente URL. +URL [http://frontend.default.127.0.0.1.sslip.io](http://frontend.default.127.0.0.1.sslip.io) + +En este punto, la aplicación debería funcionar como se espera, con una pequeña diferencia: servicios como Agenda +Service y el C4P Service se reducirán cuando no estén en uso. Si listas los pods después de 90 segundos de inactividad, +deberías ver lo siguiente: + +```shell +> kubectl get pods +NAME READY STATUS RESTARTS AGE +frontend-00002-deployment-7fdfb7b8c5-cw67t 2/2 Running 0 60s +kafka-0 1/1 Running 0 20m +notifications-service-00002-deployment-c5787bc49-flcc9 2/2 Running 0 60s +postgresql-0 1/1 Running 0 9m23s +redis-master-0 1/1 Running 0 8m50s +``` + +Debido a que los servicios Agenda y C4P están almacenando estado en almacenamiento persistente (Redis y PostgreSQL), los +datos no se pierden cuando la instancia del servicio se reduce. Sin embargo, los servicios de Notificaciones y Frontend +mantienen datos en memoria (notificaciones y eventos consumidos), por lo que hemos configurado nuestro servicio Knative +para mantener al menos una instancia activa en todo momento. Todo el estado en memoria que se mantiene de esta manera +impactará cómo la aplicación puede escalar, pero recuerda que esto es solo un esqueleto funcional. + +Ahora que tenemos la aplicación en funcionamiento, echemos un vistazo a algunas estrategias de lanzamiento diferentes. + +## Lanzamientos Canary + +En esta sección, ejecutaremos un ejemplo simple que muestra cómo realizar lanzamientos canary utilizando Servicios +Knative. Comenzaremos simplemente analizando la división de tráfico basada en porcentajes. + +Las funcionalidades de división de tráfico basada en porcentajes se proporcionan listas para usar en los Servicios +Knative. Actualizaremos el Servicio de Notificaciones que desplegamos antes en lugar de cambiar el Frontend, ya que +manejar múltiples solicitudes para obtener archivos CCS y JavaScript puede ser complicado al usar la división de tráfico +basada en porcentajes. + +Para asegurarte de que el servicio siga en funcionamiento, puedes ejecutar el siguiente comando: + +```shell +curl http://notifications-service.default.127.0.0.1.sslip.io/service/info | jq +``` + +Deberías ver la siguiente salida: + +```json +{ + "name": "NOTIFICATIONS", + "podIp": "10.244.0.16", + "podName": "notifications-service-00001-deployment-7ff76b4c77-qkk69", + "podNamespace": "default", + "podNodeName": "dev-control-plane", + "podServiceAccount": "default", + "source": "https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "version": "1.0.0" +} + +``` + +Puedes editar el Servicio Knative (`ksvc`) del Servicio de Notificaciones y crear una nueva revisión cambiando la imagen +del contenedor que está utilizando el servicio o modificando cualquier otro parámetro de configuración, como las +variables de entorno: + +```shell +kubectl edit ksvc notifications-service +``` + +Y luego cambia de: + +```yaml +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: notifications-service +spec: + template: + metadata: + annotations: + autoscaling.knative.dev/min-scale: "1" + spec: + containers: + - image: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.0.0 + ... +``` + +A `v1.1.0`: + +```yaml +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: notifications-service +spec: + template: + metadata: + annotations: + autoscaling.knative.dev/min-scale: "1" + spec: + containers: + - image: salaboy/notifications-service-0e27884e01429ab7e350cb5dff61b525:v1.1.0 + ... +``` + +Antes de guardar este cambio, que creará una nueva revisión que podemos usar para dividir el tráfico, necesitamos +agregar los siguientes valores en la sección de tráfico: + +```yaml + traffic: + - latestRevision: false + percent: 50 + revisionName: notifications-service-00001 + - latestRevision: true + percent: 50 +``` + +Ahora, si comienzas a acceder al endpoint `service/info` nuevamente, verás que la mitad del tráfico se está dirigiendo a +la versión `v1.0.0` de nuestro servicio y la otra mitad a la versión `v1.1.0`. + +```shell +> curl http://notifications-service.default.127.0.0.1.sslip.io/service/info | jq +{ + "name":"NOTIFICATIONS-IMPROVED", + "version":"1.1.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/v1.1.0/conference-application/notifications-service", + "podName":"notifications-service-00003-deployment-59fb5bff6c-2gfqt", + "podNamespace":"default", + "podNodeName":"dev-control-plane", + "podIp":"10.244.0.34", + "podServiceAccount":"default" +} + +> curl http://notifications-service.default.127.0.0.1.sslip.io/service/info | jq +{ + "name":"NOTIFICATIONS", + "version":"1.0.0", + "source":"https://github.com/salaboy/platforms-on-k8s/tree/main/conference-application/notifications-service", + "podName":"notifications-service-00001-deployment-7ff76b4c77-h6ts4", + "podNamespace":"default", + "podNodeName":"dev-control-plane", + "podIp":"10.244.0.35", + "podServiceAccount":"default" +} +``` + +Este mecanismo es muy útil cuando necesitas probar una nueva versión, pero no estás dispuesto a dirigir todo el tráfico +en vivo de inmediato a la nueva versión en caso de que surjan problemas. + +Puedes modificar las reglas de tráfico para tener una división de porcentaje diferente si te sientes confiado en que la +versión más reciente es lo suficientemente estable como para recibir más tráfico. + +```yaml + traffic: + - latestRevision: false + percent: 10 + revisionName: notifications-service-00001 + - latestRevision: true + percent: 90 +``` + +En el momento en que una revisión (versión) no tenga ninguna regla de tráfico apuntando a ella, la instancia se +reducirá, ya que no se dirigirá tráfico hacia ella. + +# Pruebas A/B y Despliegues Blue/Green + +Con las pruebas A/B queremos ejecutar dos o más versiones de la misma aplicación/servicio al mismo tiempo para permitir +que diferentes grupos de usuarios prueben cambios y así decidir cuál versión funciona mejor para ellos. + +Con Knative Serving tenemos dos opciones: enrutamientos `Header-based` y `Tag-based`. Ambos utilizan +los mismos mecanismos y configuraciones detrás de escena, pero veamos cómo se pueden usar estos mecanismos. + +Con el enrutamiento `Tag/Header-based` tenemos más control sobre hacia dónde se enviarán las solicitudes, ya que +podemos usar un encabezado HTTP o una URL específica para instruir a los mecanismos de red de Knative a dirigir el +tráfico a versiones específicas del servicio. + +Esto significa que, para este ejemplo, podemos cambiar el Frontend de nuestra aplicación, ya que todas las solicitudes +que incluyan un encabezado o una URL específica se dirigirán a la misma versión del servicio. + +Asegúrate de acceder al Frontend de la aplicación apuntando tu navegador +a: [http://frontend.default.127.0.0.1.sslip.io](http://frontend.default.127.0.0.1.sslip.io) + +![frontend v1.0.0](../imgs/frontend-v1.0.0.png) + +Ahora vamos a modificar el Servicio Knative del Frontend para desplegar una nueva versión con la función de depuración +habilitada: + +```shell +kubectl edit ksvc frontend +``` + +Actualiza el campo de imagen para que apunte a `v1.1.0` y agrega la variable de entorno FEATURE_DEBUG_ENABLED (recuerda +que estamos usando la primera versión de la aplicación que no utiliza OpenFeature). + +```yaml +spec: + containerConcurrency: 0 + containers: + - env: + - name: FEATURE_DEBUG_ENABLED + value: "true" + ... + image: salaboy/frontend-go-1739aa83b5e69d4ccb8a5615830ae66c:v1.1.0 +``` + +Antes de guardar el Servicio Knative, cambiemos las reglas de tráfico para que coincidan con las siguientes: + +```yaml +traffic: + - latestRevision: false + percent: 100 + revisionName: frontend-00001 + tag: current + - latestRevision: true + percent: 0 + tag: version110 +``` + +Ten en cuenta que no se dirigirá tráfico (porcentaje: 0) a `v1.1.0` a menos que se especifique la etiqueta en la URL del +servicio. Los usuarios ahora pueden acceder +a: [http://version110-frontend.default.127.0.0.1.sslip.io](http://version110-frontend.default.127.0.0.1.sslip.io) para +acceder a `v1.1.0` + +![v1.1.0](../imgs/frontend-v1.1.0.png) + +Ten en cuenta que `v1.1.0` tiene un tema de color diferente; cuando los veas uno al lado del otro, notarás la +diferencia. +También revisa las otras secciones de la aplicación. + +Si por alguna razón no deseas o no puedes cambiar la URL del servicio, puedes utilizar encabezados HTTP para acceder a +`v1.1.0`. Usando un complemento de navegador +como [Chrome ModHeader](https://chrome.google.com/webstore/detail/modheader-modify-http-hea/idgpnmonknjnojddfkpgkljpfnnfcklj), +puedes modificar todas las solicitudes que el navegador está enviando al +agregar parámetros o encabezados. + +Aquí estamos configurando el encabezado `Knative-Serving-Tag` con el valor `version110`, que es el nombre de la etiqueta +que +configuramos en las reglas de tráfico para nuestro Servicio Knative de frontend. + +Ahora podemos acceder a la URL normal del Servicio Knative (sin cambios) para acceder a: +`v1.1.0`: [http://frontend.default.127.0.0.1.sslip.io](http://frontend.default.127.0.0.1.sslip.io) + +![v1.1.0 with header](../imgs/frontend-v1.1.0-with-header.png) + +El enrutamiento basado en etiquetas y encabezados nos permite implementar despliegues Blue/Green de la misma manera, ya +que el servicio `green` (el que queremos probar hasta que esté listo para su uso en producción) puede estar oculto +detrás +de una etiqueta con un 0% de tráfico asignado. + +```yaml +traffic: + - revisionName: + percent: 100 # All traffic is still being routed to this revision + - revisionName: + percent: 0 # 0% of traffic routed to this version + tag: green # A named route +``` + +Whenever we are ready to switch to our `green` service we can change the traffic rules: + +```yaml +traffic: + - revisionName: + percent: 0 + tag: blue + - revisionName: + percent: 100 + +``` + +Para resumir, al utilizar las capacidades de división de tráfico y enrutamiento `header/tag-based` de los +Servicios Knative, hemos implementado lanzamientos Canary, patrones de pruebas A/B y despliegues Blue/Green. Consulta el +sitio web [Knative Website](https://knative.dev) de Knative para obtener más información sobre el proyecto. + +To recap, by using Knative Services traffic splitting and header/tag-based routing capabilities we have implemented +Canary Releases, A/B testing patterns, and Blue/Green deployments. Check the [Knative Website](https://knative.dev) for +more information about the project. + +Limpieza +Si deseas eliminar el clúster KinD creado para este tutorial, puedes ejecutar: + +```shell +kind delete clusters dev +``` +