Configurar un canal de CI / CD que conecta su código fuente con el deployment

Back to Blog

Cuemby

April 5, 2023

Implementar un pipeline CI/CD entre una web app y Kubernetes usando Jenkins

Autor:

Felipe Lujan

En primer lugar, quiero dejar claro que no soy un experto en DevOps. Aún así, espero que esto les sea útil. Esta guía se basa principalmente en el curso Implementing a Full CI/CD Pipeline dictado por William Boyd en Linux Academy.

La idea general de este procedimiento es mostrar cómo configurar un canal de CI / CD que conecte su código fuente con su respectivo deployment, lo que significa que cada vez que haga push del código en un repositorio de GitHub, se iniciará una nueva compilación con la última versión de su código y se desplegará en un cluster de Kubernetes. Si ha usado Heroku, el resultado final le podrá resultar bastante familiar. Como es de esperarse, no tendremos un deployment actualizado en “tiempo real”, de hecho, todo el proceso de build y deployment puede demorar unos 4 minutos o más desde el momento en que se envía el código a github, lo cual puede variar según tamaño de su aplicación node.js.

Si bien hay servicios administrados como Google App Engine que facilitan las implementaciones (deployments), nunca está de más expandir su campo de visión e incluir tecnologías modernas como la containerizacion y la orquestación de contenedores.

Por cierto, usaré Google Cloud Platform (GCP), pero este procedimiento definitivamente debería funcionar con el proveedor que cada quien prefiera, así que siéntase libre de desviarse y explorar, y sí, la prueba gratuita de GCP es suficiente para lo que haremos en esta guía.

Para este tutorial necesitará.

  • Conceptos básicos de las aplicaciones node.js y una lista para hacer deploy (usaré React.js)
  • Conceptos básicos de GIT y una cuenta de Github.com.
  • Comprensión básica de los contenedores Docker y una cuenta DockerHub.
  • Acceso a un clúster Kubernetes y una máquina virtual adicional donde instalaremos Jenkins, Docker, GIT.

Es deseable tener comprensión básica de sistemas Kubernetes y Linux, pero no es indispensable. Para seguir este tutorial es necesario activar la prueba gratuita de GCP, o tener una tarjeta de crédito asociada a su cuenta de GCP para cubrir los gastos de las VM que ejecutaremos.

Empezaremos por crear y configurar las máquinas virtuales VM que alojarán nuestro cluster de Kubernetes y servidor de Jenkins.

1. Una vez que estés en Google Cloud Console, pasa el cursor sobre el ícono del triple igual en la esquina superior izquierda y vaya a Compute Engine > VM instances

Aquí necesitamos crear.

1 cluster de Kubernetes

1 VM con Jenkins, Docker y GIT.

Nota: un clúster GKE no funcionará ya que no podemos comunicarnos directamente con API server de kubernetes.

Sin embargo, podemos implementar un clúster Kubernetes fácilmente mediante la creación de una máquina virtual llamada Bitnami’s Certified Kubernetes Sandbox .

En el menú principal de Google Compute Engine, haga clic en Create VM, vaya a la opción Marketplace y busque “Kubernetes”, la imagen de Bitnami debería aparecer dentro de los resultados de la búsqueda.

Haga clic en ella y luego en el botón Launch on Compute Engine.

En la descripción general de esta máquina virtual, puede ver que contiene Kubectl, Kubeadm y Kubelet, así como cri-contenererd.

Desplácese hacia abajo y haga clic en deploy para implementar esta máquina virtual en su proyecto GCP. Después de que su VM se haya creado con éxito, espere 5 minutos más, mientras que los scripts de Bitnami inician el Cluster de Kubernetes, en el panel de información general de la VM puede ver el progreso de estas tareas.

Una vez completadas esas tareas, vuelva a la página principal de Google Compute Engine y entre a su nueva VM por medio de SSH.

Ahora debería poder comunicarse con su clúster Kubernetes mediante el comando Kubectl.

Ejecute

Kubectl get nodes

El resultado es una lista de los nodos conforman este clúster y su estado; en este caso, solo tengo un nodo que funciona como Master y worker, lo cual es suficiente para el propósito de esta guia.

Ahora vamos a enfocarnos en la implementación continua (CD) del proyecto. Vamos a necesitar otra máquina virtual con Jenkins, Dockerb y Git.

Para eso, solo voy a crear una nueva instancia en GCE, si está siguiendo este procedimiento puede usar su distro de linux favorita, yo usaré CentOS 7, al momento de crear esta VM asegúrese de habilitar el tráfico mediante HTTP y HTTPS.

En primer lugar, es necesario tener java instalado en la máquina virtual, pero esta distribución específica de CentOS no tiene java preinstalado, así que instalaré java 1.8.0 OpenJDK y el paquete wget que necesitaremos más adelante. Lo anterior usando los comandos.

sudo yum install -y java-1.8.0-openjdksudo yum install -y wget

Y ahora Jenkins:

curl --silent --location http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo | sudo tee /etc/yum.repos.d/jenkins.reposudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.keysudo  yum install -y jenkinssudo systemctl enable jenkinssudo systemctl start jenkins

Con esos comandos, agregamos el repositorio de Jenkins e importamos la key necesaria para al mismo, lo instalamos jenkins, habilitamos el servicio de Jenkins para asegurarnos de que se ejecutará cada vez que iniciemos esta VM, y finalmente inicializamos dicho servicio.

El servicio Jenkins ya debería estar funcionando.

Ejecuta este comando para verificar:

sudo tail -f /var/log/jenkins/jenkins.log

Ahora instalaremos Docker:

sudo yum update && sudo yum -y  install yum-utils device-mapper-persistent-data lvm2sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.reposudo yum install -y docker-cesudo systemctl start dockersudo systemctl enable docker

Con docker instalado y funcionando podemos usar este Comando para verificar su correcto funcionamiento:

sudo docker run hello-world

Más adelante necesitaremos que jenkins pueda ejecutar comandos de docker, por lo que necesitamos agregar el usuario jenkins al grupo docker ejecutando:

sudo gpasswd -a jenkins docker

En caso de que el grupo docker no exista todavía podemos agregarlo escuchando este comando:

sudo groupadd docker

Ahora instalaremos git:

sudo yum install -y git

Con Jenkins corriendo necesitamos Ingresar a su interfaz web, la cual se encuentra en el puerto 8080. Para eso tenemos dos opciones. La primera es habilitar un cortafuegos de Google Cloud platform que nos permita Ingresar a dicho puerto. La segunda es redireccionar el tráfico entrante y saliente del puerto 80 hacia el puerto 8080. En mi caso usaré la segunda opción ejecutando el siguiente comando:

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp — dport 80 -j REDIRECT — to-port 8080

Ahora si navegamos desde nuestro navegador a la dirección IP externa de la máquina virtual de Jenkins, veremos una pantalla de bienvenida similar a esta:

2. Nuevamente en la sesión ssh de la máquina virtual de Jenkins ejecutamos:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Esto nos devolverá el password temporal de acceso de administrador, lo copiamos y pegamos en la interfaz web de jenkins:

Click en continuar

Una vez hayamos ingresado se nos preguntará si deseamos instalar varias extensiones, aceptamos y luego podremos crear una cuenta de administrador de jenkins.

Al finalizar, vará una pantalla similar a la siguiente.

¡Felicitaciones, ya tiene Jenkins instalado y configurado!

Lo primero será instalar el plugin de integración continua de kubernetes para eso vamos al panel que hay a mano izquierda y seleccionamos la opción que dice manage Jenkins y luego a manage plugins allí iremos a la pestaña que dice available y buscamos Kubernetes.

Entre los resultados de búsqueda aparecerá un plugin llamado kubernetes continuous deployment.

Lo instalamos y reiniciamos jenkins.

Una vez que Jenkins reiniciado y hemos iniciado sesión nuevamente iremos al panel izquierdo y seleccionaremos credentials > global > add credentials

Primero ingresaremos las credenciales de docker hub para eso seleccionamos usuario y contraseña en el campo kind y llenamos los campos correspondientes. En el campo ID es muy importante ingresar, docker_hub_login , y que luego nos referiremos a estas credenciales por medio de ése ID.

Para finalizar, hacer click en save.

Hacemos click nuevamente en add credentials.

Para github es un poco diferente ya que necesitaremos un Access token. En github.com vamos al avatar arriba en la derecha y seleccionamos select settings> developer settings y generamos un nuevo token con cualquier nombre y habilitamos admin:repo_hook.

Al hacer clic en generar podemos ver el token lo copiamos y pegamos en el campo de contraseña en el formulario de credenciales de jenkins, necesitaremos el token más adelante. El nombre de usuario será nuestro usuario de github. En el campo ID digitamos github_key y guardamos

Haremos click en add credentials una vez más y en kind seleccionamos kubernetes configuration el ID que asignaremos es kubeconfig y seleccionamos la opción enter directly aparecerá un campo de texto donde debemos ingresar el archivo kubeconfig de nuestro cluster de kubernetes.

Para obtener este archivo nuevamente a Google compute engine ingresamos mediante ssh a la máquina virtual donde tenemos el cluster de kubernetes.

Ingresaremos uno de estos dos comandos para obtener el archivo kubeconfig:

sudo cat ~/.kube/config

O en su defecto:

sudo cat /etc/kubernetes/admin.conf En caso de que el primer Comando no funcione

Una vez veamos el contenido del archivo en la terminal lo copiamos todo asegurándonos de no es por fuera ningún carácter ya que hacerlo invalidaría totalmente el archivo kubeconfig. Y lo pegamos en la caja de texto de las credenciales de kubernetes.

Guardamos.

Finalmente vamos a la pantalla principal de jenkins y seleccionamos las opciones manage Jenkins y luego configure system

Bajamos hasta ver la sección github server, haga clic add github server > github server.

Le asignamos un nombre cualquiera y en el campo API URL escribimos https://api.github.com

Secret text aparecerá un campo llamado secret donde debemos ingresar el token de acceso de github. Le asignamos un ID de github_secret y terminamos haciendo click en Add

Ahora github_secret aparecerá entre las opciones del menú desplegable de credenciales de github, lo seleccionamos y activamos la casilla manage webhooks

De esta forma todo estará listo para iniciar un pipeline de jenkins.

3. Si desea seguir este procedimiento primero será necesario crear un fork de este proyecto de github https://github.com/FelipeLujan/gradle-test. Una vez tenga su fork propio, verá que en la raíz del proyecto hay un archivo llamado Jenkinsfile, modifique la linea 5 de este archivo y cambie “felipelujan” por su usuario de dockerhub. Este archivo es sumamente importante, más adelante explicaremos su función.

También mientras se encuentra en su fork de github.

Vaya a la opcion settings:

En el panel del lado izquierdo será una opción que dice webhooks selecciónela y luego seleccione add webhook:

En el campo payload URL ingrese la dirección ip externa de su servidor de jenkins seguido de /github-webhook/, también modifique el campo content type tal como aparece en la imagen:

De esta manera github podrá comunicarse con jenkins cuando haya nuevo código en el repositorio.

Finalmente podremos configurar el pipeline que se encargará de obtener compilar y desplegar el proyecto de github de manera automática, para ello vamos a la pantalla principal de jenkins y seleccionamos new item.

Ingrese un nombre cualquiera y seleccione multibranch pipeline, haga clic en ok.

En branch sources haga click en add source > GitHub. Aparecerá el siguiente formulario.

En credentials seleccione github_key.

En owner, ingrese su nombre de usuario de github.

El menú desplegable siguiente se llenará automáticamente con los proyectos que tenga en su cuenta de github, allí seleccione el fork del proyecto que estamos usando.

Y en el campo behaviors, seleccione exclude branches with PRs.

Haga clic en guardar.

4. Con esto el pipeline de jenkins ya estará completo.

Para ver las tareas que se están ejecutando haga clic en el nombre del pipeline que se encuentra en la parte superior izquierda de la pantalla.

al hacerlo aparecerá una tabla con las ramas presentes en el repositorio al que ha hecho fork recientemente.

Si no ha creado ninguna otra rama solamente estará la rama Master haga allí aquí para ver los procesos descritos en el Jenkinsfile.

  1. Se está declarando una variable de ambiente llamada DOCKER_IMAGE_NAME que como su nombre indica será el nombre asignado a la imagen de docker generada al compilar el proyecto.
  2. Desde las líneas 9 hasta las 15 se está ejecutando el archivo build.gradle Aunque este paso no es indispensable para la ejecución del pipeline, se ha incluido a manera de ejemplo para demostrar la integración de un proceso de gradle con comandos dependientes entre sí.
  3. El siguiente paso es Construir la imagen de docker para el proyecto para lo cual se tienen en cuenta los archivos .dockerignore y Dockerfile, en este último se ha optado por usar la versión alpine de node.js que es rápida y ligera. en un primer paso se realiza la compilación en un contenedor de docker y posteriormente el código compilado copia a un segundo contenedor Por lo cual el segundo contenedor que puede ser usado en producción no contiene el código fuente de la aplicación.
  4. Entre las líneas 27 y 39 se sube la imagen de docker a docker hub usando las credenciales docker_hub_login almacenadas previamente.
  5. Finalmente se crea un deployment de kubernetes usando kubeconfig y el archivo k8s_svc_deploy.yaml que también se encuentra en la raíz del proyecto.k8s_svc_deploy.yaml contiene 2 definiciones de kubernetes, un deployment y un servicio, expone el puerto 31000 y redirige el tráfico al puerto 8080 que exponen los deployments.
  6. De esta forma se puede acceder al deployment accediendo al puerto 31000 de la máquina virtual que alberga el cluster de kubernetes.

Kubernetes
Ci Cd Pipeline
Jenkins
Cuemby

¡Comparte este artículo!

Incubado por

Miembros de

Hatchet Ventures 22 Cohort 1

Hatchet Ventures