Crear imágenes base personalizadas para Compute Engine con Jenkins y Packer

En este instructivo se muestra cómo convertir tus CD-ROM ISO existentes y las instalaciones de secuencias de comandos de Kickstart en imágenes base personalizadas para Compute Engine, a través de Jenkins, Packer y QEMU. GCP incluye un conjunto variado de imágenes base, por lo que no siempre es necesario que crees imágenes base personalizadas.

diagrama de arquitectura

En este instructivo se utiliza el complemento de Jenkins para Compute Engine a fin de aprovisionar instancias de procesamiento en forma de agentes Jenkins, que crean la imagen base personalizada en última instancia.

Objetivos

  • Crear un clúster de Google Kubernetes Engine.
  • Instalar Helm, un paquete de administración de Kubernetes.
  • Instalar Jenkins a través de Helm.
  • Configurar Jenkins para que utilice las instancias de Compute Engine como agentes.
  • Configurar un trabajo de Jenkins para ejecutar los trabajos de Packer.
  • Crear un trabajo de Jenkins para personalizar una imagen ISO existente y, luego, importar los resultados como una imagen de Compute Engine.

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud Platform:

  • Compute Engine
  • GKE
  • Cloud Storage

Para generar una estimación de costos en función del uso proyectado, usa la calculadora de precios. Los usuarios nuevos de GCP pueden optar por a una prueba gratuita.

Por ejemplo, supongamos que utilizas una sola máquina virtual de Compute Engine por única vez durante 77 minutos, el costo total será $176. Para obtener más información, consulta esta estimación.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En GCP Console, en la página de selección de proyecto, selecciona o crea un proyecto de GCP.

    Ir a la página de selección de proyecto

  3. Comprueba que la facturación esté habilitada en tu proyecto.

    Descubre cómo puedes habilitar la facturación

  4. Habilita lasCompute EngineAPI.

    Habilita lasAPI

Cuando finalices este instructivo, puedes borrar los recursos creados para evitar que se te siga facturando. Consulta Limpiar para obtener más información.

Preparar tu entorno

Cloud Shell te brinda acceso a la línea de comandos en GCP Console e incluye el SDK de Cloud, así como otras herramientas que utilizarás para desarrollar en GCP. Cloud Shell aparece como una ventana en la parte inferior de GCP Console. Puede tardar varios minutos en inicializarse, pero la ventana aparecerá inmediatamente.

  1. Activa Cloud Shell:

    ACTIVAR Cloud Shell

  2. Configura tu entorno en Cloud Shell.

    export PROJECT=$(gcloud info --format='value(config.project)')
  3. Configura la zona predeterminada de Compute Engine:

    export ZONE=us-central1-b
    gcloud config set compute/zone $ZONE
    
  4. Habilita la API de Kubernetes Engine:

    gcloud services enable container.googleapis.com
    
  5. Crea un depósito de almacenamiento para subir imágenes:

    gsutil mb "gs://$PROJECT-custom-images"
    

Implementar el servidor de Jenkins

En esta sección, crearás un clúster de Kubernetes en el que se alojará Jenkins; instalarás Helm para implementar Jenkins en el clúster; instalarás y te conectarás a Jenkins, y desde allí configurarás una cuenta de servicio.

Crear y configurar un clúster de Kubernetes

  1. Crea el clúster de Kubernetes en el que se alojará Jenkins:

    VERSION=$(gcloud container get-server-config --zone $ZONE \
         --format='value(validMasterVersions[0])')
    gcloud container clusters create builder --zone=$ZONE \
        --cluster-version=${VERSION} \
        --machine-type n1-standard-2 \
        --num-nodes 2 \
        --scopes='https://www.googleapis.com/auth/projecthosting,storage-rw,cloud-platform'
    
  2. Confirma que el estado del clúster sea RUNNING:

    gcloud container clusters list
    

    Resultado esperado:

    NAME     LOCATION       MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION    NUM_NODES  STATUS
    builder  us-central1-b  1.10.7-gke.11   35.184.60.60  n1-standard-2  1.10.7-gke.6 *  2          RUNNING
    

Instalar Helm

Helm se utiliza para implementar aplicaciones en tu clúster de Kubernetes. Luego de crear tu clúster, configura Helm para que funcione con el clúster.

  1. En Cloud Shell, obtén las credenciales para el clúster de Kubernetes:

    gcloud container clusters get-credentials builder
    
  2. Descarga y extrae Helm:

    wget https://storage.googleapis.com/kubernetes-helm/\
    helm-v2.9.1-linux-amd64.tar.gz
    tar zxfv helm-v2.9.1-linux-amd64.tar.gz
    cp linux-amd64/helm .
    
  3. Asigna los controles de acceso adecuados para otorgarle a Jenkins permisos en el clúster:

    kubectl create clusterrolebinding \
        cluster-admin-binding --clusterrole=cluster-admin \
        --user=$(gcloud config get-value account)
    
  4. Otórgale la función de cluster-admin a Tiller en tu clúster, el lado del servidor de Helm:

    kubectl create serviceaccount tiller --namespace kube-system
    kubectl create clusterrolebinding tiller-admin-binding --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
    
  5. Instala Helm:

    ./helm init --service-account=tiller
    ./helm update
    
  6. Verifica la instalación de Helm:

    ./helm version
    

    Resultado esperado:

    Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
    

Instalar Jenkins en el clúster de Kubernetes

  1. En Cloud Shell, crea la configuración inicial de Jenkins a través de los valores para el gráfico de Helm:

    cat <<CONFIG >values.yaml
    Master:
      InstallPlugins:
        - kubernetes:1.12.6
        - workflow-aggregator:2.5
        - workflow-job:2.21
        - credentials-binding:1.16
        - git:3.9.1
        - google-oauth-plugin:0.6
        - google-source-plugin:0.3
        - google-compute-engine:1.0.5
        - google-storage-plugin:1.2
        - packer:1.5
      Cpu: "1"
      Memory: "3500Mi"
      JavaOpts: "-Xms3500m -Xmx3500m"
      ServiceType: ClusterIP
    Agent:
      Enabled: false
    Persistence:
      Size: 100Gi
    NetworkPolicy:
      ApiVersion: networking.k8s.io/v1
    rbac:
      install: true
      serviceAccountName: cd-jenkins
    CONFIG
    
  2. En Cloud Shell, utiliza la interfaz de línea de comandos para implementar el gráfico con su conjunto de configuración:

    ./helm install -n cd \
    stable/jenkins -f values.yaml --wait
    
  3. Verifica la instalación de Jenkins, y asegúrate de que el pod de Jenkins se encuentre en un estado Running:

    kubectl get pods
    

    Resultado esperado:

    NAME                            READY     STATUS    RESTARTS   AGE
    cd-jenkins-7c786475dd-qdxpr     1/1       Running   0          3h
    

Conectarse a Jenkins

  1. En Cloud Shell, obtén la contraseña de Jenkins y anótala para utilizarla más adelante en este instructivo:

    printf $(kubectl get secret cd-jenkins -o \
        jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
    
  2. Reenvía el puerto 8080 a la implementación de Jenkins en tu clúster de Kubernetes:

    export POD_NAME=$(kubectl get pods -l "component=cd-jenkins-master"\
        -o jsonpath="{.items[0].metadata.name}")
    kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &
    
  3. Para abrir la interfaz de usuario de Jenkins, haz clic en Vista previa en la Web en Cloud Shell y luego haz clic en Vista previa en el puerto 8080.

  4. Accede como administrador con la contraseña del paso 1.

Crear la cuenta de servicio de Jenkins

El complemento de Jenkins en Compute Engine utiliza la cuenta de servicio de Jenkins para aprovisionar agentes que realicen la compilación de la imagen anidada.

  1. Regresa a la ventana original de Cloud Shell.
  2. Crea una cuenta de servicio llamada jenkins y almacena su dirección de correo electrónico:

    gcloud iam service-accounts create jenkins --display-name jenkins
    export SA_EMAIL=$(gcloud iam service-accounts list \
        --filter="displayName:jenkins" --format='value(email)')
    
  3. Vincula las siguientes funciones a la cuenta de servicio:

    gcloud projects add-iam-policy-binding $PROJECT \
        --role roles/storage.admin --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.instanceAdmin.v1 \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.networkAdmin \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/compute.securityAdmin \
        --member serviceAccount:$SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/iam.serviceAccountActor \
        --member serviceAccount:$SA_EMAIL
    
  4. Crea la clave de la cuenta de servicio:

    gcloud iam service-accounts keys \
        create jenkins-sa.json --iam-account $SA_EMAIL
    
  5. Copia el resultado del siguiente comando a tu portapapeles:

    echo "$(pwd)/jenkins-sa.json"
    
  6. En Cloud Shell, haz clic en el botón Más more_vert.

  7. Haz clic en Descargar archivo; se abrirá un cuadro de diálogo en el que deberás ingresar la ruta del archivo.

  8. Pega el contenido copiado en el cuadro de texto.

  9. Haz clic en Descargar para guardar el archivo de forma local.

Compilar la imagen del agente de Jenkins

En esta sección, debes compilar una imagen para el agente de Jenkins, que incluye los siguientes elementos:

  • Virtualización anidada
  • Packer
  • QEMU-KVM
  • Java

Crear una imagen base con la virtualización anidada habilitada

  1. Crea un disco con una imagen estándar de centos-7:

    gcloud compute disks create disk1 \
        --image-project centos-cloud \
        --image-family centos-7 \
        --zone ${ZONE}
    
  2. Crea una imagen con la virtualización anidada activada:

    gcloud compute images create nested-vm-image \
        --source-disk disk1 \
        --source-disk-zone ${ZONE} \
        --licenses \
        "https://www.googleapis.com/compute/v1/\
    projects/vm-options/global/licenses/enable-vmx"
    

Crear la imagen del agente de Jenkins

  1. Crea una instancia y especifica la plataforma de CPU mínima con una Haswell de Intel (consulta restricciones de la virtualización anidada).

    gcloud compute instances create packer-build-host \
        --zone ${ZONE} \
        --machine-type=n1-standard-4 \
        --boot-disk-size=20GB \
        --boot-disk-type=pd-ssd \
        --image nested-vm-image \
        --min-cpu-platform='Intel Haswell' \
        --metadata startup-script='#! /bin/bash
    # Install agent requirements
    sudo su -
    yum update -y
    yum install git unzip wget qemu-kvm -y
    echo "export PATH=$PATH:/usr/libexec" > /etc/profile.d/libexec-path.sh
    source /etc/profile.d/libexec-path.sh
    curl -LO \
        https://releases.hashicorp.com/packer/1.3.0/packer_1.3.0_linux_amd64.zip
    unzip packer_1.3.0_linux_amd64.zip
    cp packer /usr/bin/packerio
    yum install java-1.8.0-openjdk-devel -y'
    

    La instancia se utiliza para crear una imagen, y contiene el entorno de virtualización anidado y las herramientas con las que se crean las compilaciones. La imagen descarga la configuración desde el repositorio de código fuente a través de Git, brinda asistencia de virtualización a través de QEMU-KVM, interactúa con el agente de Jenkins por medio de Java y utiliza Packer para automatizar la creación de imágenes de máquina.

  2. Crea la imagen jenkins-packer-agent y utiliza como fuente a la instancia del host de compilación de Packer:

    gcloud compute images create jenkins-packer-agent-v1 \
        --source-disk packer-build-host \
        --source-disk-zone $ZONE \
        --family jenkins-packer-agent \
        --force
    

Crear una clave de servicio para el agente de Packer

  1. En Cloud Shell, crea la cuenta de servicio del agente de Packer que se asignará para las instancias agentes:

    gcloud iam service-accounts create packer-agent-sa \
        --display-name packer-agent-sa
    export PACKER_SA_EMAIL=$(gcloud iam service-accounts list \
       --filter="displayName:packer-agent-sa" --format='value(email)')
    
  2. Vincula las funciones a las cuentas de servicio:

    gcloud projects add-iam-policy-binding $PROJECT \
        --role roles/storage.admin --member serviceAccount:$PACKER_SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT \
        --role roles/compute.instanceAdmin.v1 \
        --member serviceAccount:$PACKER_SA_EMAIL
    gcloud projects add-iam-policy-binding $PROJECT --role roles/iam.serviceAccountActor \
        --member serviceAccount:$PACKER_SA_EMAIL
    

Configurar Jenkins

En esta sección, agregarás credenciales a Jenkins, configurarás un backend de Compute Engine, configurarás Packer para que compile una imagen de Compute Engine, ejecutarás la compilación y crearás y te conectarás a una instancia basada en la imagen.

Configurar las credenciales

  1. Desde la vista previa en la web abierta anteriormente, accede a Jenkins con la cuenta y contraseña de administrador.
  2. En Jenkins, haz clic en Credenciales en el menú de la izquierda.
  3. En el menú de la izquierda, haz clic en Sistema.
  4. En el panel principal de la IU, haz clic en Credenciales globales (no restringido).
  5. En el menú de la izquierda, haz clic en Agregar credenciales.
  6. Configura el Tipo como Cuenta de servicio de Google desde una clave privada.
  7. En el campo Nombre del proyecto, ingresa tu ID del proyecto.
  8. Haz clic en Elegir archivo.
  9. Selecciona el archivo jenkins-sa.json que descargaste anteriormente desde Cloud Shell.
  10. Haz clic en Aceptar.

Agregar un backend de Compute Engine

  1. En Jenkins, en el menú de la izquierda, haz clic en Administrar Jenkins.
  2. En el panel principal de la IU, haz clic en Configurar sistema.
  3. Desplázate hacia abajo hasta la sección de Cloud.
  4. Haz clic en Agregar nube nueva y selecciona Google Compute Engine.
  5. En Google Compute Engine, ingresa o selecciona los siguientes valores:
    • Nombre: jenkins-packer-agent
    • ID del proyecto: el nombre de tu proyecto de GCP
    • Límite de la instancia: 1
    • Credenciales de la cuenta de servicio: las credenciales creadas en la sección anterior
    • Prefijo del nombre: packerqemuagent
    • Descripción: packer agent qemu configuration
    • Etiquetas: packer-qemu
    • Ejecutar como usuario: jenkins
    • Región: us-central-1 (debe coincidir con la región predeterminada de procesamiento configurada más arriba).
    • Zona: us-central1-b (debe coincidir con la región predeterminada de procesamiento configurada más arriba).
    • Tipo de máquina: n1-standard-4
    • Plataforma de CPU mínima: Intel Haswell
    • Red: default
    • Subred: default
    • ¿IP externa?: seleccionada
    • Proyecto de la imagen: tu proyecto
    • Nombre de la imagen: jenkins-packer-agent-v1
    • Tamaño: 30
    • Borrar una vez finalizado: seleccionado
    • Correo electrónico de la cuenta de servicio: la cuenta de servicio del agente de Packer
  6. Haz clic en Guardar.

Configurar un trabajo de Packer en Jenkins

Crearás un trabajo de Jenkins que convierta una imagen ISO en una imagen de Compute Engine basada en la configuración de muestra:

  1. En el lado izquierdo de la IU de Jenkins, haz clic en Elemento nuevo.
  2. En el campo Ingresar nombre del elemento, ingresa ISO Image Factory.
  3. Selecciona Proyecto libre.
  4. Haz clic en Aceptar.
  5. Selecciona Restringir en qué lugar se puede ejecutar este proyecto.
  6. En el campo Expresión de la etiqueta, ingresa packer-qemu.
  7. En Administración del código fuente, selecciona Git.
  8. En el campo URL del repositorio, ingresa el repositorio de muestra:

    https://github.com/GoogleCloudPlatform/compute-custom-boot-images
    

Agregar los pasos para la compilación de la imagen

Compilar una imagen consta de dos pasos. Primero, el trabajo de Jenkins limpia cualquier compilación existente de Packer por si el agente de compilación se vuelve a utilizar. Luego, el trabajo de Jenkins utiliza Packer para compilar una imagen base que utilice la secuencia de comandos de Packer incluida en el repositorio de muestra. La secuencia de comandos de Packer incluye secuencias de comandos de aprovisionamiento que instalan los paquetes necesarios para utilizar con Compute Engine, incluido el entorno invitado de Linux.

  1. En la sección Compilación, haz clic en Agregar paso de compilación.
  2. Haz clic en Ejecutar Shell.
  3. En el campo Comando, ingresa el siguiente comando, que borra cualquier imagen generada en el agente de Packer:

    if [[ -d output ]]; then
      rm -rf output
    fi
    
  4. Haz clic nuevamente en Agregar paso de compilación.

  5. Haz clic en Ejecutar Shell.

  6. En el campo Comando, ingresa el siguiente comando, que compila la imagen parcialmente aprovisionada y la importa a Compute Engine. Reemplaza [PROJECT] con el nombre de tu proyecto y [ZONE] con la zona que quieres utilizar para compilar tu imagen.

    packerio build \
    -var "project=[PROJECT]" \
    -var "image_family=acme-centos" \
    -var "gcs_bucket=gs://[PROJECT]-custom-images" \
    -var "build_number=$BUILD_NUMBER" \
    -var "zone=[ZONE]" \
    *-from-iso.json
    

Ejecutar la compilación

  1. En la esquina superior izquierda, haz clic en Jenkins.
  2. Junto con la compilación que acabas de crear, haz clic en el botón Compilar ahora.

Implementar una instancia a través de la imagen compilada

Cuando la compilación finalice, debes crear una instancia para la imagen y conectarte a ella con SSH.

  1. En Cloud Shell, crea la instancia (esto puede tardar uno o dos minutos):

    gcloud compute instances create test-image-build \
      --zone=us-central-1b \
      --image-family=acme-centos
    
  2. Prueba si puedes acceder a la imagen con SSH:

    gcloud compute ssh test-image-build
    

Limpiar

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

Borrar el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

  1. En GCP Console, dirígete a la página Administrar recursos.

    Ir a la página Administración de recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Limpiar los recursos individuales

  1. Borra la instancia de prueba:

    gcloud compute instances delete test-image-build
    
  2. Borra el clúster de GKE:

    gcloud container clusters delete builder
    
  3. Borra la imagen:

    gcloud compute images delete \
        $(gcloud compute images list --filter="family=acme-centos" --format="value(name)")
    
  4. Borra el depósito de almacenamiento:

    gsutil rm -rf gs://$PROJECT-custom-images
    

Pasos siguientes