Si Serverless es simple, ¿necesito un pipeline de CI/CD?

Alvaro David
google-cloud-hispanoamerica
6 min readFeb 2, 2023

Como desarrolladores nuestro foco principal es el código, y en este punto, Serverless (servicios gerenciados) nos ha ayudado de gran manera. Con un simple comando conseguimos desplegar nuestras aplicaciones en la nube rápidamente, delegando la complejidad y esfuerzo de la parte operacional (con temas como escalabilidad, infraestructura y otros) al proveedor de servicios, en este caso, Google Cloud.

Cuando comenzamos un nuevo proyecto, podemos tener el control de todos los aspectos del mismo. Sin embargo, conforme existe un crecimiento orgánico del mismo, la administración y complejidad del mismo se incrementa de forma natural.. Por ejemplo, podríamos comenzar con una arquitectura monolítica, y después pasar a una arquitectura en microservicios, dependiendo de nuestras necesidades.

Además, no sólo la aplicación crece, sino también los equipos de trabajo que la desarrollan, mantienen y operan, lo cual trae consigo una mayor dinámica de cambios que tenemos que cuidar.

Un pipeline de Continuous Integration/Continuous Deployment (CI/CD) te puede ayudar a manejar esa complejidad y dinámica, así como a minimizar la posibilidad de que algún cambio altere la operación de la aplicación. Es por eso que es necesario un pipeline de CI/CD en este tipo de implementaciones.

Ahora que sabemos la forma en la cual un pipeline de CI/CD puede ayudarnos, la siguiente pregunta es ¿cómo funciona? o ¿cómo podemos construirlo?

Creando un pipeline de CI/CD

Desde el momento en que hacemos un commit del código al repositorio hasta que estos cambios aparecen al usuario final, hay por lo menos una serie de pasos que deben ser cumplidos, los cuales son:

  • Build (Construir)
  • Store (Almacenar)
  • Deploy (Desplegar)
Software supply chain CI/CD

Para explorar cada paso, vamos a construir un pipeline básico de ejemplo.

En la consola de Google Cloud, utilizaremos Cloud Shell como nuestro ambiente de trabajo.

Cloud Shell

Como ejemplo de código vamos a usar una aplicación web de Hello World hecha en NodeJS del repositorio de samples de Cloud Code en GitHub (también disponible en otros lenguajes de programación).

Una opción es hacer un fork para tener el repositorio de forma rápida en tu cuenta de GitHub. Otra opción es clonar el repositorio y copiar solo la carpeta del ejemplo para hacer push en un nuevo repositorio. Para este ejemplo, usaremos la segunda opción:

git clone https://github.com/GoogleCloudPlatform/cloud-code-samples.git
cp -r cloud-code-samples/nodejs/nodejs-cloud-run-hello-world .
cd nodejs-cloud-run-hello-world/

git init
git remote add origin [your-new-repository]

Ahora que tenemos el repositorio para el código, requerimos de un repositorio para nuestras imágenes de los contenedores. Artifact Registry es la opción indicada.

Para crear un repositorio en Artifact Registry, ejecutamos el siguiente comando:

# Puedes seleccionar la región más cercana a tu localización 

gcloud artifacts repositories create nodejs-cloud-run-hello-world \
--location southamerica-east1 \
--repository-format docker

Tenemos un repositorio para el código y un repositorio para las imágenes de container, ahora procedemos a construir (build) la imagen del contenedor y almacenar (store) esa imagen para poder desplegarla (deploy) posteriormente.

Aquí hace su ingreso Cloud Build, primero tenemos que indicarle a Cloud Build de donde va a obtener el código y cuando debe hacer el buildde la imagen de container con el código. Para esto creamos un Activador (trigger):

En la consola de Google Cloud, vamos para la sección de Cloud Build > Activadores y hacemos clic en CONECTAR REPOSITORIO. Seleccionamos GitHub como origen.

Seleccionar origen

Ahora, elegimos el repositorio en Github que queremos conectar con Cloud Build:

Seleccionar repositorio

Acto seguido, creamos el activador, hacemos clic en CREAR UN ACTIVADOR:

Crear un activador

Y completamos los campos como se muestra en la imagen:

Creando el activador

Existen varios campos para configurar, sin embargo, nos enfocaremos en los básicos y esenciales para crear el pipeline de CI/CD:

  • Nombre: Debe ser único en la región del proyecto.
  • Región: Donde va a ser ejecutado el pipeline, la región debe ser la misma que el repositorio de imágenes de container en Artifact Registry.
  • Evento: El activador que detona al evento; en este caso, un envío (push)a una rama (branch).
  • Fuente: El lugar donde se encuentra el código. Seleccionaremos el repositorio que acabamos de conectar.
  • Rama (branch): La rama que invocará al activador, para esta demo usamos main.
  • Configuración: Usamos un archivo de configuración YAML con los pasos (steps)que queremos que realice Cloud Build. Este archivo debe nombrarse /cloudbuild.yaml.

El archivo /cloudbuild.yaml se creará en el repositorio de código local:

steps:
# Build app
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'southamerica-east1-docker.pkg.dev/$PROJECT_ID/nodejs-cloud-run-hello-world/hello-cloud-run:$COMMIT_SHA', '.']
id: BUILD

# Storage of the image
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'southamerica-east1-docker.pkg.dev/$PROJECT_ID/nodejs-cloud-run-hello-world/hello-cloud-run:$COMMIT_SHA']
id: STORAGE

# Deploy
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'hello-cloud-run',
'--image', 'southamerica-east1-docker.pkg.dev/$PROJECT_ID/nodejs-cloud-run-hello-world/hello-cloud-run:$COMMIT_SHA',
'--region', 'southamerica-east1',
'--platform', 'managed',
'--allow-unauthenticated']
id: DEPLOY

Con este archivo de configuración, Cloud Build llevará a cabo los siguientes pasos:

  1. Construir (Build) la imagen del contenedor: docker build.
  2. Almacenar (Storage) la imagen del contenedor en Artifact Registry: docker push.
  3. Desplegar (Deploy) en Cloud Run: gcloud run deploy.

Realizamos el commitdel código y hacemos push al repositorio:

git add .
git commit -m "First commit"
git push origin main

El activador es invocado al hacer push en el branch main:

Cloud Build Logs

Para verificar que el despliegue fue correcto, ingresamos a la URL https://hello-cloud-run-[your-hash]-rh.a.run.app

It’s running!

Vamos a hacer las cosas un poco más interesantes. Cuando lanzamos una nueva característica, nos gustaría que sólo un porcentaje de nuestros usuarios experimentaran este cambio. Vamos a crear un Canary Release.

Para realizar esta división de tráfico, agregamos el modificador --no-traffic durante el despliegue a Cloud Run. Esto significa que el nuevo release no recibirá peticiones.

# Deploy
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'hello-cloud-run',
'--image', 'southamerica-east1-docker.pkg.dev/$PROJECT_ID/nodejs-cloud-run-hello-world/hello-cloud-run:$COMMIT_SHA',
'--region', 'southamerica-east1',
'--no-traffic',
'--platform', 'managed',
'--allow-unauthenticated']
id: DEPLOY

Luego, añadiremos un paso (step) que indique el porcentaje de tráfico dirigido a la nueva versión liberada.

 # Canary release
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'services', 'update-traffic', 'hello-cloud-run',
'--region', 'southamerica-east1',
'--to-revisions=LATEST=50']
id: CANARY

Para revisar el cambio con mayor facilidad, asignamos un tráfico del 50%.

La nueva característica será un cambio en el saludo. En lugar de It’s running! aparecerá ¡Hola Google Cloud Blog Hispanoamérica!.

# index.html.hbs
...
<div class="message">
<h1>¡Hola Google Cloud Blog Hispanoamérica!</h1>
<h2>Congratulations, you successfully deployed a container image to Cloud Run</h2>
</div>
...

Nuevamente realizamos un commit y pushdel código:

git add .
git commit -m "New message"
git push origin main

El paso de Canary aparece en el pipeline:

Cloud Build Logs

Volvemos al sitio desplegado en Cloud Run, y al refrescar varias veces, podemos notar que aproximadamente la mitad de las veces aparece el nuevo mensaje y la otra mitad, el mensaje antiguo.

¡Hola Google Cloud Blog Hispanoamérica!

Conclusión

Este ejercicio puede ser un primer paso para automatizar tus pipelines de CI/CD, experimenta y aprovecha todas las capacidades que tiene Cloud Build, Artifact Registry y Cloud Run, nuestros servicios completamente gerenciados.

Como mencionamos al principio, este es un pipeline básico. Podemos añadir más pasos dependiendo de nuestras necesidades, como por ejemplo: Pruebas unitarias, Autorización binaria y Análisis de vulnerabilidades.

¡Te invitamos a seguir construyendo con Google Cloud!.

Gracias Javier Huerta y Roberto Garcia por el review.

--

--