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
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
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
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 y selecciona “Vista previa en el puerto 8080”.
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:
Cuando hagamos clic en Acceder, se nos redireccionará a la página principal de Jenkins.
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:
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.
En la sección de la página titulada Sistema, haz clic en Credenciales globales y, luego, en Agregar credenciales a la izquierda:
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.
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:
Luego, Configurar sistema:
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:
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”:
Ingresa “jenkins-integration-sample” para el nombre, selecciona “Multibranch Pipeline” como el tipo de proyecto y haz clic en Aceptar:
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.
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:
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”.
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.