En este instructivo, se explica cómo administrar la infraestructura como código con Terraform y Jenkins mediante la metodología popular GitOps. El instructivo es para desarrolladores y operadores que buscan prácticas recomendadas a fin de administrar la infraestructura de la manera en que administran las aplicaciones de software. En el artículo, se supone que estás familiarizado con Terraform, Jenkins, GitHub, Google Kubernetes Engine (GKE) y Google Cloud.
Arquitectura
La arquitectura que se usa en este instructivo usa ramas de GitHub (dev
y prod
) para representar entornos de desarrollo y producción reales. Estos entornos se definen mediante redes de nube privada virtual (VPC) (dev
y prod
) en un proyecto de Google Cloud.
Propuesta de infraestructura
Como se muestra en el siguiente diagrama de arquitectura, el proceso comienza cuando un desarrollador o un operador hacen una propuesta de infraestructura a una rama no protegida de GitHub, por lo general, una rama de funciones. Cuando corresponda, esta rama de funciones se puede promover al entorno de desarrollo a través de una solicitud de extracción (PR) a la rama dev
. Luego, Jenkins activa de forma automática un trabajo para ejecutar la canalización de validación. Este trabajo ejecuta el comando terraform plan
e informa el resultado de la validación a GitHub y, además, incluye un vínculo a un informe detallado de cambios en la infraestructura. Este paso es fundamental porque te permite revisar posibles cambios con los colaboradores y agregar confirmaciones de seguimiento antes de que los cambios se combinen en la rama dev
.
Implementación Dev
Si el proceso de validación se realiza de forma correcta y apruebas los cambios propuestos en la infraestructura, puedes combinar la solicitud de extracción en la rama dev
. En el diagrama a continuación, se muestra este proceso.
Cuando se completa la combinación, Jenkins activa otro trabajo para ejecutar la canalización de implementación. En esta situación, el trabajo aplica los manifiestos de Terraform en el entorno de desarrollo para lograr el estado que deseas. Este paso es importante porque te permite probar el código de Terraform antes de ascenderlo a producción.
Implementación Prod
Después de realizar las pruebas y estar listo para promover los cambios a la producción, debes combinar la rama dev
con la rama prod
a fin de activar la instalación de la infraestructura en el entorno de producción. En el diagrama a continuación, se muestra este proceso.
El mismo proceso de validación se ejecuta cuando creas la solicitud de extracción. Este proceso permite que el equipo de operaciones revise y apruebe los cambios propuestos para la producción.
Objetivos
- Configurar el repositorio de GitHub
- Crear el almacenamiento de estado remoto de Terraform
- Crear un clúster de GKE e instalar Jenkins
- Cambiar la configuración del entorno en una rama de funciones
- Promover los cambios en el entorno de desarrollo.
- Promover los cambios en el entorno de producción.
Costos
En este instructivo, se usan los siguientes componentes facturables de Google Cloud:
Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud sean aptos para obtener una prueba gratuita.
Cuando finalices este instructivo, podrás borrar los recursos creados para evitar que se te siga facturando. Para obtener más información, consulta cómo hacer una limpieza.
Antes de comenzar
- Accede a tu Cuenta de Google.
Si todavía no tienes una cuenta, regístrate para obtener una nueva.
-
En la página del selector de proyectos de Google Cloud Console, selecciona o crea un proyecto de Google Cloud.
-
Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Descubre cómo confirmar que tienes habilitada la facturación en un proyecto.
-
En Cloud Console, activa Cloud Shell.
En la parte inferior de Cloud Console, se inicia una sesión de Cloud Shell en la que se muestra una ventana de línea de comandos. Cloud Shell es un entorno de shell que tiene el SDK de Cloud preinstalado, incluida la herramienta de línea de comandos de
gcloud
, y valores ya establecidos para el proyecto actual. La inicialización de la sesión puede tomar unos minutos. - En Cloud Shell, configura el ID del proyecto y el nombre de usuario y la dirección de correo electrónico de GitHub:
PROJECT_ID=PROJECT_ID GITHUB_USER=YOUR_GITHUB_USER GITHUB_EMAIL=YOUR_EMAIL_ADDRESS gcloud config set project $PROJECT_ID
Si no accediste a GitHub desde Cloud Shell antes, puedes configurarlo con tu nombre de usuario y dirección de correo electrónico:
git config --global user.email "$GITHUB_EMAIL" git config --global user.name "$GITHUB_USER"
GitHub usa esta información para identificarte como el autor de las confirmaciones que creas en Cloud Shell.
Configura un repositorio de GitHub
En este instructivo, usarás un único repositorio de GitHub para definir la infraestructura de nube. Para organizar esta infraestructura debes tener diferentes ramas que correspondan a diferentes entornos:
- La rama
dev
contiene los cambios más recientes que se aplican al entorno de desarrollo. - La rama
prod
contiene los cambios más recientes que se aplican al entorno de producción.
Con esta infraestructura, siempre se puede hacer referencia al repositorio a fin de saber qué configuración se espera en cada entorno y combinar cambios nuevos en el entorno dev
para proponerlos. A continuación, debes combinar la rama dev
con la rama prod
para promover los cambios.
Para comenzar, debes bifurcar el repositorio solutions-terraform-jenkins-gitops
.
- En GitHub, ve al repositorio
solutions-terraform-jenkins-gitops
. Haz clic en Fork.
Ahora tienes una copia del repositorio
solutions-terraform-jenkins-gitops
con archivos de origen.En Cloud Shell, clona este repositorio bifurcado:
cd ~ git clone https://github.com/$GITHUB_USER/solutions-terraform-jenkins-gitops.git cd ~/solutions-terraform-jenkins-gitops
El código de este repositorio está estructurado de la siguiente manera:
- Carpeta
example-pipelines/
: Contiene subcarpetas con la canalización de ejemplo que se usó en este instructivo. example-create/
: Contiene el código de Terraform para crear una máquina virtual en el entorno.environments/
: Contiene carpetas del entornodev
yprod
con configuraciones de backend y vínculos a archivos de la carpetaexample-create/
.- Carpeta
jenkins-gke/
: Contiene secuencias de comandos necesarias para implementar Jenkins en un clúster de GKE nuevo. tf-gke/
: Contiene el código de Terraform para implementar en GKE e instalar Jenkins y sus recursos dependientes.
- Carpeta
Crea el almacenamiento de estado remoto de Terraform
De forma predeterminada, el estado de Terraform se almacena de forma local. Sin embargo, te recomendamos almacenar el estado en el almacenamiento central remoto al que puedes acceder desde cualquier sistema. Este enfoque te ayuda a evitar crear varias copias en sistemas diferentes, lo que puede provocar que la configuración y los estados de la infraestructura no coincidan.
En esta sección, configurarás un bucket de Cloud Storage que almacena el estado remoto de Terraform.
En Cloud Shell, crea un bucket de Cloud Storage:
gsutil mb gs://${PROJECT_ID}-tfstate
Habilita el control de versiones de objetos para mantener el historial de los estados:
gsutil versioning set on gs://${PROJECT_ID}-tfstate
Reemplaza el marcador de posición PROJECT_ID por el ID del proyecto en los archivos
terraform.tfvars
ybackend.tf
:sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./example-pipelines/environments/*/terraform.tfvars sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./example-pipelines/environments/*/backend.tf sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./jenkins-gke/tf-gke/terraform.tfvars sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./jenkins-gke/tf-gke/backend.tf
Verifica si todos los archivos se actualizaron:
git status
El resultado luce de la siguiente manera:
On branch dev Your branch is up-to-date with 'origin/dev'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: example-pipelines/environments/dev/backend.tf modified: example-pipelines/environments/dev/terraform.tfvars modified: example-pipelines/environments/prod/backend.tf modified: example-pipelines/environments/prod/terraform.tfvars modified: jenkins-gke/tf-gke/backend.tf modified: jenkins-gke/tf-gke/terraform.tfvars
Confirma y envía los cambios:
git add --all git commit -m "Update project IDs and buckets" git push origin dev
Según la configuración de GitHub, es posible que debas autenticarte para enviar los cambios anteriores.
Crea un clúster de GKE e instala Jenkins
En esta sección, usas Terraform y Helm para configurar el entorno a fin de administrar la infraestructura como código. Primero, usa Terraform y Cloud Foundations Toolkit para configurar una nube privada virtual, un clúster de GKE y Workload Identity. Luego, usa helm para instalar Jenkins sobre este entorno.
Antes de comenzar a ejecutar comandos de Terraform, debes crear un token de acceso personal de GitHub. Este token es necesario para permitir que Jenkins acceda al repositorio bifurcado.
Crea un token de acceso personal de GitHub
- Accede a GitHub.
- Haz clic en tu foto de perfil y, luego, en Settings.
- Haz clic en Developer settings y, luego, en Personal access tokens.
- Haz clic en Generate new token y agrega una descripción del token en el campo Note, luego, selecciona el alcance de repo.
Haz clic en Generate token y copia el token recién creado en el portapapeles.
En Cloud Shell, guarda el token en la variable
GITHUB_TOKEN
. Este contenido de la variable se almacena más tarde como un Secret en el clúster de GKE.GITHUB_TOKEN="NEWLY_CREATED_TOKEN"
Crea un clúster de GKE e instala Jenkins
Ahora crearás el clúster de GKE. Este clúster incluye una Workload Identity (jenkins-wi-jenkins@PROJECT_ID.iam.gserviceaccount.com
), que te permite darle a Jenkins el permiso que necesita en la página Cuentas de servicio en Cloud Console.
Debido a las propiedades de seguridad y la capacidad de administración mejoradas, recomendamos usar Workload Identity para acceder a los servicios de Google Cloud desde GKE.
Para administrar la infraestructura de Google Cloud como código, Jenkins debe autenticarse a fin de usar las API de Google Cloud. En los siguientes pasos, Terraform configura la cuenta de servicio de Kubernetes (KSA) que Jenkins usa para que actúe como una cuenta de servicio de Google (GSA). Esta configuración permite que Jenkins se autentique de forma automática como GSA cuando accede a las API de Google Cloud.
Para hacerlo más simple, en este instructivo, otorgas acceso de editor de proyectos. Sin embargo, debido a que esta función tiene un amplio conjunto de permisos, en entornos de producción, debes seguir las prácticas recomendadas de seguridad de TI de tu empresa, lo que implica proporcionar un acceso de mínimo privilegio.
En Cloud Shell, instala Terraform:
wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip unzip terraform_0.12.24_linux_amd64.zip sudo mv terraform /usr/local/bin/ rm terraform_0.12.24_linux_amd64.zip
Crea el clúster de GKE e instala Jenkins:
cd jenkins-gke/tf-gke/ terraform init terraform plan --var "github_username=$GITHUB_USER" --var "github_token=$GITHUB_TOKEN" terraform apply --auto-approve --var "github_username=$GITHUB_USER" --var "github_token=$GITHUB_TOKEN"
Este proceso puede llevar unos minutos para completarse. El resultado es similar al siguiente:
Apply complete! Resources: 28 added, 0 changed, 0 destroyed. Outputs: ca_certificate = LS0tLS1CRU.. client_token = <sensitive> cluster_name = jenkins gcp_service_account_email = jenkins-wi-jenkins@PROJECT_ID.iam.gserviceaccount.com jenkins_k8s_config_secrets = jenkins-k8s-config jenkins_project_id = PROJECT_ID k8s_service_account_name = jenkins-wi-jenkins kubernetes_endpoint = <sensitive> service_account = tf-gke-jenkins-k253@PROJECT_ID.iam.gserviceaccount.com zone = us-east4-a
Cuando se implementa Jenkins en el clúster de GKE que se acaba de crear, el directorio de la página principal de Jenkins se almacena en un volumen persistente según la documentación del gráfico de Helm. Esta implementación también incluye una canalización de varias ramas preconfigurada con
example-pipelines/environments/Jenkinsfile
, que se activa en solicitudes de extracción y se combina con las ramasdev
yprod
.Regresa a la carpeta principal:
cd ../..
Recupera las credenciales de clúster que acabas de crear:
gcloud container clusters get-credentials jenkins --zone=us-east4-a --project=${PROJECT_ID}
Recupera las credenciales y la URL de Jenkins:
JENKINS_IP=$(kubectl get service jenkins -o jsonpath='{.status.loadBalancer.ingress[0].ip}') JENKINS_PASSWORD=$(kubectl get secret jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo printf "Jenkins url: http://$JENKINS_IP\nJenkins user: admin\nJenkins password: $JENKINS_PASSWORD\n"
Accede a Jenkins mediante la información del resultado del paso anterior.
Configura la ubicación de Jenkins para que GitHub pueda crear vínculos que vayan directamente a las compilaciones. Haz clic en Administrar Jenkins > Configurar sistema, y en el campo URL de Jenkins, configura la URL de Jenkins.
Cambia la configuración del entorno en una rama de funciones nueva
Ya se configuró la mayor parte del entorno. Por lo tanto, es hora de hacer algunos cambios en el código.
En Cloud Shell, crea una rama de funciones nueva en la que puedas trabajar sin afectar a otras del equipo:
git checkout -b change-vm-name
Cambia el nombre de la máquina virtual:
cd example-pipelines/example-create sed -i.bak "s/\${var.environment}-001/\${var.environment}-new/g" main.tf
Estás cambiando el archivo
main.tf
en la carpetaexample-create
. Este archivo está vinculado por las carpetas del entornodev
yprod
, lo que significa que el cambio se propaga en ambos entornos.Envía el cambio de código a la rama de funciones de GitHub:
git commit -am "change vm name" git push --set-upstream origin change-vm-name
En GitHub, ve a la página principal del repositorio bifurcado.
Haz clic en la pestaña Pull requests del repositorio y, luego, en New pull request.
En base repository, selecciona el repositorio bifurcado.
En base, selecciona
dev
y, en compare, seleccionachange-vm-name
.Haz clic en Create pull request.
Cuando la solicitud de extracción está abierta, un trabajo de Jenkins se inicia de forma automática (Jenkins puede tomarse un minuto aproximadamente para confirmar la recepción de la solicitud de extracción nueva). Haz clic en Show all checks y espera a que la marca se vuelva verde.
Haz clic en Details para ver más información, incluido el resultado del comando
terraform plan
.
El trabajo de Jenkins ejecutó la canalización definida en Jenkinsfile
.
Esta canalización tiene comportamientos diferentes según la rama que se recupera. La compilación verifica si la variable TARGET_ENV
coincide con alguna carpeta de entorno. Si coincide, Jenkins ejecuta terraform plan
para ese entorno. De lo contrario, Jenkins ejecuta terraform plan
para todos los entornos a fin de garantizar que el cambio propuesto sea válido en todos ellos. Si alguno de estos planes no se ejecuta, falla la compilación.
terraform plan
se ejecuta para todas las subcarpetas example-pipelines/environments
a fin de garantizar que los cambios propuestos se apliquen a cada entorno. De esta manera, antes de combinar la solicitud de extracción, puedes revisar los planes para asegurarte de no otorgar acceso a una entidad no autorizada, por ejemplo.
Este es el código terraform plan
en JENKINSFILE
:
De manera similar, el comando terraform apply
se ejecuta para las ramas de entorno, pero se ignora en cualquier otro caso. En esta sección, enviaste un cambio de código a una rama nueva, por lo que no se aplicaron implementaciones de infraestructura en el proyecto de Cloud.
Este es el código terraform apply
en JENKINSFILE
:
Aplica de forma forzosa la ejecución exitosa de Jenkins antes de combinar las ramas
Puedes asegurarte de que las combinaciones solo se apliquen cuando las ejecuciones de trabajos de Jenkins sean exitosas.
- En GitHub, ve a la página principal del repositorio bifurcado.
- En el nombre del repositorio, haz clic en Settings.
- Haz clic en Branches.
- En Branch protection rules, haz clic en Add rule.
- En Branch name pattern, ingresa
dev
. En Protect matching branches, selecciona Require status checks to pass before merging y, luego,
continuous-integration/jenkins/pr-merge
.Considera habilitar las opciones Require pull request reviews before merging y Include administrators para evitar que las solicitudes de extracción no revisadas y no autorizadas se combinen con el entorno de producción (opcional).
Haz clic en Create.
Repite los pasos del 4 al 7 y establece el Branch name pattern en
prod
.
Esta configuración es importante para proteger las ramas dev
y prod
, lo que significa que primero debes enviar las confirmaciones a otra rama y, después, combinarlas con la rama protegida. En este instructivo, la protección requiere que la ejecución del trabajo de Jenkins sea exitosa para que se permita la combinación. Puedes ver si la configuración se aplicó en la solicitud de extracción recién creada. Busca las marcas de verificación verdes.
Promueve los cambios en el entorno de desarrollo
Tienes una solicitud de extracción en espera para combinarse. Ahora puedes aplicar el estado que deseas en el entorno dev
.
- En GitHub, ve a la página principal del repositorio bifurcado.
- Para el nombre del repositorio, haz clic en Pull requests.
- Haz clic en la solicitud de extracción que creaste.
Haz clic en Merge pull request y, luego, en Confirm merge.
En Jenkins, haz clic en Open Blue Ocean. Luego, en el proyecto de varias ramas
terraform-jenkins-create-demo
, en la pestaña Branches, verifica el ícono de estado para ver si un trabajo dev nuevo se activó. Este proceso puede llevar aproximadamente un minuto.En Cloud Console, ve a la página Instancias de VM (VM instances) y verifica si tienes la VM con el nombre nuevo.
Promueve los cambios en el entorno de producción
Ahora que probaste el entorno de desarrollo, puedes promover el código de infraestructura a la producción.
- En GitHub, ve a la página principal del repositorio bifurcado.
- Haz clic en New pull request.
En el base repository, selecciona el repositorio que bifurcaste.
En base, selecciona
prod
y, en compare, seleccionadev
.Haz clic en Create pull request.
Ingresa un título, como
Promoting vm name change
y, luego, haz clic en Create pull request.Espera a que el verificador se vuelva verde (puede llevar uno o dos minutos) y, luego, haz clic en el vínculo Details junto a
continuous-integration/jenkins/pr-merge
.En Jenkins, selecciona
TF Plan
y revisa los cambios propuestos en los registros.Si los cambios propuestos tienen un aspecto correcto, en GitHub haz clic en Merge pull request y, luego, en Confirm merge.
En Cloud Console, abre la página Instancias de VM (VM instances) y verifica si la VM de producción se implementó.
Configuraste una canalización de infraestructura como código en Jenkins. En el futuro, se recomienda probar lo siguiente:
- Agregar implementaciones para casos de uso independientes
- Crear entornos adicionales que reflejen tus necesidades
- Usar un proyecto por entorno en lugar de una VPC por entorno
Realiza una limpieza
Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:
Borra el proyecto
- En Cloud Console, ve a la página Administrar recursos.
- En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.
¿Qué sigue?
- Para obtener más información sobre la implementación y la autorización del acceso seguro a Google Cloud desde Jenkins interno, lee Jenkins en Google Cloud.
- Consulta Introducción a Workload Identity: La mejor autenticación para las aplicaciones de GKE.
- Aprende a administrar la infraestructura como código en Administra la infraestructura como código con Terraform y Cloud Build.
- Considera usar plantillas de Cloud Foundation Toolkit a fin de compilar con rapidez una base lista para empresas repetible en Google Cloud.
- Consulta Entrega continua del tipo GitOps con Cloud Build.
- Prueba funciones más avanzadas de Cloud Build:
- Prueba otras funciones de Google Cloud. Consulta nuestros instructivos.