Canalización de Jenkins de varias ramas en GKE

1. Descripción general

Jenkins es una de las soluciones de integración continua más populares disponibles. Se usa para automatizar las partes esenciales no humanas del proceso de desarrollo de software. Cuando implementamos Jenkins en Kubernetes en Google Cloud y usamos el complemento de GKE, podemos escalar ejecutores de compilación de forma rápida y automática según sea necesario. En combinación con Cloud Storage, podemos compilar y probar una aplicación con un esfuerzo mínimo.

Actividades

  • Implementa Jenkins en un clúster de Kubernetes
  • Implementa y configura el complemento de GKE de Jenkins para permitir que Jenkins cree y destruya pods como nodos de ejecutor
  • Compila y prueba una aplicación de SpringBoot de ejemplo
  • Compila y publica un contenedor en Google Container Registry
  • Implementa la aplicación de ejemplo en un entorno de GKE de pruebas y producción

Requisitos

  • Un proyecto de Google Cloud con la facturación configurada Si no tienes una, deberás crearla.

2. Cómo prepararte

Este codelab se puede ejecutar por completo en Google Cloud Platform sin ninguna instalación ni configuración local.

Cloud Shell

A lo largo de este codelab, aprovisionaremos y administraremos diferentes recursos y servicios de la nube con la línea de comandos a través de Cloud Shell.

Habilita las APIs

Estas son las APIs que necesitaremos habilitar en nuestro proyecto:

  • API de Compute Engine: Crea y ejecuta máquinas virtuales.
  • API de Kubernetes Engine: Compila y administra aplicaciones basadas en contenedores.
  • API de Cloud Build: La plataforma de integración continua y entrega continua de Google Cloud
  • API de Service Management: Permite que los productores de servicios publiquen servicios en Google Cloud Platform.
  • API de Cloud Resource Manager: Crea, lee y actualiza los metadatos para contenedores de recursos de Google Cloud.

Habilita las APIs requeridas con el siguiente comando de gcloud:

gcloud services enable compute.googleapis.com \
container.googleapis.com \
cloudbuild.googleapis.com \
servicemanagement.googleapis.com \
cloudresourcemanager.googleapis.com \
--project ${GOOGLE_CLOUD_PROJECT}

Crea un bucket de GCS

Necesitaremos un bucket de GCS para subir nuestro trabajo de prueba. Crearé un bucket con el ID de nuestro proyecto en el nombre para garantizar la exclusividad:

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket/ 

3. Creación de clústeres de Kubernetes

Crea el clúster

A continuación, crearemos un clúster de GKE que alojará nuestro sistema de Jenkins, incluidos los pods que se enviarán como nodos de trabajo. El alcance adicional que indica la marca --scopes permitirá que Jenkins acceda a Cloud Source Repositories y a Container Registry. En la consola de Cloud, ejecuta lo siguiente:

gcloud container clusters create jenkins-cd \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--scopes "https://www.googleapis.com/auth/source.read_write,cloud-platform" \
--cluster-version latest

También implementaremos 2 clústeres para alojar las compilaciones de etapa de pruebas y producción de nuestra aplicación de ejemplo:

gcloud container clusters create staging \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--cluster-version latest
gcloud container clusters create prod \
--machine-type n1-standard-2 --num-nodes 2 \
--zone us-east1-d \
--cluster-version latest

28b45298e1e82748.png Verificar

Una vez que se hayan creado los clústeres, podemos confirmar que se están ejecutando con gcloud container clusters list.

El resultado debe tener RUNNING en la columna STATUS:

NAME        LOCATION    MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jenkins-cd  us-east1-d  1.15.9-gke.9    34.74.77.124  n1-standard-2  1.15.9-gke.9  2          RUNNING
prod        us-east1-d  1.15.9-gke.9    35.229.98.12  n1-standard-2  1.15.9-gke.9  2          RUNNING
staging     us-east1-d  1.15.9-gke.9    34.73.92.228  n1-standard-2  1.15.9-gke.9  2          RUNNING

4. Implementa Jenkins con Helm

Instala Helm

Usaremos Helm, un administrador de paquetes de aplicaciones para Kubernetes, para instalar Jenkins en nuestro clúster. Para comenzar, descarga el proyecto que incluye los manifiestos de Kubernetes que usaremos para implementar Jenkins:

git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes

Cambia tu directorio de trabajo actual al directorio del proyecto:

cd ~/continuous-deployment-on-kubernetes/

Crea una vinculación de roles de clúster para otorgarte permisos de rol de administrador del clúster:

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)

Obtén las credenciales de tu clúster de Jenkins para conectarte a él:

gcloud container clusters get-credentials jenkins-cd --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Y descarga el objeto binario de Helm en la consola de Cloud:

wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz

Descomprime el archivo y copia el archivo helm incluido en tu directorio de trabajo actual:

tar zxfv helm-v2.14.1-linux-amd64.tar.gz && \
cp linux-amd64/helm .

Tiller es el lado del servidor de Helm que se ejecuta en el clúster de Kubernetes. Crear una cuenta de servicio llamada tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

Y vincúlalo al rol de clúster cluster-admin para que pueda realizar cambios:

kubectl create clusterrolebinding tiller-admin-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller

Ahora podemos inicializar Helm y actualizar el repositorio:

./helm init --service-account=tiller && \
./helm repo update

28b45298e1e82748.png Verificar

Confirma que Helm está listo con ./helm version. Esto debería mostrar los números de versión del cliente y el servidor:

Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}

Instala Jenkins

Ahora que Helm está instalado en nuestro clúster, ya podemos instalar Jenkins:

./helm install stable/jenkins -n cd \
-f jenkins/values.yaml \
--version 1.2.2 --wait

28b45298e1e82748.png Verificar

Revisemos los pods:

kubectl get pods

El resultado debería mostrar nuestro pod de Jenkins con el estado RUNNING:

NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-vbhg4   1/1       Running   0          1m

Confirma que el servicio de Jenkins se haya creado correctamente:

kubectl get svc

El resultado debería ser similar a este:

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         ClusterIP   10.35.241.170   <none>        8080/TCP    2m27s
cd-jenkins-agent   ClusterIP   10.35.250.57    <none>        50000/TCP   2m27s
kubernetes         ClusterIP   10.35.240.1     <none>        443/TCP     75m

La instalación de Jenkins usará el complemento de Kubernetes para crear agentes de compilación. El máster de Jenkins los iniciará automáticamente según sea necesario. Cuando finalice su trabajo, se terminarán automáticamente y los recursos se agregarán de nuevo al grupo de recursos de clústeres.

Cómo conectarse a Jenkins

Jenkins se ejecuta en nuestro clúster, pero para acceder a la IU, configuremos la redirección de puertos desde Cloud Shell:

export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

Se generó una contraseña de administrador durante la instalación. Vamos a recuperarlo:

printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

En la parte superior de Cloud Shell, haz clic en el ícono de vista previa web 7ddf5a65fd556dd6.png y selecciona “Vista previa en el puerto 8080”.

1d614c831a621cff.png

Deberíamos ver una pantalla de acceso de Jenkins en la que podemos ingresar el admin para el nombre de usuario y la contraseña que se muestra en el paso anterior:

9cba23e856cbc84f.png

Cuando hagamos clic en Acceder, se nos redireccionará a la página principal de Jenkins.

9261f3e914829137.png

5. Instala y configura el complemento de GKE

El complemento de Google Kubernetes Engine nos permite publicar implementaciones compiladas en Jenkins en nuestros clústeres de Kubernetes que se ejecutan en GKE. Hay algunos parámetros de configuración que se deben realizar con los permisos de IAM en tu proyecto. Implementaremos esa configuración con Terraform.

Primero, descarga el proyecto del complemento de GKE:

git clone https://github.com/jenkinsci/google-kubernetes-engine-plugin.git ~/google-kubernetes-engine-plugin

Configuración automática de permisos de IAM

Cambia tu directorio de trabajo actual al directorio rbac del proyecto de GKE que clonamos antes:

cd ~/google-kubernetes-engine-plugin/docs/rbac/

gcp-sa-setup.tf es un archivo de configuración de Terraform que creará un rol de IAM de GCP personalizado con permisos restringidos junto con una cuenta de servicio de GCP a la que se le otorgará ese rol. El archivo requiere valores para las variables de nombre del proyecto, la región y la cuenta de servicio. Para proporcionar esos valores, primero declaramos las siguientes variables de entorno:

export TF_VAR_project=${GOOGLE_CLOUD_PROJECT}
export TF_VAR_region=us-east1-d
export TF_VAR_sa_name=kaniko-role

Inicializa Terraform, genera un plan y aplícalo:

terraform init
terraform plan -out /tmp/tf.plan
terraform apply /tmp/tf.plan && rm /tmp/tf.plan

La cuenta de servicio necesitará permisos de administrador de almacenamiento para guardar en nuestro bucket de Cloud Storage:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \
--role 'roles/storage.admin'

También necesitará permisos de contenedor para las etapas de implementación de nuestra canalización:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} --member \
serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com --role 'roles/container.developer'

Ahora podemos usar Helm para configurar los permisos del clúster para el complemento de GKE con el implementador de robots de gke. Cambia tu directorio de trabajo al directorio de Helm del proyecto de GKE:

cd ~/google-kubernetes-engine-plugin/docs/helm/

Y, luego, instálalo con el gráfico de Helm proporcionado:

export TARGET_NAMESPACE=kube-system && \
envsubst < gke-robot-deployer/values.yaml | helm install ./gke-robot-deployer --name gke-robot-deployer -f -

6. Configura Jenkins

Claves de cuenta de servicio

Para que la cuenta de servicio funcione correctamente, necesitaremos generar un archivo de clave privada y agregarlo como secreto de Kubernetes. Primero, genera el archivo con el siguiente comando de gcloud:

gcloud iam service-accounts keys create /tmp/kaniko-secret.json --iam-account kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

Crearemos una clave secreta en el almacén de secretos de Kubernetes con ese archivo:

kubectl create secret generic jenkins-int-samples-kaniko-secret --from-file=/tmp/kaniko-secret.json 

Para descargar el archivo JSON en tu disco local, accede al elemento Descargar archivo desde el menú de 3 puntos de Cloud Shell:

c40378e72013b843.png

Ingresa la ruta de acceso del archivo /tmp/kaniko-secret.json y haz clic en Descargar.

En la página de Jenkins, en el panel lateral izquierdo, haz clic en Credenciales y, luego, en Sistema.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

En la sección de la página titulada Sistema, haz clic en Credenciales globales y, luego, en Agregar credenciales a la izquierda:

4350c0e68561119b.png

3d3526551cdae8b.png

En el menú desplegable Kind, selecciona Cuenta de servicio de Google desde una clave privada. Ingresa "kaniko-role" como nombre, sube la clave JSON que creaste en los pasos anteriores y haz clic en Aceptar.

b0502213408e730e.png

Variables de entorno

Hay algunas variables de entorno que necesitaremos definir en Jenkins antes de crear la canalización de varias ramas. Son los siguientes:

  • JENK_INT_IT_ZONE: Es la zona del clúster de Kubernetes. En nuestro caso, us-east1-d
  • JENK_INT_IT_PROJECT_ID: Se refiere al ID del proyecto de GCP que aloja esta instancia de Jenkins.
  • JENK_INT_IT_STAGING: Es el nombre de nuestro clúster de "etapa de pruebas". A modo de demostración, es staging.
  • JENK_INT_IT_PROD: Es el nombre de nuestro clúster de "prod". A modo de demostración, es prod.
  • JENK_INT_IT_BUCKET: Es el bucket de Google Cloud Storage que creaste en el paso anterior.
  • JENK_INT_IT_CRED_ID: Se refiere a las credenciales creadas con el archivo JSON en el paso anterior. El valor debe coincidir con el nombre que le asignamos, kaniko-role.

Para agregarlos, ve a Administrar Jenkins:

d54f279190a07878.png

Luego, Configurar sistema:

ce79d218b2799640.png

Verás una sección llamada Propiedades globales y, cuando marques la casilla de Variables de entorno, aparecerá un botón Agregar en el que haremos clic para agregar las variables anteriores como pares clave-valor:

81aa222a2b17b2cc.png

Haz clic en el botón Guardar que se encuentra en la parte inferior de la página para aplicar los cambios.

7. Configura una canalización

En Jenkins, haz clic en “Elemento nuevo”:

8d1270ce4d7b6a8a.png

Ingresa “jenkins-integration-sample” para el nombre, selecciona “Multibranch Pipeline” como el tipo de proyecto y haz clic en Aceptar:

eb071ecfbb4d775b.png

Se te redireccionará a la página de configuración de la canalización. En Branch Sources, ingresa https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git como Project Repository. En Configuración de compilación, ingresa "gke/Jenkinsfile" como Ruta de la secuencia de comandos.

5135bd6b0374508c.png

Haz clic en Guardar para aplicar esta configuración. Cuando lo guardes, Jenkins iniciará un análisis del repositorio y una compilación posterior para cada rama. A medida que avanza, verás que se crean, ejecutan y destruyen pods a medida que las compilaciones avanzan en la página Cargas de trabajo de Kubernetes.

Cuando terminen las compilaciones, verás dos elementos en la página Cargas de trabajo de Kubernetes llamados jenkins-integration-samples-gke, cada uno de los cuales corresponde al clúster de producción o de pruebas. El estado aparecerá como OK:

bdec6b1753d1ba07.png

Con el siguiente comando gcloud, veremos que subimos una imagen de contenedor al Registro de contenedores de Google correspondiente a nuestra canalización:

gcloud container images list

Para ver la carga de trabajo en tu navegador, obtén las credenciales del clúster de producción:

gcloud container clusters get-credentials prod --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Ejecuta el siguiente comando para configurar un redirección de puertos desde el puerto 8081 de tu shell al puerto 8080 de tu carga de trabajo:

export POD_NAME=$(kubectl get pods -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8081:8080 >> /dev/null &

En la parte superior de Cloud Shell, haz clic en el ícono de vista previa en la Web y selecciona “Vista previa en el puerto 8081”.

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. Limpieza

Exploramos cómo implementar Jenkins y una canalización de ejemplo de varias ramas en Kubernetes. Ahora es el momento de limpiar nuestro proyecto de los recursos que creamos.

Borra el proyecto

Si lo prefieres, puedes borrar todo el proyecto. En GCP Console, ve a la página Cloud Resource Manager.

En la lista de proyectos, selecciona el proyecto en el que hemos estado trabajando y haz clic en Borrar. Se te pedirá que ingreses el ID del proyecto. Ingrésalo y haz clic en Cerrar.

Como alternativa, puedes borrar todo el proyecto directamente desde Cloud Shell con gcloud:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Si prefieres borrar los diferentes componentes facturables uno por uno, continúa con la siguiente sección.

Clúster de Kubernetes

Borra todo el clúster de Kubernetes con gcloud:

gcloud container clusters delete jenkins-cd --zone=us-east1-d

Buckets de almacenamiento

Quita todos los archivos subidos y borra nuestro bucket con gsutil:

gsutil rm -r gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket

Imágenes de Google Container Registry

Borraremos las imágenes de Google Container Registry con los resúmenes de imágenes. Primero, recupera los resúmenes con el siguiente comando:

gcloud container images list-tags gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke --format="value(digest)"

Luego, para cada resumen que se muestra, haz lo siguiente:

gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>

9. ¡Felicitaciones!

¡Hurra! Lo lograste. Aprendiste a implementar Jenkins en GKE y a enviar trabajos a clústeres de Kubernetes.

Temas abordados

  • Implementamos un clúster de Kubernetes y usamos Helm para instalar Jenkins.
  • Instalamos y configuramos el complemento de GKE para permitir que Jenkins implemente artefactos de compilación en clústeres de Kubernetes.
  • Configuramos Jenkins para establecer una canalización de varias ramas que envía trabajo a los clústeres de GKE.