Press "Enter" to skip to content

Cómo instalar Jenkins en Kubernetes

Hace poco a solicitud de un cliente tuve que realizar la instalación de Jenkins sobre un clúster de Kubernetes EKS (AWS), y de esta manera poder aprovechar las características de alta disponibilidad, escalamiento horizontal, inicio de agentes a demanda, etc. que brinda Kubernetes.

Luego de revisar la diversa documentación existente y de realizar varias pruebas de concepto, encontré que a parte del despliegue del clúster en sí, eran necesarios otros componentes que permitieran el correcto funcionamiento de una aplicación en K8s (Jenkins en este caso).

En el presente proyecto, he tratado de describir este proceso de la manera más detallada posible. Aunque puede parecer tedioso en un inicio, una vez comprendidos los conceptos replicar el procedimiento no debe tomarnos más de unos cuantos minutos.

Si bien este procedimiento ha sido desarrollado pensado en el despliegue de Jenkins, puede adaptarse fácilmente a cualquier tipo de aplicación conteinerizada, o simplemente para el despliegue correcto de un clúster Kubernetes sobre AWS.

🔰 Requerimientos Iniciales

🌉 Arquitectura Jenkins sobre Kubernetes

A continuación se muestra la arquitectura de componentes de la aplicación Jenkins sobre un clúster de Kubernetes EKS (AWS).

kubernetes aws eks cluster jenkins
Arquitectura Jenkins sobre un Clúster de Kubernetes

En el diagrama se puede apreciar lo siguiente:

  • Los recursos utilizados por Jenkins (pods, services, pvc, serviceAccount, ingress, etc. ) irán desplegados en su propio namespace, aislándolos de otros servicios / aplicaciones ya existentes en el clúster.
  • El deployment de Jenkins puede implementarse en uno o más pods brindando alta disponibilidad y escalamiento horizontal.
  • Los agentes Jenkins se levantan a demanda como pods y existen sólo durante el tiempo de ejecución del pipeline, luego de que éste finaliza el pod se destruye automáticamente y se liberan los recursos.
  • Si en un futuro el clúster se queda sin recursos de CPU / memoria, simplemente deben agregarse más nodos Kubernetes tipo Worker al clúster.
  • Los nodos tipo Worker en EKS por defecto usan el sistema operativo Amazon Linux 2.
  • El servicio de Jenkins será expuesto públicamente a través de un ingress, el cual a su vez está enlazado con un Application Load Balancer (ALB). Es a través de este ALB que podremos acceder a nuestra aplicación desde Internet.

🏗️ Despliegue de un Clúster Kubernetes en AWS EKS

⚙️ Desplegando el clúster con eksctl

En mi experiencia, la manera más fácil para desplegar un clúster Kubernetes (EKS) en AWS es usando la herramienta eksctl.

Eksctl nos creará de manera automática las plantillas de CloudFormation que desplegarán los recursos solicitados en AWS.

Teniendo eksctl correctamente instalado y configurado, ejecutar el siguiente comando en una terminal:

eksctl create cluster --name "my-cluster" --region "us-east-1" --zones "us-east-1a,us-east-1b" --version 1.24 --node-type "t2.small" --nodes 2 --nodes-min 1 --nodes-max 2 --with-oidc --alb-ingress-access --spot

Vamos a explicar las principales opciones de la línea de comandos anterior:

  • –name: El nombre que llevará el clúster, en este caso my-cluster.
  • –region: La región AWS sobre la que se desplegará el clúster, nosotros usaremos us-east-1.
  • –zones: Las zonas de disponibilidad (subnets) dentro de la región sobre las que funcionará el clúster. Para nuestro caso y por simplicidad sólo seleccionamos 2, pero pueden ser más.
  • –version: La versión de Kubernetes a utilizar.
  • –node-type: El tipo de instancia que se utilizará para desplegar los nodos. En nuestro ejemplo usaremos t2.small.
  • –nodes, –nodes-min, –nodes-max: Número de nodos inicial, mínimo y máximo que tendrá el clúster
  • –spot (Opcional): Desplegará las instancias EC2 como tipo spot ahorrando costos. No usar esta opción en despliegues para producción.

Al ejecutar esta línea de comando, veremos una salida como la siguiente:

14:38:34  eksctl version 0.122.0
14:38:34  using region us-east-1
14:38:34  subnets for us-east-1a - public:192.168.0.0/19 private:192.168.64.0/19
14:38:34  subnets for us-east-1b - public:192.168.32.0/19 private:192.168.96.0/19
14:38:34  nodegroup "ng-0e78de48" will use "" [AmazonLinux2/1.24]
14:38:34  using Kubernetes version 1.24
14:38:34  creating EKS cluster "my-cluster" in "us-east-1" region with managed nodes
14:38:34  will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup
14:38:34  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=us-east-1 --cluster=my-cluster'
14:38:34  Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "my-cluster" in "us-east-1"
.
.
14:57:04  waiting for CloudFormation stack "eksctl-my-cluster-nodegroup-ng-0e78de48"
14:57:04  waiting for the control plane to become ready
14:57:05 [✔]  saved kubeconfig as "C:\\Users\\John\\.kube\\config"
14:57:05  no tasks
14:57:05 [✔]  all EKS cluster resources for "my-cluster" have been created
14:57:06  nodegroup "ng-0e78de48" has 2 node(s)
14:57:06  node "ip-192-168-32-202.ec2.internal" is ready
14:57:06  node "ip-192-168-5-170.ec2.internal" is ready
14:57:06  waiting for at least 1 node(s) to become ready in "ng-0e78de48"
14:57:10  kubectl command should work with "C:\\Users\\John\\.kube\\config", try 'kubectl get nodes'
14:57:10 [✔]  EKS cluster "my-cluster" in "us-east-1" region is ready

Al terminar el despliegue, vamos a la consola de AWS y verificamos que nuestro clúster EKS se haya desplegado correctamente:

Clúster AWS EKS Kubernetes
Clúster EKS recién desplegado

🔗 Configurando la conexión al clúster Kubernetes

Para acceder a nuestro nuevo clúster, ya sea por línea de comandos eksctl o de manera gráfica usando Lens, debemos actualizar nuestro archivo local de configuración de Kubernetes (~/.kube/config) con la información correspondiente de conexión. Para ello ejecutamos el siguiente comando:

aws eks update-kubeconfig --region "us-east-1" --name "my-cluster"
Updated context arn:aws:eks:us-east-1:680655248338:cluster/my-cluster in C:\Users\John\.kube\config

En el parámetro –region colocamos la región en la cual desplegamos nuestro clúster, y en –name el nombre del mismo.

A continuación verificamos que podamos conectarnos correctamente al clúster usando kubectl:

kubectl cluster-info
Kubernetes control plane is running at https://******.gr7.us-east-1.eks.amazonaws.com
CoreDNS is running at https://******.gr7.us-east-1.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
kubectl get nodes
NAME                             STATUS   ROLES    AGE    VERSION
ip-192-168-32-202.ec2.internal   Ready    <none>   113m   v1.24.7-eks-fb459a0
ip-192-168-5-170.ec2.internal    Ready    <none>   113m   v1.24.7-eks-fb459a0

Para el caso de Lens, una nueva conexión aparecerá en la lista de clústeres disponibles:

EKS K8s Lens
Accediendo al clúster Kubernetes usando Lens

💽 Instalación del controlador Amazon EBS CSI

Para poder aprovisionar volúmenes de almacenamiento (unidades de disco) en nuestro clúster, es necesario que instalemos un controlador de almacenamiento.

Para AWS EKS instalaremos el controlador Amazon EBS CSI (Elastic Block Store Container Storage Interface). Este driver nos permitirá crear y eliminar dinámicamente volúmenes EBS (Elastic Block Store) para ser utilizados por las aplicaciones en nuestro clúster.

👨‍💼 Creación del rol de IAM

Primero debemos crear el rol de IAM con el cual se ejecutará el controlador EBS CSI en el clúster. Para ello, en el siguiente comando reemplazamos my-cluster por el nombre de nuestro clúster y lo ejecutamos:

eksctl create iamserviceaccount \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --cluster my-cluster \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
  --approve \
  --role-only \
  --role-name AmazonEKS_EBS_CSI_DriverRole

Verificamos que el comando termine de ejecutarse correctamente:

17:35:34  1 existing iamserviceaccount(s) (kube-system/aws-node) will be excluded
17:35:34  1 iamserviceaccount (kube-system/ebs-csi-controller-sa) was included (based on the include/exclude rules)
17:35:34  serviceaccounts that exist in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
17:35:34  1 task: { create IAM role for serviceaccount "kube-system/ebs-csi-controller-sa" }
17:35:34  building iamserviceaccount stack "eksctl-my-cluster-addon-iamserviceaccount-kube-system-ebs-csi-controller-sa"
17:35:34  deploying stack "eksctl-my-cluster-addon-iamserviceaccount-kube-system-ebs-csi-controller-sa"
17:35:34  waiting for CloudFormation stack "eksctl-my-cluster-addon-iamserviceaccount-kube-system-ebs-csi-controller-sa"

🪛 Instalación del controlador usando eksctl o AWS CLI

Ahora realizaremos la instalación del controlador en sí. En el siguiente comando, reemplazamos my-cluster por el nombre de nuestro clúster y el valor de 111122223333 por nuestro identificador de cuenta de AWS:

eksctl create addon --name aws-ebs-csi-driver --cluster my-cluster --service-account-role-arn arn:aws:iam::111122223333:role/AmazonEKS_EBS_CSI_DriverRole

También podemos realizar la misma tarea usando AWS CLI:

aws eks create-addon --cluster-name my-cluster --addon-name aws-ebs-csi-driver --service-account-role-arn arn:aws:iam::111122223333:role/AmazonEKS_EBS_CSI_DriverRole

Verificamos que el driver haya terminado de instalarse correctamente:

2023-01-08 11:53:31 [ℹ]  Kubernetes version "1.24" in use by cluster "my-cluster"
2023-01-08 11:53:32 [ℹ]  using provided ServiceAccountRoleARN "arn:aws:iam::680655248338:role/AmazonEKS_EBS_CSI_DriverRole"
2023-01-08 11:53:32 [ℹ]  creating addon
AWS EKS EBS CSI Driver
Driver Amazon EBS CSI instalándose

📊 Instalación de Prometheus para el monitoreo del clúster

Para el monitoreo básico del estado de nuestro clúster, instalaremos la aplicación Prometheus. Esto lo realizaremos usando el comando helm.

Primero agregamos el repositorio de charts de Prometheus y actualizamos nuestra caché local:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

Instalamos el chart de Prometheus:

helm install prometheus prometheus-community/prometheus

Una vez Prometheus esté instalado, podremos ver en los widgets de monitoreo de Lens información de uso de recursos como CPU, memoria, etc.:

consumo cpu memoria kubernetes prometheus
Widgets de consumo de CPU y Memoria del Clúster después de instalar Prometheus
kubernetes lens prometheus 2
Consumo de CPU y Memoria por Nodo después de instalar Prometheus

🌐 Instalación del controlador AWS Load Balancer

Para poder publicar nuestros servicios en Kubernetes y así estén disponibles en Internet, es necesario contar con un controlador que mapee estos servicios con un balanceador de carga correspondiente al proveedor de cloud que estemos utilizando.

Para el caso de AWS es necesario instalar el AWS Load Balancer Controller. Este controlador nos permitirá mapear un ingress o servicio de Kubernetes a un Application Load Balancer (ALB) o Network Load Balancer (NLB), según sea el caso.

👨‍💼 Creación de la política y rol de IAM

Primero creamos la política que utilizará el rol. Ejecutamos:

curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

Creamos el rol IAM y Service Account con el cual se ejecutará el controlador a instalar. Reemplazamos my-cluster con el nombre de nuestro clúster y el valor de 111122223333 lo reemplazamos por nuestro identificador de cuenta de AWS. Ejecutamos:

eksctl create iamserviceaccount \
  --cluster=my-cluster \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name "AmazonEKSLoadBalancerControllerRole" \
  --attach-policy-arn=arn:aws:iam::111122223333:policy/AWSLoadBalancerControllerIAMPolicy \
  --approve

🪛 Instalación del controlador con Helm

Instalaremos el controlador usando helm. Primero agregamos el Helm chart correspondiente y actualizamos:

helm repo add eks https://aws.github.io/eks-charts
helm repo update

En el siguiente comando, reemplazamos my-cluster con el nombre de nuestro clúster, los valores 602401143452 y us-east-1 debes reemplazarlos con los valores correspondientes a tu caso según el siguiente cuadro. Ejecutamos el comando y verificamos que termine correctamente.

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set image.repository=602401143452.dkr.ecr.us-east-1.amazonaws.com/amazon/aws-load-balancer-controller

🚀 Despliegue de Jenkins en Kubernetes

Ya tenemos nuestro clúster Kubernetes ejecutándose y con todos los plugins necesarios, así que ya podemos proceder a instalar Jenkins.

Si aún no lo haz hecho, clona el repositorio de código en GitHub correspondiente al presente artículo:

git clone https://github.com/jruizcampos/jenkins-k8s.git

🔩 Creando los recursos de Jenkins en Kubernetes

Ubicados en la carpeta del repositorio clonado, ejecutamos los siguientes comandos. Creamos el namespace, Service Account y volumen necesarios:

kubectl apply -f namespace.yaml
kubectl apply -f serviceAccount.yaml
kubectl apply -f volume.yaml

Creamos el deployment de Jenkins y su servicio de acceso correspondiente:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

⚓ Configurando el Ingress y Load Balancer en AWS

Para configurar el ingress en Kubernetes, necesitamos la lista de subnets públicas configuradas en nuestro clúster EKS. Para ello, desde la consola de AWS vamos al servicio de VPC, seleccionamos Subnets y filtramos las redes por «public«. Copiamos los Subnet ID encontrados:

EKS Cluster Subnets
Listando las subnets públicas del Clúster EKS

Editamos el archivo ingress.yaml y buscamos la sección alb.ingress.kubernetes.io/subnets, a continuación actualizamos los valores con la lista de Subnet ID‘s obtenida en el paso anterior:

  alb.ingress.kubernetes.io/subnets: subnet-0ce7fbd629a3db193,subnet-0c4b6807f56cbd85d

Procedemos a crear el ingress:

kubectl apply -f ingress.yaml
ingress.networking.k8s.io/jenkins-ingress created

Luego de unos minutos, verificamos que el load balancer correspondiente se haya creado en AWS. Vamos a la consola EC2 de AWS y seleccionamos Load Balancers. El load balancer creado debe ser del tipo application (ALB):

Application Load Balancer for EKS
Application Load Balancer creado por el ingress desplegado (archivo ingress.yaml)

🌎 Comprobando el acceso a Jenkins

En el Load Balancer creado en el paso anterior verificamos su DNS name, lo copiamos y pegamos en la barra de direcciones de nuestro navegador web y accedemos:

Jenkins DNS Name
Accediendo a Jenkins mediante el DNS Name del Load Balancer

Se nos pedirá la clave de administrador inicial generada durante el momento de la instalación. Para obtener esta clave, debemos inspeccionar los logs del pod de despliegue de Jenkins.

Primero listamos los pods ejecutándose actualmente en el namespace devops-tools:

kubectl get pods -n devops-tools
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-5ddc766476-ll82g   1/1     Running   0          88m

Una vez identificado el pod, obtenemos las últimas 20 líneas de su log de ejecución:

kubectl logs jenkins-5ddc766476-ll82g --tail 20 -n devops-tools

En el fragmento de log mostrado, se puede apreciar claramente la clave generada:

*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

a14f39190fa44226af623ce9560b0d7b

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************

Ingresamos esta clave en la página de inicio de Jenkins, instalamos la lista de plugins recomendados y creamos un usuario administrador:

Jenkins install suggested plugins
Instalación de plugins recomendados de Jenkins

Configuramos la URL de acceso a nuestra instancia e ingresamos a la consola de Jenkins:

Jenkins URL de acceso
Configurando la URL de acceso a Jenkins
Jenkins first run
Consola de Jenkins recién instalado

0 0 votos
Calificación del artículo
Suscribirse
Notificar de
guest
0 Comentarios
Inline Feedbacks
View all comments
error: Contenido protegido!
0
Déjanos tus comentarios!x
()
x