{"id":12019,"date":"2021-09-22T23:55:06","date_gmt":"2021-09-22T23:55:06","guid":{"rendered":"https:\/\/bluetab.net\/?p=12019"},"modified":"2021-09-22T23:55:06","modified_gmt":"2021-09-22T23:55:06","slug":"gitops-kubernetes","status":"publish","type":"post","link":"https:\/\/bluetab.mx\/en\/2021\/09\/gitops-kubernetes\/","title":{"rendered":"Desplegando una plataforma CI\/CD escalable con Jenkins y Kubernetes"},"content":{"rendered":"<h1>Desplegando una plataforma CI\/CD escalable con Jenkins y Kubernetes<\/h1>\n<figure><img decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/lucas-150x150.png\" alt=\"\" loading=\"lazy\"><\/figure>\n<h4>Lucas Calvo Berlanga<\/h4>\n<p>Cloud Engineer<\/p>\n<p>Share on twitter<br \/>\nShare on linkedin<\/p>\n<p>En este art\u00edculo de la&nbsp;<a href=\"https:\/\/bluetab.net\">pr\u00e1ctica cloud<\/a>&nbsp;veremos c\u00f3mo crear una plataforma de CI\/CD de una forma totalmente automatizada. Para ello nos apoyaremos en una metodolog\u00eda GitOps para as\u00ed realizar nuestros despliegues de una forma m\u00e1s sencilla, escalable e industrializada.<\/p>\n<p>La idea de este taller es crearnos un cluster de GKE donde tengamos desplegado Jenkins como nuestra pieza central de CI\/CD y que este vaya escalando en&nbsp;<a href=\"https:\/\/plugins.jenkins.io\/kubernetes\/\">agentes<\/a>&nbsp;de una forma totalmente automatizada para que seg\u00fan la demanda de ejecuciones de jobs nuestro cluster crezca o decrezca de una forma transparente para nosotros. Otra de las grandes ventajas de esta arquitectura es que podemos crear diferentes tipos de slaves para as\u00ed cubrir todo tipo de ejecuciones dentro de nuestra compa\u00f1\u00eda.<\/p>\n<p><img decoding=\"async\" width=\"991\" height=\"731\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-kubernetes.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-kubernetes.png 991w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-kubernetes-300x221.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-kubernetes-768x567.png 768w\" sizes=\"(max-width: 991px) 100vw, 991px\"><\/p>\n<p>Los componentes\/herramientas que usaremos en este proyecto ser\u00e1n los siguientes:<\/p>\n<ul>\n<li><strong>Terraform.<\/strong><\/li>\n<li><strong>GKE.<\/strong><\/li>\n<li><strong>Jenkins.<\/strong><\/li>\n<li><strong>Prometheus.<\/strong><\/li>\n<li><strong>Grafana.<\/strong><\/li>\n<li><strong>Slack.<\/strong><\/li>\n<\/ul>\n<h2>Objetivos<\/h2>\n<ol>\n<li>Creaci\u00f3n de la las vpcs donde se desplegar\u00e1 la infraestructura.<\/li>\n<li>Creaci\u00f3n de la infraestructura, en nuestro caso GKE, de una forma totalmente automatizada.<\/li>\n<li>Despliegue de Jenkins como componente principal haciendo uso del provider del helm.<\/li>\n<li>Configuraci\u00f3n de Jenkins usando el plugin de&nbsp;<a href=\"https:\/\/www.jenkins.io\/projects\/jcasc\/\">Jcasc<\/a>.<\/li>\n<li>Despliegue de prometheus para la monitorizaci\u00f3n de nuestro sistema haciendo uso de helm.<\/li>\n<li>Despliegue de grafana para la monitorizaci\u00f3n de nuestro sistema haciendo uso de helm.<\/li>\n<li>Configuraci\u00f3n de grafana haciendo uso de prometheus y unos dashboard configurados autom\u00e1ticamente.<\/li>\n<li>Revisi\u00f3n de toda la infraestructura levantada y chequeo de la monitorizaci\u00f3n.<\/li>\n<li>Ejecuci\u00f3n de un Job de ejemplo para ver el flujo completo.<\/li>\n<li>Comprobar sistema de alertas tanto ca\u00edda de sistemas como de jobs completos.<\/li>\n<li>Comprobar el escalado de nuestra infraestructura y de los componentes desplegados.<\/li>\n<\/ol>\n<h2>Introducci\u00f3n a Terraform<\/h2>\n<p><img decoding=\"async\" width=\"1024\" height=\"246\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-header-1024x246.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-header-1024x246.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-header-300x72.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-header-768x184.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-header.png 1280w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Terraform es una herramienta open-source para automatizar la creaci\u00f3n de infraestructura como c\u00f3digo. Para nuestro caso de uso usaremos Terraform tanto para desplegar la infraestructura, tanto GKE como la VPC donde se har\u00e1 el despliegue de este \u00faltimo.<\/p>\n<p>Terraform no solo nos permite desplegar infraestructura como c\u00f3digo sino que tambi\u00e9n nos da la opci\u00f3n de usar otros provedores como el de Kubernetes para la creaci\u00f3n de namespace (entre otras muchas cosas) o la posibilidad de realizar despliegues de otros componentes dentro del cluster de GKE con el proveedor de Helm.&nbsp;<a href=\"https:\/\/www.Terraform.io\">Terraform<\/a>.<\/p>\n<h2>Introducci\u00f3n a GKE<\/h2>\n<p><img decoding=\"async\" width=\"900\" height=\"804\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-header.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-header.png 900w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-header-300x268.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-header-768x686.png 768w\" sizes=\"(max-width: 900px) 100vw, 900px\"><\/p>\n<p>GKE es el servicio de Kubernetes gestionado y autoescalado por&nbsp;<a href=\"https:\/\/cloud.google.com\/\">GCP<\/a>. Es donde se realizar\u00e1n todos los despliegues tanto de Jenkins como de la monitorizaci\u00f3n que tendr\u00e1 nuestra plataforma.&nbsp;<a href=\"https:\/\/cloud.google.com\/kubernetes-engine\">GKE<\/a>. Este componente lo vamos a automatizar haciendo uso de Terraform donde se har\u00e1n las implementaciones necesarias para realizar el despliegue correctamente.<\/p>\n<h2>Introducci\u00f3n a Jenkins<\/h2>\n<p><img decoding=\"async\" width=\"1024\" height=\"330\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-header-1024x330.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-header-1024x330.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-header-300x97.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-header-768x247.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-header.png 1280w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Jenkins es nuestra pieza central de la plataforma de CI\/CD. Jenkins es una herramienta de construcci\u00f3n, implementaci\u00f3n y automatizaci\u00f3n de proyectos software. Para el despliegue de este componente nos apoyaremos en el provider de Helm de Terraform.&nbsp;<a href=\"https:\/\/www.jenkins.io\/\">Jenkins<\/a>.<\/p>\n<h2>Introducci\u00f3n a Prometheus<\/h2>\n<p><img decoding=\"async\" width=\"1024\" height=\"1015\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-1024x1015.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-1024x1015.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-300x297.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-150x150.png 150w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-768x761.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-1536x1523.png 1536w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-2048x2030.png 2048w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/prometheus-header-75x75.png 75w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Prometheus es un sistema de monitorizaci\u00f3n que usaremos para comprobar el estado de todos los pods desplegados en nuestra plataforma, as\u00ed como para monitorizar el estado de nuestra infraestructura como tal(Picos de consumo, nodos ca\u00eddos&#8230;). Para el despliegue de este componente nos apoyaremos en el provider de Helm de Terraform.&nbsp;<a href=\"https:\/\/prometheus.io\/\">Prometheus<\/a>.<\/p>\n<h2>Introducci\u00f3n a Grafana<\/h2>\n<p><img decoding=\"async\" width=\"240\" height=\"220\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-header.png\" alt=\"\" loading=\"lazy\"><\/p>\n<p>Grafana es nuestra herramienta de visualizaci\u00f3n de la monitorizaci\u00f3n. Nos decantamos por esta herramienta ya que se integra perfectamente con prometheus y nos permite crear dashboards personalizados de nuestra infraestructura. Para el despliegue de este componente nos apoyaremos en el provider de Helm de Terraform.&nbsp;<a href=\"https:\/\/grafana.com\/\">Grafana<\/a>.<\/p>\n<h2>Introducci\u00f3n a Slack<\/h2>\n<p><img decoding=\"async\" width=\"1024\" height=\"261\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-header-1024x261.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-header-1024x261.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-header-300x76.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-header-768x196.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-header.png 1280w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Por \u00faltimo, haremos uso de slack como herramienta de envi\u00f3 de alertas tanto en la ejecuci\u00f3n de los jobs de Jenkins como alertas de monitorizaci\u00f3n de ca\u00eddas en alguno de los pods desplegados.&nbsp;<a href=\"https:\/\/slack.com\">Slack<\/a><\/p>\n<h2>Preparaci\u00f3n de entorno<\/h2>\n<p>Para la ejecuci\u00f3n de la plataforma CI\/CD ser\u00e1 necesario hacer la instalaci\u00f3n de estas herramientas:<\/p>\n<ol>\n<li>Terraform. Aqu\u00ed se usa la versi\u00f3n v1.0. Se puede descargar&nbsp;<a href=\"https:\/\/learn.hashicorp.com\/tutorials\/terraform\/install-cli\">aqu\u00ed<\/a>. Para instalar una versi\u00f3n anterior consultar&nbsp;<a href=\"https:\/\/www.Terraform.io\/downloads.html\">aqu\u00ed<\/a>.<\/li>\n<li>Helm.&nbsp;<a href=\"https:\/\/helm.sh\/docs\/intro\/install\/\">Gu\u00eda de instalaci\u00f3n de Helm<\/a>.<\/li>\n<li>GCP. Para la realizaci\u00f3n del taller ser\u00e1 necesario la creaci\u00f3n de una cuenta en&nbsp;<a href=\"https:\/\/console.cloud.google.com\/\">GCP<\/a>.<\/li>\n<\/ol>\n<p><img decoding=\"async\" width=\"761\" height=\"211\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-helm.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-helm.png 761w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/terraform-helm-300x83.png 300w\" sizes=\"(max-width: 761px) 100vw, 761px\"><\/p>\n<h2>Clonaci\u00f3n de repositorio<\/h2>\n<p>El c\u00f3digo fuente est\u00e1 disponible en&nbsp;<a href=\"https:\/\/github.com\/lucasberlang\/gitops-kubernetes-jenkins\/\">github<\/a>.<\/p>\n<pre><code class=\"language-python\">git clone https:\/\/github.com\/lucasberlang\/gitops-kubernetes-jenkins\/\ncd gitops-kubernetes-jenkins <\/code><\/pre>\n<h2>\u00cdndice de ficheros<\/h2>\n<p>Dentro de la carpeta src tendremos todo el c\u00f3digo necesario para hacer el despliegue de nuestra infraestructura de una forma automatizada. En este apartado haremos un breve resumen de lo que contienen cada uno de los ficheros para que nuestro proyecto funcione.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/providers.tf\">providers.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Definici\u00f3n de los proveedores que usaremos para hacer el despliegue con Terraform. En nuestro caso haremos uso del provider de Google, helm y kubernetes.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/Terraform.tfvars\">terraform.tfvars<\/a><\/strong><\/li>\n<\/ul>\n<p>Variables que usaremos dentro de los m\u00f3dulos de Terraform.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/variables.tf\">variables.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Definici\u00f3n de las variables que usaremos tanto en los m\u00f3dulos de Terraform como en los secretos que desplegaremos para hacer uso en Jenkins.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/outputs.tf\">outputs.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Informaci\u00f3n del proyecto que nos interesa conocer.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/main.tf\">main.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Contendr\u00e1 la l\u00f3gica realizada en Terraform para hacer el despliegue de los componentes de infraestructura que necesitamos, en este caso VPC y GKE. Para ello haremos uso de dos m\u00f3dulos desarrollados por&nbsp;<a href=\"https:\/\/bluetab.net\">Bluetab<\/a>.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/kubernetes_secrets.tf\">kubernetes_secrets.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Archivo que contendr\u00e1 toda la informaci\u00f3n sensible que usaremos dentro de los despliegues que realizaremos (Grafana, Prometheus, Jenkins), como contrase\u00f1as, tokens, etc&#8230; .<\/p>\n<ul>\n<li><strong><a href=\"\/src\/helm_monitoring.tf\">helm_monitoring.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Archivo que contiene la configuraci\u00f3n que se realizar\u00e1 con el proveedor de Helm para el despliegue de los componentes Prometheus y Grafana.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/helm_jenkins.tf\">helm_jenkins.tf<\/a><\/strong><\/li>\n<\/ul>\n<p>Archivo que contiene la configuraci\u00f3n que se realizar\u00e1 con el proveedor de Helm para el despliegue de los componentes Jenkins.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/templates\/grafana.yaml\">grafana.yaml<\/a><\/strong><\/li>\n<\/ul>\n<p>En este archivo contiene la configuraci\u00f3n inicial que usar\u00e1 Helm cuando realicemos el despliegue de grafana.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/templates\/prometheus.yaml\">prometheus.yaml<\/a><\/strong><\/li>\n<\/ul>\n<p>En este archivo contiene la configuraci\u00f3n inicial que usar\u00e1 Helm cuando realicemos el despliegue de prometheus.<\/p>\n<ul>\n<li><strong><a href=\"\/src\/templates\/jenkins.yaml\">jenkins.yaml<\/a><\/strong><\/li>\n<\/ul>\n<p>En este archivo contiene la configuraci\u00f3n inicial que usar\u00e1 Helm cuando realicemos el despliegue de jenkins.<\/p>\n<ul>\n<li><strong><a href=\"\/vars.example.env\">vars.example.env<\/a><\/strong><\/li>\n<\/ul>\n<p>Archivo que contendr\u00e1 todas las variables de entorno que usaremos en nuestro proyecto. En este caso le pasaremos las variables m\u00e1s sensibles como pueden ser la contrase\u00f1a de grafana o el token usado en slack para no tener que subirlo al repositorio.<\/p>\n<h2>Configuraci\u00f3n de Slack<\/h2>\n<ol>\n<li>Primero de todo nos tendremos que registrar en&nbsp;<a href=\"https:\/\/slack.com\/\">Slack<\/a>.<\/li>\n<li>Una vez que tengamos el registro se deber\u00e1 seguir la gu\u00edan de configuraci\u00f3n de&nbsp;<a href=\"https:\/\/my.slack.com\/services\/new\/jenkins-ci\">Slack con Jenkins<\/a>. De este paso solo necesitaremos el token de Slack que pasaremos como variable de entorno TF_VAR_slack_token.<\/li>\n<li>Adem\u00e1s, nos crearemos un canal en Slack el cual pasaremos posteriormente como variable de entorno, TF_VAR_slack_channel.<\/li>\n<li>Ser\u00e1 necesario tambi\u00e9n coger el nombre del dominio de slack y pas\u00e1rselo como variable,TF_VAR_team_domain.<\/li>\n<li>Por \u00faltimo nos crearemos un webhook para el env\u00edo de alertas desde Prometheus. Para ello podemos seguir esta&nbsp;<a href=\"https:\/\/slack.com\/intl\/es-es\/help\/articles\/115005265063-Webhooks-entrantes-para-Slack#cu243mo-configurar-webhooks-entrantes\">gu\u00eda<\/a>. De este paso solo necesitaremos el endpoint para luego pasarlo como variable de entorno, TF_VAR_slack_api_url.<\/li>\n<\/ol>\n<h2>Configuraci\u00f3n de variables<\/h2>\n<p>Antes de realizar la ejecuci\u00f3n de nuestro proyecto debemos definir una serie de variables de entorno que necesitaremos para el correcto funcionamiento de este. Para ello haremos uso del archivo&nbsp;<a href=\"\/vars.example.env\">vars.example.env<\/a>&nbsp;donde tenemos ya definidas las variables m\u00e1s importantes. Para efectos de la demo las \u00fanicas variables que se tendr\u00e1n que modificar son las siguientes:<\/p>\n<ul>\n<li><strong>TF_VAR_project_id:<\/strong>&nbsp;el id del proyecto de la cuenta de GCP donde se realizar\u00e1 el despliegue de la infraestructura.<\/li>\n<li><strong>TF_VAR_vault_addr:<\/strong>&nbsp;se a\u00f1adir\u00e1 la direcci\u00f3n de vault para la autenticaci\u00f3n en el despliegue del proyecto de prueba. En caso de no tener vault se podr\u00e1 tambi\u00e9n configurar con las credenciales de Azure o crearse otra proyecto de ejemplo.<\/li>\n<li><strong>TF_VAR_vault_token:<\/strong>&nbsp;token de vault que se utilizar\u00e1 para autenticarse contra Azure en nuestro proyecto de demo. Igual que con la variable de arriba no ser\u00e1 necesaria si se configura el proyecto demo para autenticarse con las credenciales de Azure.<\/li>\n<li><strong>TF_VAR_slack_api_url:<\/strong>&nbsp;El endpoint de Slack que configuraremos para que se env\u00eden las alertas de nuestra plataforma.<\/li>\n<li><strong>TF_VAR_slack_channel:<\/strong>&nbsp;Canal de Slack donde se publicar\u00e1n los mensajes de las alertas.<\/li>\n<li><strong>TF_VAR_slack_token:<\/strong>&nbsp;El token de Slack que configuraremos para que se env\u00eden las alertas de nuestra plataforma.<\/li>\n<li><strong>TF_VAR_team_domain:<\/strong>&nbsp;El dominio de Slack que configuraremos para que se env\u00eden las alertas de nuestra plataforma.<\/li>\n<li><strong>TF_VAR_user_grafana:<\/strong>&nbsp;Nombre del usuario de Grafana que usaremos para loguearnos.<\/li>\n<li><strong>TF_VAR_password_grafana:<\/strong>&nbsp;Contrase\u00f1a para el usuario de Grafana definido anteriormente para hacer el login.<\/li>\n<\/ul>\n<p>Una vez se hayan configuradas todas estas variables se tendr\u00e1 que lanzar el siguiente comando para que queden como variables de entornos.<\/p>\n<pre><code class=\"language-python\">source vars.example.env <\/code><\/pre>\n<h2>Configuraci\u00f3n VPC<\/h2>\n<p>Para la configuraci\u00f3n de la VPC haremos uso del m\u00f3dulo corporativo desarrollado por&nbsp;<a href=\"https:\/\/bluetab.net\">Bluetab<\/a>. Este m\u00f3dulo est\u00e1 publica en el repositorio de&nbsp;<a href=\"https:\/\/github.com\/lucasberlang\/gcp-network\">github<\/a>&nbsp;y est\u00e1 totalmente documentado por si se tiene alguna duda de su funcionamiento o se quiere realizar alguna modificaci\u00f3n en la VPC. Para que esto funcione lo \u00fanico que debemos de hacer es instanciar nuestro m\u00f3dulo con las variables necesarias para hacerle funcionar:<\/p>\n<pre><code class=\"language-python\">module \"network\" {\n  source = \"git@github.com:lucasberlang\/gcp-network.git\"\n  project_id         = var.project_id\n  description        = var.description\n  enable_nat_gateway = true\n  intra_subnets = [\n    {\n      subnet_name           = \"private-subnet01\"\n      subnet_ip_cidr        = \"10.0.0.0\/16\"\n      subnet_private_access = false\n      subnet_region         = var.region\n    }\n  ]\n  secondary_ranges = {\n    private-subnet01 = [\n      {\n        range_name    = \"private-subnet01-01\"\n        ip_cidr_range = var.ip_range_pods\n      },\n      {\n        range_name    = \"private-subnet01-02\"\n        ip_cidr_range = var.ip_range_services\n      },\n    ]\n  }\n  labels = var.labels\n} <\/code><\/pre>\n<p>Lo \u00fanico necesario para ejecutar la creaci\u00f3n de la VPC ser\u00e1 el id del proyecto de GCP. Adem\u00e1s de desplegar la VPC con la creaci\u00f3n del m\u00f3dulo se realizar\u00e1 el despliegue de una subred a nuestra VPC con el direccionamiento 10.0.0.0\/16. Este es totalmente modificable as\u00ed como el nombre de la subred o la regi\u00f3n en donde se despliega. Tambi\u00e9n se han creado dos rangos secundarios de direccionamientos para los pods y servicios que desplegaremos en GKE.<\/p>\n<h2>Configuraci\u00f3n GKE<\/h2>\n<p>Para el despliegue del proyecto se ha optado por usar infraestructura totalmente gestionado, en este caso haremos uso de GKE. Para automatizar el despliegue usaremos el m\u00f3dulo corporativo desarrollado por&nbsp;<a href=\"https:\/\/bluetab.net\">Bluetab<\/a>. Este m\u00f3dulo est\u00e1 publica en el repositorio de&nbsp;<a href=\"https:\/\/github.com\/lucasberlang\/gcp-gke\">github<\/a>&nbsp;y esta totalmente documentado por si se tiene alguna duda de su funcionamiento o se quiere realizar alguna modificaci\u00f3n en el GKE. Para que esto funcione lo \u00fanico que debemos de hacer es instanciar nuestro m\u00f3dulo con las variables necesarias para hacerle funcionar:<\/p>\n<pre><code class=\"language-python\">module \"gke\" {\n  source = \"git@github.com:lucasberlang\/gcp-gke.git\"\n  project_id              = var.project_id\n  name                    = \"gitops\"\n  regional                = true\n  region                  = var.region\n  network                 = module.network.network_name\n  subnetwork              = module.network.intra_subnet_names.0\n  ip_range_pods           = \"private-subnet01-01\"\n  ip_range_services       = \"private-subnet01-02\"\n  enable_private_endpoint = false\n  enable_private_nodes    = false\n  master_ipv4_cidr_block  = \"172.16.0.0\/28\"\n  kubernetes_version      = \"latest\"\n  master_authorized_networks = [\n    {\n      cidr_block   = module.network.intra_subnet_ips.0\n      display_name = \"VPC\"\n    },\n    {\n      cidr_block   = \"0.0.0.0\/0\"\n      display_name = \"shell\"\n    }\n  ]\n  node_pools = [\n    {\n      name         = \"default-node-pool\"\n      machine_type = \"n1-standard-4\"\n    },\n  ]\n  istio     = var.istio\n  dns_cache = var.dns_cache\n  labels    = var.labels\n} <\/code><\/pre>\n<p>Como se puede observar en el c\u00f3digo la implementaci\u00f3n del m\u00f3dulo es bastante intuitivo solo ser\u00e1 necesario declarar algunas variables. Las variables m\u00e1s importantes son el tipo de instancia que usaran los node-pools y la subred donde se desplegar\u00e1 el cluster de GKE que para esto usaremos la red declarada anteriormente.<\/p>\n<p>El funcionamiento de GKE en nuestra VPC ser\u00e1 este:<\/p>\n<p><img decoding=\"async\" width=\"758\" height=\"586\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-master.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-master.png 758w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/gke-master-300x232.png 300w\" sizes=\"(max-width: 758px) 100vw, 758px\"><\/p>\n<h2>Configuraci\u00f3n Jenkins<\/h2>\n<p>Para la configuraci\u00f3n de Jenkins como hemos dicho anteriormente usaremos el provider de Helm. Para hacer el despliegue nos crearemos un namespace llamado gitops donde se desplegar\u00e1 Jenkins. El fichero donde se har\u00e1 esta configuraci\u00f3n es&nbsp;<a href=\"\/src\/helm_jenkins.tf\">helm_jenkins.tf<\/a>.<\/p>\n<pre><code class=\"language-python\">resource \"kubernetes_namespace\" \"jenkins\" {\n  metadata {\n    name = \"gitops\"\n  }\n} <\/code><\/pre>\n<p>Luego procederemos a hacer el despliegue de Jenkins con Helm.<\/p>\n<pre><code class=\"language-python\">data \"local_file\" \"helm_chart_values\" {\n  filename = \"${path.module}\/templates\/jenkins.yaml\"\n}\nresource \"helm_release\" \"jenkins\" {\n  name       = \"jenkins\"\n  repository = \"https:\/\/charts.jenkins.io\"\n  chart      = \"jenkins\"\n  version    = \"3.5.3\"\n  namespace  = kubernetes_namespace.jenkins.metadata.0.name\n  timeout    = 180\n  values = [data.local_file.helm_chart_values.content]\n} <\/code><\/pre>\n<p>Cogeremos el chart del repositorio oficial de Jenkins y le pasaremos el fichero&nbsp;<a href=\"\/src\/templates\/jenkins.yaml\">jenkins.yaml<\/a>&nbsp;como configuraci\u00f3n inicial.<\/p>\n<p>De este fichero vamos a destacar algunos puntos que hemos modificado para realizar una automatizaci\u00f3n de nuestro servicio.<\/p>\n<pre><code class=\"language-python\"> image: \"jenkins\/jenkins\"\n  imagePullPolicy: \"Always\"\n  adminSecret: true\n  adminUser: \"admin\"\n  jenkinsUrl: \"http:\/\/${kubernetes_endpoint}:80\" <\/code><\/pre>\n<p>Se ha realizado la modificaci\u00f3n del nombre del adminUser para que sea m\u00e1s gen\u00e9rico y jenkinsUrl para que nos de el endpoint de Jenkins en el GKE cuando nos leguen las alertas de los jobs en el slack.<\/p>\n<pre><code class=\"language-python\">  containerEnv:\n    - name: kubernetes_endpoint\n      valueFrom:\n        secretKeyRef:\n            name: jenkins-k8s-config\n            key: kubernetes_endpoint\n    - name: gitlab_username\n      valueFrom:\n        secretKeyRef:\n            name: gitlab-credentials\n            key: gitlab_username\n    - name: gitlab_ssh_key\n      valueFrom:\n        secretKeyRef:\n            name: gitlab-credentials\n            key: gitlab_ssh_key\n    - name: vault_token\n      valueFrom:\n        secretKeyRef:\n            name: vault-credentials\n            key: vault_token\n    - name: vault_addr\n      valueFrom:\n        secretKeyRef:\n            name: vault-credentials\n            key: vault_addr\n    - name: arm_access_key\n      valueFrom:\n        secretKeyRef:\n            name: azure-credentials\n            key: arm_access_key\n    - name: slack_token\n      valueFrom:\n        secretKeyRef:\n            name: slack-credentials\n            key: slack_token\n    - name: team_domain\n      valueFrom:\n        secretKeyRef:\n            name: slack-credentials\n            key: team_domain            \n  servicePort: 80\n  serviceType: LoadBalancer <\/code><\/pre>\n<p>Estos son todos los secrets que hemos definido en el archivo&nbsp;<a href=\"\/src\/kubernetes_secrets.tf\">kubernetes_secrets.tf<\/a>. Estos son necesarios para el correcto funcionamiento de Jenkins ya que haremos uso de muchos de estos secretos cuando realicemos la configuraci\u00f3n con el plugin de Jcasc de Jenkins.<\/p>\n<p>Adem\u00e1s, en la configuraci\u00f3n del serviceType lo hemos definido como LoadBalancer externo y el servicePort 80 para que sea visible desde el exterior.<\/p>\n<pre><code class=\"language-python\">installPlugins:\n    - kubernetes\n    - docker-custom-build-environment\n    - ansicolor\n    - aws-credentials\n    - azure-credentials\n    - gitlab-api\n    - gitlab-branch-source\n    - docker-java-api\n    - github-branch-source\n    - pipeline-graph-analysis\n    ... <\/code><\/pre>\n<p>Listado de todos los plugins que se instalar\u00e1n por defecto en la configuraci\u00f3n inicial de Jenkins.<\/p>\n<h2>Configuraci\u00f3n inicial de Jcasc<\/h2>\n<p>Jcasc es el plugin de configuraci\u00f3n como c\u00f3digo de Jenkins. Lo usaremos para hacer una serie de configuraciones previas como pueden ser:<\/p>\n<ul>\n<li><strong>Configuraci\u00f3n de los slaves:<\/strong><\/li>\n<\/ul>\n<p>Esta parte es donde definiremos la creaci\u00f3n de un cloud de kubernetes donde se desplegar\u00e1n todos nuestros pods cada vez que se lance una ejecuci\u00f3n de un job en nuestro Jenkins. Tambi\u00e9n configuraremos la imagen que se usar\u00e1 para desplegar cada slave y el namespace donde se realizar\u00e1 dicho despliegue. Para nuestro ejemplo usaremos una imagen ya modificada con la instalaci\u00f3n de Terraform y algunos componentes como el SDK de Google o el cli de azure (lucasbluetab\/jnlp-agent-Terraform-gcloud:latest). Adem\u00e1s, se configurar\u00e1 los recursos que gaste cada vez que se levante un pod en cualquier ejecuci\u00f3n de nuestros, consiguiendo as\u00ed una infraestructura totalmente escalable.<\/p>\n<pre><code class=\"language-python\">      cloud: |\n        jenkins:\n          clouds:\n            - kubernetes:\n                name: \"Terraform-executors\"\n                serverUrl: \"https:\/\/kubernetes.default\"\n                jenkinsTunnel: \"jenkins-agent:50000\"\n                jenkinsUrl: \"http:\/\/jenkins:80\"\n                skipTlsVerify: true\n                namespace: \"gitops\"\n                templates:\n                    - name: \"jenkins-jnlp\"\n                      namespace: \"gitops\"\n                      nodeUsageMode: NORMAL\n                      label: \"jnlp-exec\"\n                      containers:\n                        - name: \"jnlp\"\n                          image: \"jenkins\/jnlp-slave\"\n                          alwaysPullImage: false\n                          workingDir: \"\/home\/jenkins\/agent\"\n                          ttyEnabled: true\n                          command: \"\"\n                          args: \"\"\n                          resourceRequestCpu: \"500m\"\n                          resourceLimitCpu: \"1000m\"\n                          resourceRequestMemory: \"1Gi\"\n                          resourceLimitMemory: \"2Gi\"\n                      volumes:\n                        - emptyDirVolume:\n                            memory: false\n                            mountPath: \"\/tmp\"\n                      idleMinutes: \"1\"\n                      activeDeadlineSeconds: \"120\"\n                      slaveConnectTimeout: \"1000\"\n                    - name: \"Terraform\"\n                      namespace: \"gitops\"\n                      nodeUsageMode: NORMAL\n                      label: \"Terraform-exec\"\n                      containers:\n                        - name: \"Terraform\"\n                          image: \"lucasbluetab\/jnlp-agent-Terraform-gcloud:latest\"\n                          alwaysPullImage: false\n                          workingDir: \"\/home\/jenkins\/agent\"\n                          ttyEnabled: true\n                          command: \"\/bin\/sh -c\"\n                          args: \"cat\"\n                          resourceRequestCpu: \"100m\"\n                          resourceLimitCpu: \"500m\"\n                          resourceRequestMemory: \"500Mi\"\n                          resourceLimitMemory: \"1Gi\"\n                      volumes:\n                        - emptyDirVolume:\n                            memory: false\n                            mountPath: \"\/tmp\"\n                      podRetention: \"never\"\n                      activeDeadlineSeconds: \"900\"\n                      slaveConnectTimeout: \"1000\" <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n de las credenciales:<\/strong>&nbsp;se definir\u00e1n todas las credenciales que se usar\u00e1n dentro de Jenkins, en nuestro caso las credenciales de Jenkins y alguna extras que podremos configurar si es necesario.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">      credentials: |\n          credentials:\n              system:\n                  domainCredentials:\n                  - credentials:\n                    - basicSSHUserPrivateKey:\n                        scope: GLOBAL\n                        id: \"GitLab\"\n                        username: ${gitlab_username}\n                        passphrase: \"\"\n                        privateKeySource:\n                          directEntry:\n                            privateKey: ${gitlab_ssh_key}\n                    - string:\n                        scope: GLOBAL\n                        id: vaultUrl\n                        secret: ${vault_addr}\n                    - string:\n                        scope: GLOBAL\n                        id: vaultToken\n                        secret: \"${vault_token}\"\n                    - string:\n                        scope: GLOBAL\n                        id: azureARMKey\n                        secret: \"${arm_access_key}\"\n                    - string:\n                        scope: GLOBAL\n                        id: slackToken\n                        secret: \"${slack_token}\"\n                    - string:\n                        scope: GLOBAL\n                        id: teamDomain\n                        secret: \"${team_domain}\" <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n de Slack:<\/strong>&nbsp;Aqu\u00ed se pasar\u00e1 la configuraci\u00f3n que realizamos en Jenkins en nuestro caso le indicaremos el dominio de nuestro Slack, para nuestras pruebas Bluetabmundo, y la sala por defecto donde se escribir\u00e1n todas las alertas que manden nuestros jobs. Para terminar, le pasaremos el token de Slack para que haga correctamente la conexi\u00f3n. Tanto el teamDomain como la room deber\u00e1n ser modificados con los que hab\u00e9is creado en el apartado de configuraci\u00f3n de Slack.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">      unclassified: |\n        unclassified:\n          slackNotifier:\n            teamDomain: bluetabmundo\n            room: \"#jenkins\"\n            tokenCredentialId: slackToken <\/code><\/pre>\n<ul>\n<li><strong>Arreglo de bugs:<\/strong>&nbsp;Una de las ventajas m\u00e1s interesantes de Jcasc es que nos permite la utilizaci\u00f3n de scripts de groovy dentro de su configuraci\u00f3n. En nuestro caso crearemos un script para quitar un bug que salta en Jenkins al usar el plugin de de env-injector. B\u00e1sicamente este script nos quita un warning que no deber\u00eda salir pero por un bug de la versi\u00f3n del plugin salta.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">      scriptgroovy: |\n        groovy:\n          - script: &gt;\n              import jenkins.model.*;\n              import jenkins.security.*;\n              import hudson.security.*;\n              import hudson.model.*;\n              import static groovy.json.JsonOutput.*;\n              import hudson.ExtensionList;\n              ExtensionList&lt;UpdateSiteWarningsConfiguration&gt; configurations = ExtensionList.lookup(UpdateSiteWarningsConfiguration.class);\n              println configurations;\n              UpdateSiteWarningsConfiguration configuration = configurations.get(0);\n              HashSet&lt;UpdateSite.Warning&gt; activeWarnings = new HashSet&lt;&gt;();\n              activeWarnings.add('SECURITY-248');\n              configuration.ignoredWarnings = activeWarnings;\n              configuration.save(); <\/code><\/pre>\n<ul>\n<li><strong>Uso de Jobdsl:<\/strong>&nbsp;Con el plugin de Jcasc tambi\u00e9n lo podemos combinar con el plugin de Jobdsl que nos permite definirnos jobs cuando arranque nuestro Jenkins y as\u00ed tener ya creado todos nuestros principales jobs.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">      init-jobs: |\n            jobs:\n              - script: &gt;\n                  folder('Terraform')\n              - script: &gt;\n                  multibranchPipelineJob('Terraform\/azure-test') {\n                      branchSources {\n                          branchSource {\n                              source {\n                                  git {\n                                      remote('https:\/\/github.com\/lucasberlang\/Terraform-azure-test.git')\n                                  }\n                              }\n                              strategy {\n                                  defaultBranchPropertyStrategy {\n                                      props {\n                                          noTriggerBranchProperty()\n                                      }\n                                  }\n                              }\n                          }\n                      }\n                      configure {\n                          it \/ sources \/ data \/ 'jenkins.branch.BranchSource' \/ source \/ traits {\n                            'jenkins.plugins.git.traits.BranchDiscoveryTrait'()\n                          }\n                      }\n                      triggers {\n                          periodic(60)\n                      }\n                  } <\/code><\/pre>\n<h2>Configuraci\u00f3n Prometheus<\/h2>\n<p>Para la configuraci\u00f3n de Prometheus como hemos dicho anteriormente usaremos el provider de Helm. Para hacer el despliegue nos crearemos un namespace llamado monitoring donde se desplegar\u00e1 Prometheus. El fichero donde se har\u00e1 esta configuraci\u00f3n es&nbsp;<a href=\"\/src\/helm_monitoring.tf\">helm_monitoring.tf<\/a>.<\/p>\n<pre><code class=\"language-python\">resource \"kubernetes_namespace\" \"jenkins\" {\n  metadata {\n    name = \"gitops\"\n  }\n} <\/code><\/pre>\n<h4>Luego procederemos a hacer el despliegue de Prometheus con Helm.<\/h4>\n<pre><code class=\"language-python\">data \"template_file\" \"file\" {\n  template = \"${file(\"${path.module}\/templates\/prometheus.yaml\")}\"\n  vars = {\n    slack_api_url = \"${var.slack_api_url}\"\n    slack_channel = \"${var.slack_channel}\"\n  }\n}\nresource \"helm_release\" \"prometheus\" {\n  chart      = \"prometheus\"\n  name       = \"prometheus\"\n  namespace  = kubernetes_namespace.monitoring.metadata.0.name\n  repository = \"https:\/\/charts.helm.sh\/stable\"\n  values = [data.template_file.file.rendered]\n} <\/code><\/pre>\n<p>Para ello haremos unas modificaciones en el template&nbsp;<a href=\"\/src\/templates\/prometheus.yaml\">prometheus.yaml<\/a>&nbsp;sustituyendo las variables slack_api_url y slack_channel dentro del fichero por las variables de entorno que le pasamos en el paso inicial. Estas variables ser\u00e1n usadas para el env\u00edo de alertas si existiera alg\u00fan problema en el cluster de GKE o el alg\u00fan pod desplegado en este.<\/p>\n<p>De este fichero vamos a destacar algunos puntos que hemos modificado para realizar una automatizaci\u00f3n de nuestro servicio.<\/p>\n<ul>\n<li><strong>Configuraci\u00f3n del servicio:<\/strong>&nbsp;Configuraremos el servicio de Prometheus como un ClusterIP para que solo sea visible dentro del cluster.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">    type: ClusterIP <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n de las alertas de Slack:<\/strong>&nbsp;A\u00f1adiremos la configuraci\u00f3n de env\u00edo de alertas por si se cae alg\u00fan nodo de la infraestructura o hay alguna ca\u00edda de servicio como puede ser un fallo en el pod de Jenkins. Si sucede alguno de los dos puntos anteriores nos llegar\u00e1 una alerta a nuestro canal de Slack.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">alertmanagerFiles:\n  alertmanager.yml:\n    global:\n      slack_api_url: ${slack_api_url}\n    receivers:\n      - name: slack-notifications\n        slack_configs:\n          - channel: ${slack_channel}\n            send_resolved: true\n            icon_url: https:\/\/avatars3.githubusercontent.com\/u\/3380462\n            title: |\n              [{{ .Status | toUpper }}{{ if eq .Status \"firing\" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}\n              {{- if gt (len .CommonLabels) (len .GroupLabels) -}}\n                {{\" \"}}(\n                {{- with .CommonLabels.Remove .GroupLabels.Names }}\n                  {{- range $index, $label := .SortedPairs -}}\n                    {{ if $index }}, {{ end }}\n                    {{- $label.Name }}=\"{{ $label.Value -}}\"\n                  {{- end }}\n                {{- end -}}\n                )\n              {{- end }}\n            text: |\n              {{ range .Alerts -}}\n              *Alert:* {{ .Annotations.title }}{{ if .Labels.severity }} - `{{ .Labels.severity }}`{{ end }}\n              *Description:* {{ .Annotations.description }}\n              *Details:*\n                {{ range .Labels.SortedPairs }} \u2022 *{{ .Name }}:* `{{ .Value }}`\n                {{ end }}\n              {{ end }}\n    route:\n      group_wait: 10s\n      group_interval: 5m\n      receiver: slack-notifications\n      repeat_interval: 3h <\/code><\/pre>\n<p>Aqu\u00ed es donde se har\u00e1 la sustituci\u00f3n de nuestro webhook de Slack(slack_api_url) configurado en el paso inicial y tambi\u00e9n la sustituci\u00f3n del canal donde va a escribir las alertas(slack_channel).<\/p>\n<ul>\n<li><strong>Configuraci\u00f3n de recolecci\u00f3n de logs:<\/strong>&nbsp;por defecto Prometheus hace la recolecci\u00f3n de todos los logs de kubernetes al nivel de infraestructura. La \u00fanica modificaci\u00f3n que haremos es que recopile los logs del pod de Jenkins (Este funciona ya que hemos instalado el plugin de prometheus en Jenkins) as\u00ed recibiremos informaci\u00f3n valiosa de Jenkins que luego explotaremos con Grafana.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">      - job_name: 'jenkins'\n        metrics_path: \/prometheus\n        static_configs:\n          - targets: [jenkins.gitops.svc.cluster.local:80] <\/code><\/pre>\n<h2>Configuraci\u00f3n Grafana<\/h2>\n<p>Como \u00faltimo paso realizaremos la configuraci\u00f3n de Grafana. Para esto como hemos dicho anteriormente usaremos el provider de Helm. Para hacer el despliegue usaremos el namespace creado anteriormente llamado monitoring donde se desplegar\u00e1 Grafana. El fichero donde se realizaremos el despliegue de Grafana es&nbsp;<a href=\"\/src\/helm_monitoring.tf\">helm_monitoring.tf<\/a>.<\/p>\n<p>Para realizar el despliegue con helm usaremos el siguiente c\u00f3digo:<\/p>\n<pre><code class=\"language-python\">data \"local_file\" \"helm_chart_grafana\" {\n  filename = \"${path.module}\/templates\/grafana.yaml\"\n}\nresource \"helm_release\" \"grafana\" {\n  chart      = \"grafana\"\n  name       = \"grafana\"\n  namespace  = kubernetes_namespace.monitoring.metadata.0.name\n  repository = \"https:\/\/charts.helm.sh\/stable\"\n  values = [data.local_file.helm_chart_grafana.content]\n} <\/code><\/pre>\n<p>Todas las configuraciones iniciales de Grafana vienen modificadas en el template&nbsp;<a href=\"\/src\/templates\/grafana.yaml\">grafana.yaml<\/a>.<\/p>\n<p>Las configuraciones m\u00e1s importantes que hemos realizado en dicho archivo son las siguientes:<\/p>\n<ul>\n<li><strong>Configuraci\u00f3n del servicio:<\/strong>&nbsp;el servicio de Grafana se levantar\u00e1 como LoadBalancer para que sea visible desde el exterior y lo podamos revisar desde nuestro navegador web.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">service:\n  type: LoadBalancer\n  port: 80\n  targetPort: 3000\n    # targetPort: 4181 To be used with a proxy extraContainer\n  annotations: {}\n  labels: {}\n  portName: service <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n de credenciales:<\/strong>&nbsp;para loguearnos en Grafana haremos uso del&nbsp;<a href=\"\/src\/kubernetes_secrets.tf\">secret de kubernetes grafana-secrets<\/a>&nbsp;que hemos definido con usuario y contrase\u00f1a.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">admin:\n  existingSecret: grafana-credentials\n  userKey: adminUser\n  passwordKey: adminPassword <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n del datasource:<\/strong>&nbsp;como configuraci\u00f3n inicial tambi\u00e9n a\u00f1adiremos Prometheus como fuente de datos en Grafana. Para ello tendremos que a\u00f1adir la url interna de prometheus, en nuestro caso ser\u00e1 el nombre del servicio (prometheus-server) m\u00e1s el namespace donde esta desplegado (monitoring) y por \u00faltimo la&nbsp;<a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/concepts\/service-discovery\">resoluci\u00f3n del DNS en GKE<\/a>.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">datasources:\n datasources.yaml:\n   apiVersion: 1\n   datasources:\n   - name: Prometheus\n     type: prometheus\n     url: http:\/\/prometheus-server.monitoring.svc.cluster.local\n     isDefault: true <\/code><\/pre>\n<ul>\n<li><strong>Configuraci\u00f3n de los dashboards:<\/strong>&nbsp;a\u00f1adiremos unos dashboards inciales cuando se levante el servicio de Grafana. Estos dashboards ser\u00e1n los siguientes:\n<ul>\n<li>Jenkins-Performance: Encargado de la monitorizaci\u00f3n del servicio de Jenkins a nivel de ejecuci\u00f3n de jobs y de uso de recursos.<\/li>\n<li>Kubernetes-nodes: Monitorizaci\u00f3n de la infraestructura de GKE.<\/li>\n<li>kubernetes-cluster: Monitorizaci\u00f3n de la infraestructura de GKE.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"language-python\">dashboards:\n  default:\n    Jenkins-Performance:\n      gnetId: 14764\n      revision: 1\n      datasource: Prometheus\n    Kubernetes-nodes:\n      gnetId: 315\n      revision: 3\n      datasource: Prometheus\n    Kubernetes-cluster:\n      gnetId: 6417\n      revision: 1\n      datasource: Prometheus <\/code><\/pre>\n<h2>Despliegue de la infraestructura<\/h2>\n<p>Una vez realizado el paso de&nbsp;<a href=\"\/#configuraci%C3%B3n-de-variables\"><strong>configuraci\u00f3n de variables<\/strong><\/a>&nbsp;pasaremos a realizar el despliegue de toda la infraestructura (GKE y VPC) y de todos los componentes que vamos a desplegar (Jenkins, Prometheus y Grafana).<\/p>\n<p>Para ello al tenerlo todo configurado con Terraform solo debemos ejecutar los siguientes comandos dentro de nuestro proyecto:<\/p>\n<pre><code class=\"language-python\">cd src\/\nterraform init\nterraform apply <\/code><\/pre>\n<p>Una vez ejecutado los comandos anteriores la salida esperada de nuestro proyecto ser\u00e1 la siguiente:<\/p>\n<p><img decoding=\"async\" width=\"1000\" height=\"310\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/output-terraform.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/output-terraform.png 1000w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/output-terraform-300x93.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/output-terraform-768x238.png 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\"><\/p>\n<h4 id=\"revisi%C3%B3n-de-la-infraestructura\"><strong>Revisi\u00f3n de la infraestructura<\/strong><\/h4>\n<p>Una vez desplegado toda la infraestructura empezaremos a hacer la revisi\u00f3n de todo lo desplegado para ello nos conectaremos al cluster de GKE de la siguiente forma:<\/p>\n<pre><code class=\"language-python\">gcloud container clusters get-credentials $cluster_name --region $region --project $project_id <\/code><\/pre>\n<p>Para ello se deber\u00e1 sustituir las variables cluster_name por el nombre del cluster, region por la regi\u00f3n donde se ha desplegado el cluster de GKE y la variable project_id haciendo referencia al proyecto donde se desplegar\u00e1.<\/p>\n<p>Una vez conectado al cluster de GKE haremos una revisi\u00f3n de los nodos desplegados:<\/p>\n<pre><code class=\"language-python\">kubectl get nodes <\/code><\/pre>\n<p>Esto nos devolver\u00e1:<\/p>\n<p><img decoding=\"async\" width=\"892\" height=\"117\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes.png 892w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes-300x39.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes-768x101.png 768w\" sizes=\"(max-width: 892px) 100vw, 892px\"><\/p>\n<p>As\u00ed como pods y servicios que tenemos disponibles:As\u00ed como pods y servicios que tenemos disponibles:<\/p>\n<pre><code class=\"language-python\">kubectl get pods,svc -n gitops\nkubectl get pods,svc -n monitoring <\/code><\/pre>\n<p>Con la siguiente salida:<\/p>\n<p><img decoding=\"async\" width=\"1009\" height=\"434\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/pods-svc-kubernetes.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/pods-svc-kubernetes.png 1009w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/pods-svc-kubernetes-300x129.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/pods-svc-kubernetes-768x330.png 768w\" sizes=\"(max-width: 1009px) 100vw, 1009px\"><\/p>\n<h4 id=\"revisi%C3%B3n-de-jenkins\"><strong>Revisi\u00f3n de Jenkins<\/strong><\/h4>\n<p>Una vez hemos verificado nuestra infraestructura vamos a realizar la revisi\u00f3n de Jenkins.<\/p>\n<p>Con la informaci\u00f3n sacada del servicio de jenkins accederemos a la interfaz web donde nos tendremos que loguear, en nuestro caso 34.79.219.11.<\/p>\n<p>Para sacar la contrase\u00f1a de nuestro usuario de Jenkins tendremos que ejecutar el siguiente comando:<\/p>\n<pre><code class=\"language-python\">JENKINS_PASSWORD=$(kubectl get secret jenkins -n gitops -o jsonpath=\"{.data.jenkins-admin-password}\" | base64 --decode);echo\necho $JENKINS_PASSWORD <\/code><\/pre>\n<p id=\"revisi%C3%B3n-de-jenkins\">Esto nos devolver\u00e1 la contrase\u00f1a y ya podremos hacer el login:<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"1024\" height=\"486\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-ui-1024x486.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-ui-1024x486.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-ui-300x142.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-ui-768x365.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-ui.png 1365w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Como se puede observar una vez dentro de Jenkins tenemos la configuraci\u00f3n que hemos realizado con Jcasc y la creaci\u00f3n del job que hemos definido con JobDsl.<\/p>\n<h4 id=\"revisi%C3%B3n-de-grafana\"><strong>Revisi\u00f3n de Grafana<\/strong><\/h4>\n<p>Para la revisi\u00f3n de Grafana debemos acceder tambi\u00e9n a la interfaz web y loguearnos. La direcci\u00f3n de la interfaz web la podemos observar con el comando de kubectl lanzado anteriormente en nuestro caso es 34.140.61.173.<\/p>\n<p>Para loguearnos usaremos la informaci\u00f3n que pasamos por nuestras variables de entorno, TF_VAR_password_grafana y TF_VAR_user_grafana.<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"489\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-ui-1024x489.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-ui-1024x489.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-ui-300x143.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-ui-768x366.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-ui.png 1358w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Podemos comprobar que la configuraci\u00f3n que hemos a\u00f1adido al template de creaci\u00f3n de datasources y dashboards es correcta.<\/p>\n<ul>\n<li><strong>Datasources:<\/strong><\/li>\n<\/ul>\n<p><img decoding=\"async\" width=\"1024\" height=\"493\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-datasources-ui-1024x493.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-datasources-ui-1024x493.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-datasources-ui-300x144.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-datasources-ui-768x370.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-datasources-ui.png 1351w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<ul>\n<li><strong>Dashboards:<\/strong><\/li>\n<\/ul>\n<p><img decoding=\"async\" width=\"1024\" height=\"489\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-dashboards-ui-1024x489.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-dashboards-ui-1024x489.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-dashboards-ui-300x143.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-dashboards-ui-768x367.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/grafana-dashboards-ui.png 1359w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<h2>Job de prueba<\/h2>\n<p>Para nuestro ejemplo usaremos un proyecto que desplegar\u00e1 un resource group en Azure, se encuentra en el siguiente&nbsp;<a href=\"https:\/\/github.com\/lucasberlang\/terraform-azure-test\">repositorio<\/a>.<\/p>\n<p>Lo m\u00e1s destacable de este proyecto es la definici\u00f3n de nuestro pipeline de ejecuci\u00f3n:<\/p>\n<pre><code class=\"language-python\">pipeline {\n  agent {\n      label \"terraform-exec\"\n  }\n stages {\n  stage('checkout') {\n   steps {\n    container('terraform') {\n     echo \"La rama de la que se va a hacer el checkout es: master\"\n     git branch: \"master\", url: 'https:\/\/github.com\/lucasberlang\/terraform-azure-test.git'\n    }\n   }\n  }\n   stage('Review Terraform version') {\n    steps {\n    container('terraform') {\n      sh 'terraform --version'\n    }\n    }\n   }\n   stage('Terraform init') {\n    steps {\n    container('terraform') {\n      sh 'terraform init -upgrade'\n    }\n   }\n   }\n  stage('Terraform plan infrastructure') {\n    steps {\n    container('terraform') {\n     withCredentials([string(credentialsId: 'vaultUrl', variable: 'VAULT_ADDR'),\n     string(credentialsId: 'vaultToken', variable: 'VAULT_TOKEN')\n     ]) {\n      sh 'export VAULT_ADDR=${VAULT_ADDR} &amp;&amp; export VAULT_TOKEN=${VAULT_TOKEN} &amp;&amp; terraform plan'\n     slackSend channel: \"#practica-cloud-deployments\",color: '#BADA55', message: \"Plan completed! Do you approve deployment? ${env.RUN_DISPLAY_URL}\"\n     }\n    }\n   }\n  }\n  stage('Approval') {\n   when{\n    not {\n     branch 'poc'\n    }\n   }\n   steps {\n    container('terraform') {\n     script {\n     def userInput = input(id: 'confirm', message: 'Apply Terraform?', parameters: [ [$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Apply terraform', name: 'confirm'] ])\n     }\n    }\n   }\n  }\n  stage('Terraform Apply') {\n    steps {\n    container('terraform') {\n     withCredentials([string(credentialsId: 'vaultUrl', variable: 'VAULT_ADDR'),\n     string(credentialsId: 'vaultToken', variable: 'VAULT_TOKEN')\n     ]) {\n      sh 'export VAULT_ADDR=${VAULT_ADDR} &amp;&amp; export VAULT_TOKEN=${VAULT_TOKEN} &amp;&amp; terraform apply -auto-approve'\n     slackSend color: '#BADA55', message: \"Apply completed! Build logs from jenkins server ${env.RUN_DISPLAY_URL}\"\n     }\n    }\n    }\n  }\n  stage('Waiting to review the infrastructure') {\n    steps {\n    container('terraform') {\n     slackSend channel: \"#practica-cloud-deployments\", color: '#BADA55', message: \"Waiting 5 minutes before destroy the infrastructure!\"\n     sh 'sleep 300'\n    }\n   }\n  }\n  stage('Destroy Infra') {\n    steps {\n    container('terraform') {\n     withCredentials([string(credentialsId: 'vaultUrl', variable: 'VAULT_ADDR'),\n     string(credentialsId: 'vaultToken', variable: 'VAULT_TOKEN')\n     ]) {\n      sh 'export VAULT_ADDR=${VAULT_ADDR} &amp;&amp; export VAULT_TOKEN=${VAULT_TOKEN} &amp;&amp; terraform destroy -auto-approve'\n     slackSend channel: \"#practica-cloud-deployments\", color: '#BADA55', message: \"Destroy completed! Build logs from jenkins server ${env.RUN_DISPLAY_URL}\"\n     }\n    }\n    }\n  }\n }\n} <\/code><\/pre>\n<p>En el pipeline se han definido las siguientes stages:<\/p>\n<ul>\n<li><strong>Checkout:<\/strong>&nbsp;se har\u00e1 el checkoput de nuestro proyecto.<\/li>\n<li><strong>Review Terraform Version:<\/strong>&nbsp;revisaremos la versi\u00f3n de terraform desplegada en nuestro contenedor agente.<\/li>\n<li><strong>Terraform init:<\/strong>&nbsp;stage de inicializaci\u00f3n de entorno.<\/li>\n<li><strong>Terraform plan infrastructure:<\/strong>&nbsp;revisi\u00f3n de la infraestructura a desplegar en nuestro caso un resource group de Azure.<\/li>\n<li><strong>Approval:<\/strong>&nbsp;paso de aprobaci\u00f3n manual para comprobar si la infraestructura a desplegar es correcta.<\/li>\n<li><strong>Terraform Apply:<\/strong>&nbsp;ejecuci\u00f3n y creaci\u00f3n de toda la infraestructura que vamos a realizar en Azure.<\/li>\n<li><strong>Waiting to review the infrastructure:<\/strong>&nbsp;solo como para la demo haremos una espera de 5 minutos para revisar toda nuestra infraestructura.<\/li>\n<li><strong>Destroy Infra:<\/strong>&nbsp;destrucci\u00f3n de toda la infraestructura una vez esperado estos 5 minutos.<\/li>\n<\/ul>\n<h2>Ejecuci\u00f3n end to end<\/h2>\n<p>Una vez realizado todas las comprobaciones pertinentes vamos a ejecutar el job de prueba en Jenkins para ver como escala nuestra plataforma as\u00ed como el env\u00edo de alertas y la monitorizaci\u00f3n que realizaremos en Grafana.<\/p>\n<p>Accederemos a nuestro job de prueba y lo ejecutaremos, d\u00e1ndole al bot\u00f3n construir ahora:<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"491\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jobs-jenkins-running-1024x491.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jobs-jenkins-running-1024x491.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jobs-jenkins-running-300x144.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jobs-jenkins-running-768x368.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jobs-jenkins-running.png 1343w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Una vez que el job esta lanzado podemos comprobar c\u00f3mo se instancia un nuevo agente de Jenkins para nuestra ejecuci\u00f3n teniendo as\u00ed una infraestructura totalmente escalable:<\/p>\n<pre><code class=\"language-python\">watch -n 1 kubectl get pods -n gitops <\/code><\/pre>\n<p><img decoding=\"async\" width=\"855\" height=\"210\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slaves-running.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slaves-running.png 855w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slaves-running-300x74.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slaves-running-768x189.png 768w\" sizes=\"(max-width: 855px) 100vw, 855px\"><\/p>\n<p>Cuando el job este ejecutando podemos observar c\u00f3mo nos van a ir llegando alertas autom\u00e1ticamente al Slack. La primera alerta llegar\u00e1 en el stage de approval donde nos pedir\u00e1 Jenkins que revisemos la infraestructura que vamos a desplegar y si es correcta aprobaremos el cambio:<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"711\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-job-alert-1024x711.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-job-alert-1024x711.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-job-alert-300x208.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-job-alert-768x533.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/slack-job-alert.png 1520w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Y una vez que entremos en el link de slack nos saltar\u00e1 directamente la interfaz de blueocean:<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"499\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/approval-blue-jenkins-1024x499.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/approval-blue-jenkins-1024x499.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/approval-blue-jenkins-300x146.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/approval-blue-jenkins-768x374.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/approval-blue-jenkins.png 1326w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Una vez aprobado el cambio se realizar\u00e1 el despliegue en nuestra cuenta de Azure, donde podemos revisar que esta todo correcto y el resource group, en nuestro caso example-test, se ha desplegado correctamente:<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"457\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/azure-resource-group-1024x457.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/azure-resource-group-1024x457.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/azure-resource-group-300x134.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/azure-resource-group-768x343.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/azure-resource-group.png 1331w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Por \u00faltimo podemos observar todas las alertas que hemos recibido en nuestro canal de Slack las cuales nos avisaran en el stage de approval, waiting y destroy de la infra:<\/p>\n<p><img decoding=\"async\" width=\"732\" height=\"223\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/all-alerts-slack.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/all-alerts-slack.png 732w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/all-alerts-slack-300x91.png 300w\" sizes=\"(max-width: 732px) 100vw, 732px\"><\/p>\n<h2>Escalabilidad de la soluci\u00f3n<\/h2>\n<p>Una vez que hemos comprobado que nuestra soluci\u00f3n est\u00e1 totalmente automatizada y que funciona correctamente vamos a comprobar la escalabilidad de nuestra plataforma.<\/p>\n<p>Para ello lo que vamos a hacer es lanzar m\u00faltiples ejecuciones de nuestro job de Jenkins para ver c\u00f3mo va desplegando la soluci\u00f3n tanto a nivel de agentes (Levantar\u00e1 un pod por ejecuci\u00f3n) como la escalabilidad de nuestros nodos cuando tengamos m\u00e1s peticiones y consumo de memoria y CPU.<\/p>\n<p>El primer paso ser\u00e1 ejecutar m\u00faltiples jobs desde la interfaz web:<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"593\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins-1024x593.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins-1024x593.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins-300x174.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins-768x445.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins-1536x890.png 1536w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-jobs-jenkins.png 1807w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<p>Como se puede observar nuestros pods ir\u00e1n escalando seg\u00fan el n\u00famero de ejecuciones que tenemos:<\/p>\n<p><img decoding=\"async\" width=\"844\" height=\"409\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-pods-slaves.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-pods-slaves.png 844w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-pods-slaves-300x145.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/multiple-pods-slaves-768x372.png 768w\" sizes=\"(max-width: 844px) 100vw, 844px\"><\/p>\n<p>Para ver como escala a nivel de m\u00e1quinas usaremos el siguiente comando:<\/p>\n<pre><code class=\"language-python\">watch -n 1 kubectl get nodes <\/code><\/pre>\n<p><img decoding=\"async\" width=\"888\" height=\"177\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/auto-scale-nodes.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/auto-scale-nodes.png 888w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/auto-scale-nodes-300x60.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/auto-scale-nodes-768x153.png 768w\" sizes=\"(max-width: 888px) 100vw, 888px\"><\/p>\n<p>Como se puede observar se ha agregado un nuevo nodo hace 23 segundos por lo que nuestra plataforma es capaz de ir escalando seg\u00fan las peticiones que se realicen desde nuestro Jenkins.<\/p>\n<h2>Monitorizaci\u00f3n de la plataforma<\/h2>\n<p>Dado que hemos realizado tanto la configuraci\u00f3n de Grafana como la de Prometheus vamos a hacer uso de nuestros dashboards predefinidos para monitorizar la plataforma en Grafana y el env\u00edo de alertas con Prometheus.<\/p>\n<h4 id=\"dashboards\"><strong>Dashboards<\/strong><\/h4>\n<p>Estos dashboards que hemos creado son los siguientes:<\/p>\n<ul>\n<li><strong>Jenkins: Performance and Health Overview:<\/strong>&nbsp;dashboard con informaci\u00f3n relativa a nuestras ejecuciones en Jenkins, n\u00famero de jobs, memoria utilizada&#8230; .<\/li>\n<\/ul>\n<p><img decoding=\"async\" width=\"1024\" height=\"543\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring-1024x543.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring-1024x543.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring-300x159.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring-768x408.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring-1536x815.png 1536w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-monitoring.png 1826w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<ul>\n<li><strong>Kubernetes Cluster:<\/strong>&nbsp;en este dahsboard tendremos informaci\u00f3n del cluster de kubernetes a nivel de pods corriendo en el cluster memoria consumida por pod etc.<\/li>\n<\/ul>\n<p><img decoding=\"async\" width=\"1024\" height=\"564\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring-1024x564.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring-1024x564.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring-300x165.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring-768x423.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring-1536x847.png 1536w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-kubernetes-monitoring.png 1827w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<ul>\n<li><strong>Kubernetes Cluster:<\/strong>&nbsp;en el \u00faltimo dahsboard se mostrar\u00e1 gr\u00e1ficos de picos de red, CPUs y memoria a nivel de m\u00e1quinas en el Cluster de GKE.<\/li>\n<\/ul>\n<p><img decoding=\"async\" width=\"1024\" height=\"599\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring-1024x599.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring-1024x599.png 1024w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring-300x175.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring-768x449.png 768w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring-1536x898.png 1536w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/cluster-cpu-monitoring.png 1755w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"><\/p>\n<h2>Alertas del sistema<\/h2>\n<p>Adem\u00e1s de alertas cuando se ejecuta un job tambi\u00e9n se hemos realizado la configuraci\u00f3n de alertas de la infraestructura v\u00eda Prometheus. Este nos enviar\u00e1 alertas cuando el pod de Jenkins este ca\u00eddo o alguno de los nodos del cluster se caiga.<\/p>\n<p>Para hacerlo un poco m\u00e1s ilustrativo usaremos el ejemplo de autoescalado que hemos realizado antes para que Prometheus nos env\u00ede una alerta cuando empiece a quitarse m\u00e1quinas porque el cluster de GKE detecte que no se est\u00e1 consumiendo tanta memoria.<\/p>\n<p>Cuando hicimos la prueba de&nbsp;<a href=\"\/#escalabilidad-de-la-soluci%C3%B3n\"><strong>autoescalado<\/strong><\/a>&nbsp;vimos como se hab\u00eda agregado un nuevo nodo llamado gke-go-euw2-bk-sca-g-default-node-poo-c9c04d95-sgmz. Este despu\u00e9s del pico de ejecuciones de jobs en Jenkins se auto eliminar\u00e1 ya que no tendremos tanta actividad en nuestro GKE.<\/p>\n<p><img decoding=\"async\" width=\"892\" height=\"117\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes.png 892w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes-300x39.png 300w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/nodes-kubernetes-768x101.png 768w\" sizes=\"(max-width: 892px) 100vw, 892px\"><\/p>\n<p>Prometheus al detectar que nuestro nodo ha desaparecido nos enviar\u00e1 una alerta de nodo ca\u00eddo autom\u00e1ticamente a Slack.<\/p>\n<p><img decoding=\"async\" width=\"712\" height=\"807\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/down-scale-nodes-alert.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/down-scale-nodes-alert.png 712w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/down-scale-nodes-alert-265x300.png 265w\" sizes=\"(max-width: 712px) 100vw, 712px\"><\/p>\n<p>As\u00ed sabremos de una forma totalmente automatizada si nuestra infraestructura ha sufrido alg\u00fan problema.<\/p>\n<p>Para el caso de los pods lo que vamos a provocar es una ca\u00edda del componente de Jenkins para que as\u00ed Prometheus nos env\u00ede una alerta de pod ca\u00eddo.<\/p>\n<p>Para ello lo que vamos a realizar es la destrucci\u00f3n del pod de Jenkins para provocar una ca\u00edda del servicio:<\/p>\n<pre><code class=\"language-python\">kubectl delete pod jenkins-0 -n gitops <\/code><\/pre>\n<p>Una vez que el pod este eliminado se arrancar\u00e1 autom\u00e1ticamente:<\/p>\n<p><img decoding=\"async\" width=\"551\" height=\"151\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/delete-pod-jenkins.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/delete-pod-jenkins.png 551w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/delete-pod-jenkins-300x82.png 300w\" sizes=\"(max-width: 551px) 100vw, 551px\"><\/p>\n<p>Y pasado un minuto Prometheus nos avisar\u00e1 de la ca\u00edda del servicio de Jenkins y de su posterior recuperaci\u00f3n:<\/p>\n<p><img decoding=\"async\" width=\"677\" height=\"426\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-delete-alert.png\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-delete-alert.png 677w, https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/jenkins-delete-alert-300x189.png 300w\" sizes=\"(max-width: 677px) 100vw, 677px\"><\/p>\n<h2>Eliminaci\u00f3n de recursos<\/h2>\n<p>El \u00faltimo paso que haremos tras probar el \u00e9xito de nuestra plataforma CI\/CD ser\u00e1 realizar la destrucci\u00f3n de todos sus componentes para ello ejecutaremos el siguiente comando:<\/p>\n<pre><code class=\"language-python\">cd src\/\nterraform destroy <\/code><\/pre>\n<h2>Conclusi\u00f3n<\/h2>\n<p>Es de sobra conocido la importancia de automatizar el ciclo de vida del desarrollo software pero en este art\u00edculo le hemos querido dar una vuelta m\u00e1s a esta automatizaci\u00f3n consiguiendo industrializar toda nuestra plataforma CI\/CD. Para ello hemos automatizado tanto el levantamiento de toda nuestra infraestructura con Terraform as\u00ed como la configuraci\u00f3n inicial de nuestras tres piezas centrales Jenkins, Prometheus y Grafana.<\/p>\n<p>Haciendo uso de plugin como Jcasc conseguimos automatizar toda la configuraci\u00f3n inicial de Jenkins que muchas veces es bastante tediosa de hacer de arranque. Esto nos permite que si alguna vez hay una ca\u00edda de nuestro servicio siempre mantendremos una configuraci\u00f3n base en este, evitando tiempos de configuraci\u00f3n que al final se reduce en tiempo de espera para el usuario.<\/p>\n<p>Adem\u00e1s, a\u00f1adiendo una monitorizaci\u00f3n inicial tanto con Prometheus como con Grafana somos capaces de crear un sistema de avisos que nos ayude a comprobar y chequear el correcto comportamiento de toda nuestra plataforma para as\u00ed poder evitar futuras incidencias.<\/p>\n<p>Por \u00faltimo el uso de GKE en este tipo de plataformas consiguen un ahorro de costes bastante importante en nuestra organizaci\u00f3n ya que nos da la posibilidad de tener un autoescalado dependiendo del uso que se est\u00e9 realizando sobre nuestra plataforma, pudiendo as\u00ed tener picos de gran carga sin tener un deterioro del servicio.<\/p>\n<h6><strong>Navegaci\u00f3n<\/strong><\/h6>\n<p><a href=\"\/#introduccion\">Introducci\u00f3n<\/a><\/p>\n<p><a href=\"\/#objetivos\">Objetivos<\/a><\/p>\n<p><a href=\"\/#into-terra\">Introducci\u00f3n a Terraform<\/a><\/p>\n<p><a href=\"\/#into-gke\">Introducci\u00f3n a GKE<\/a><\/p>\n<p><a href=\"\/#into-jenkins\">Introducci\u00f3n a Jenkins<\/a><\/p>\n<p><a href=\"\/#into-prome\">Introducci\u00f3n a Prometheus<\/a><\/p>\n<p><a href=\"\/#into-grafa\">Introducci\u00f3n a Grafana<\/a><\/p>\n<p><a href=\"\/#into-slack\">Introducci\u00f3n a Slack<\/a><\/p>\n<p><a href=\"\/#pre-entorno\">Preparaci\u00f3n de entorno<\/a><\/p>\n<p><a href=\"\/#clon-repo\">Clonaci\u00f3n de repositorio<\/a><\/p>\n<p><a href=\"\/#indi-fiche\">\u00cdndice de ficheros<\/a><\/p>\n<p><a href=\"\/#confi-slack\">Configuraci\u00f3n de Slack<\/a><\/p>\n<p><a href=\"\/#confi-variables\">Configuraci\u00f3n de variables<\/a><\/p>\n<p><a href=\"\/#confi-vpc\">Configuraci\u00f3n VPC<\/a><\/p>\n<p><a href=\"\/#confi-gke\">Configuraci\u00f3n GKE<\/a><\/p>\n<p><a href=\"\/#confi-jenkins\">Configuraci\u00f3n Jenkins<\/a><\/p>\n<p><a href=\"\/#confi-prome\">Configuraci\u00f3n Prometheus<\/a><\/p>\n<p><a href=\"\/#confi-grafa\">Configuraci\u00f3n Grafana<\/a><\/p>\n<p><a href=\"\/#despli-infra\">Despliegue de la infraestructura<\/a><\/p>\n<p><a href=\"\/#job\">Job de prueba<\/a><\/p>\n<p><a href=\"\/#ejec-end\">Ejecuci\u00f3n end to end<\/a><\/p>\n<p><a href=\"\/#escala\">Escalabilidad de la soluci\u00f3n<\/a><\/p>\n<p><a href=\"\/#monito\">Monitorizaci\u00f3n de la plataforma<\/a><\/p>\n<p><a href=\"\/#elimina\">Eliminaci\u00f3n de recursos<\/a><\/p>\n<p><a href=\"\/#conclusion\">Conclusi\u00f3n<\/a><\/p>\n<p><a href=\"\/#autor\">Autor<\/a><\/p>\n<h5>\u00bfQuieres saber m\u00e1s de lo que ofrecemos y ver otros casos de \u00e9xito?<\/h5>\n<p><a href=\"\/\" role=\"button\"><br \/>\nDESCUBRE BLUETAB<br \/>\n<\/a><br \/>\nShare on twitter<br \/>\nShare on linkedin<\/p>\n<figure><img decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/bluetab.net\/wp-content\/uploads\/2021\/09\/lucas-150x150.png\" alt=\"\" loading=\"lazy\"><\/figure>\n<h4>Lucas Calvo Berlanga<\/h4>\n<p>Cloud Engineer<\/p>\n<p><b>SOLUCIONES, <\/b>SOMOS EXPERTOS<\/p>\n<p><a href=\"\/soluciones\/data-strategy\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/data-strategy\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/data-strategy\/\"><\/p>\n<h5>\n\t\t\t\t\t\tDATA STRATEGY<\/h5>\n<p><\/a><a href=\"\/soluciones\/data-strategy\/\"><\/a><a href=\"\/soluciones\/data-strategy\/\">\t\t\t\t\t\t<\/a><br \/>\n<a href=\"\/soluciones\/data-fabric\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/data-fabric\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/data-fabric\/\"><\/p>\n<h5>\n\t\t\t\t\t\tDATA FABRIC<\/h5>\n<p><\/a><a href=\"\/soluciones\/data-fabric\/\"><\/a><a href=\"\/soluciones\/data-fabric\/\">\t\t\t\t\t\t<\/a><br \/>\n<a href=\"\/soluciones\/augmented-analytics\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/augmented-analytics\/\"><\/a><\/p>\n<p><a href=\"\/soluciones\/augmented-analytics\/\"><\/p>\n<h5>\n\t\t\t\t\t\tAUGMENTED ANALYTICS<\/h5>\n<p><\/a><a href=\"\/soluciones\/augmented-analytics\/\"><\/a><a href=\"\/soluciones\/augmented-analytics\/\">\t\t\t\t\t\t<\/a><\/p>\n<p>Te puede interesar<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Desplegando una plataforma CI\/CD escalable con Jenkins y Kubernetes Lucas Calvo Berlanga Cloud Engineer Share on twitter Share on linkedin En este art\u00edculo de la&nbsp;pr\u00e1ctica cloud&nbsp;veremos c\u00f3mo crear una plataforma de CI\/CD de una forma totalmente automatizada. Para ello nos apoyaremos en una metodolog\u00eda GitOps para as\u00ed realizar nuestros despliegues de una forma m\u00e1s sencilla, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":20794,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"elementor_header_footer","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7,29,30],"tags":[],"class_list":["post-12019","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-es","category-practices-en","category-tech-en"],"acf":[],"jetpack_featured_media_url":"https:\/\/bluetab.mx\/wp-content\/uploads\/2021\/09\/12.png","_links":{"self":[{"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/posts\/12019","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/comments?post=12019"}],"version-history":[{"count":0,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/posts\/12019\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/media\/20794"}],"wp:attachment":[{"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/media?parent=12019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/categories?post=12019"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bluetab.mx\/en\/wp-json\/wp\/v2\/tags?post=12019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}