Pipeline multi-ramo Jenkins su GKE

1. Panoramica

Jenkins è una delle soluzioni di integrazione continua più diffuse disponibili. Viene utilizzato per automatizzare le parti essenziali del processo di sviluppo software non umane. Eseguendo il deployment di Jenkins in Kubernetes su Google Cloud e utilizzando il plug-in GKE, siamo in grado di scalare rapidamente e automaticamente gli esecutori di build in base alle esigenze. In combinazione con Cloud Storage, siamo in grado di creare e testare un'applicazione con il minimo sforzo.

Attività previste

  • Esegui il deployment di Jenkins in un cluster Kubernetes
  • Esegui il deployment e configura il plug-in Jenkins GKE per consentire a Jenkins di creare e distruggere i pod come nodi di esecuzione
  • Creare e testare un'applicazione SpringBoot di esempio
  • Creare e pubblicare un container in Google Container Registry
  • Esegui il deployment dell'applicazione di esempio in un ambiente GKE di staging e produzione

Che cosa ti serve

  • Un progetto Google Cloud con la fatturazione configurata. Se non ne hai uno, dovrai crearne uno.

2. Preparazione

Questo codelab può essere eseguito completamente sulla piattaforma Google Cloud senza alcuna installazione o configurazione locale.

Cloud Shell

In questo codelab, eseguiamo il provisioning e la gestione di diverse risorse e servizi cloud utilizzando la riga di comando tramite Cloud Shell.

Abilita le API

Ecco le API che dovremo attivare nel nostro progetto:

  • API Compute Engine: crea ed esegue macchine virtuali
  • API Kubernetes Engine: crea e gestisce applicazioni basate su container
  • API Cloud Build: la piattaforma di integrazione e distribuzione continua di Google Cloud
  • API Service Management: consente ai produttori di servizi di pubblicare servizi sulla piattaforma Google Cloud
  • API Cloud Resource Manager: crea, legge e aggiorna i metadati per i contenitori di risorse Google Cloud

Abilita le API richieste con il seguente comando gcloud:

gcloud services enable compute.googleapis.com \
container.googleapis.com \
cloudbuild.googleapis.com \
servicemanagement.googleapis.com \
cloudresourcemanager.googleapis.com \
--project ${GOOGLE_CLOUD_PROJECT}

Crea un bucket GCS

Ci servirà un bucket GCS per caricare il nostro lavoro di test. Creiamo un bucket utilizzando il nostro ID progetto nel nome per garantire l'unicità:

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket/ 

3. Creazione di cluster Kubernetes

Crea il cluster

Successivamente, creeremo un cluster GKE che ospiterà il nostro sistema Jenkins, inclusi i pod che verranno inviati come nodi worker. L'ambito aggiuntivo indicato dal flag --scopes consentirà a Jenkins di accedere a Cloud Source Repositories e Container Registry. In Cloud Console, esegui quanto segue:

gcloud container clusters create jenkins-cd \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--scopes "https://www.googleapis.com/auth/source.read_write,cloud-platform" \
--cluster-version latest

Eseguiamo anche il deployment di due cluster per ospitare le build di staging e di produzione della nostra applicazione di esempio:

gcloud container clusters create staging \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--cluster-version latest
gcloud container clusters create prod \
--machine-type n1-standard-2 --num-nodes 2 \
--zone us-east1-d \
--cluster-version latest

28b45298e1e82748.png Verifica

Una volta creati i cluster, possiamo confermare che sono in esecuzione con gcloud container clusters list

L'output dovrebbe avere RUNNING nella colonna STATUS:

NAME        LOCATION    MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jenkins-cd  us-east1-d  1.15.9-gke.9    34.74.77.124  n1-standard-2  1.15.9-gke.9  2          RUNNING
prod        us-east1-d  1.15.9-gke.9    35.229.98.12  n1-standard-2  1.15.9-gke.9  2          RUNNING
staging     us-east1-d  1.15.9-gke.9    34.73.92.228  n1-standard-2  1.15.9-gke.9  2          RUNNING

4. Esegui il deployment di Jenkins con Helm

Installa Helm

Utilizzeremo Helm, un gestore di pacchetti per applicazioni per Kubernetes, per installare Jenkins nel nostro cluster. Per iniziare, scarica il progetto che include i manifest Kubernetes che utilizzeremo per eseguire il deployment di Jenkins:

git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes

Cambia la directory di lavoro corrente in quella del progetto:

cd ~/continuous-deployment-on-kubernetes/

Crea un'associazione del ruolo del cluster per concederti le autorizzazioni del ruolo di amministratore del cluster:

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)

Connettiti al cluster Jenkins recuperando le relative credenziali:

gcloud container clusters get-credentials jenkins-cd --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

E scarica il file binario Helm nella console Cloud:

wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz

Decomprimi il file e copia il file Helm incluso nella directory di lavoro corrente:

tar zxfv helm-v2.14.1-linux-amd64.tar.gz && \
cp linux-amd64/helm .

Tiller è il lato server di Helm che viene eseguito sul cluster Kubernetes. Creiamo un account di servizio denominato tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

E associalo al ruolo del cluster cluster-admin in modo che possa apportare modifiche:

kubectl create clusterrolebinding tiller-admin-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller

Ora possiamo inizializzare Helm e aggiornare il repository:

./helm init --service-account=tiller && \
./helm repo update

28b45298e1e82748.png Verifica

Verifica che Helm sia pronto con ./helm version: dovrebbero essere restituiti i numeri di versione del client e del server:

Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}

Installa Jenkins

Ora che Helm è installato nel nostro cluster, siamo pronti per l'installazione di Jenkins:

./helm install stable/jenkins -n cd \
-f jenkins/values.yaml \
--version 1.2.2 --wait

28b45298e1e82748.png Verifica

Controlliamo i pod:

kubectl get pods

L'output dovrebbe mostrare il pod Jenkins con lo stato RUNNING:

NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-vbhg4   1/1       Running   0          1m

Verifica che il servizio Jenkins sia stato creato correttamente:

kubectl get svc

L'output dovrebbe essere simile al seguente:

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         ClusterIP   10.35.241.170   <none>        8080/TCP    2m27s
cd-jenkins-agent   ClusterIP   10.35.250.57    <none>        50000/TCP   2m27s
kubernetes         ClusterIP   10.35.240.1     <none>        443/TCP     75m

L'installazione di Jenkins utilizzerà il plug-in Kubernetes per creare gli agenti di compilazione. Verranno avviati automaticamente dal master Jenkins in base alle esigenze. Al termine del loro lavoro, vengono terminati automaticamente e le loro risorse vengono aggiunte di nuovo al pool di risorse del cluster.

Connettiti a Jenkins

Jenkins è in esecuzione sul nostro cluster, ma per accedere all'interfaccia utente, configura il port forwarding da Cloud Shell:

export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

Durante l'installazione è stata generata una password di amministratore. Recuperiamolo:

printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

Nella parte superiore di Cloud Shell, fai clic sull'icona Anteprima web 7ddf5a65fd556dd6.pnge seleziona "Anteprima sulla porta 8080".

1d614c831a621cff.png

Dovremmo vedere una schermata di accesso a Jenkins in cui possiamo inserire admin per il nome utente e la password restituita nel passaggio precedente:

9cba23e856cbc84f.png

Quando facciamo clic su Accedi, dovrebbe aprirsi la pagina principale di Jenkins.

9261f3e914829137.png

5. Installa e configura il plug-in GKE

Il plug-in Google Kubernetes Engine ci consente di pubblicare i deployment creati in Jenkins nei nostri cluster Kubernetes in esecuzione in GKE. È necessario eseguire alcune configurazioni con le autorizzazioni IAM nel progetto. Eseguiremo il deployment della configurazione utilizzando Terraform.

Innanzitutto, scarica il progetto del plug-in GKE:

git clone https://github.com/jenkinsci/google-kubernetes-engine-plugin.git ~/google-kubernetes-engine-plugin

Configurazione automatica delle autorizzazioni IAM

Cambia la directory di lavoro corrente in rbac del progetto GKE che abbiamo clonato in precedenza:

cd ~/google-kubernetes-engine-plugin/docs/rbac/

gcp-sa-setup.tf è un file di configurazione Terraform che crea un ruolo IAM di Google Cloud personalizzato con autorizzazioni limitate e un account di servizio Google Cloud a cui concedere il ruolo. Il file richiede valori per le variabili del nome del progetto, della regione e dell'account di servizio. Forniamo questi valori dichiarando prima le seguenti variabili di ambiente:

export TF_VAR_project=${GOOGLE_CLOUD_PROJECT}
export TF_VAR_region=us-east1-d
export TF_VAR_sa_name=kaniko-role

Inizializza Terraform, genera un piano e applicalo:

terraform init
terraform plan -out /tmp/tf.plan
terraform apply /tmp/tf.plan && rm /tmp/tf.plan

L'account di servizio avrà bisogno delle autorizzazioni di amministratore dello spazio di archiviazione per salvare nel nostro bucket Cloud Storage:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \
--role 'roles/storage.admin'

Inoltre, saranno necessarie le autorizzazioni del contenitore per le fasi di deployment della pipeline:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} --member \
serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com --role 'roles/container.developer'

Ora possiamo utilizzare Helm per configurare le autorizzazioni del cluster per il plug-in GKE utilizzando il deployer del robot gke. Cambia la directory di lavoro in quella di Helm del progetto GKE:

cd ~/google-kubernetes-engine-plugin/docs/helm/

Esegui l'installazione utilizzando il grafico Helm fornito:

export TARGET_NAMESPACE=kube-system && \
envsubst < gke-robot-deployer/values.yaml | helm install ./gke-robot-deployer --name gke-robot-deployer -f -

6. Configura Jenkins

Chiavi account di servizio

Affinché l'account di servizio funzioni correttamente, dobbiamo generare un file della chiave privata e aggiungerlo come secret Kubernetes. Innanzitutto, genera il file con il seguente comando gcloud:

gcloud iam service-accounts keys create /tmp/kaniko-secret.json --iam-account kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

Creeremo una chiave segreta nell'archivio secret di Kubernetes con questo file:

kubectl create secret generic jenkins-int-samples-kaniko-secret --from-file=/tmp/kaniko-secret.json 

Scarica il file JSON sul disco locale accedendo all'elemento Scarica file dal menu con tre puntini di Cloud Shell:

c40378e72013b843.png

Inserisci il percorso del file /tmp/kaniko-secret.json e fai clic su Scarica.

Torna alla pagina di Jenkins, nel riquadro a sinistra fai clic su Credenziali, quindi su Sistema.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

Nella sezione della pagina Sistema,fai clic su Credenziali globali e poi su Aggiungi credenziali a sinistra:

4350c0e68561119b.png

3d3526551cdae8b.png

Nel menu a discesa Tipo, seleziona Account di servizio Google dalla chiave privata. Inserisci "kaniko-role" come nome, quindi carica la chiave JSON creata nei passaggi precedenti e fai clic su OK.

b0502213408e730e.png

Variabili di ambiente

Prima di creare la pipeline con più rami, dobbiamo definire alcune variabili di ambiente per Jenkins. Sono:

  • JENK_INT_IT_ZONE: la zona del cluster Kubernetes. Nel nostro caso us-east1-d
  • JENK_INT_IT_PROJECT_ID: si riferisce all'ID progetto Google Cloud che ospita questa istanza di Jenkins
  • JENK_INT_IT_STAGING: il nome del nostro cluster di "preparazione", per scopi dimostrativi è staging
  • JENK_INT_IT_PROD: il nome del nostro cluster "prod". A scopo dimostrativo, è prod
  • JENK_INT_IT_BUCKET: il bucket Google Cloud Storage creato nel passaggio precedente
  • JENK_INT_IT_CRED_ID: si riferisce alle credenziali create utilizzando il file JSON nel passaggio precedente. Il valore deve corrispondere al nome che gli abbiamo assegnato, kaniko-role

Per aggiungerli, vai a Gestisci Jenkins:

d54f279190a07878.png

Quindi Configura sistema:

ce79d218b2799640.png

Verrà visualizzata una sezione denominata Proprietà globali e, se selezioniamo la casella Voci di ambiente, verrà visualizzato un pulsante Aggiungi su cui fare clic per aggiungere le variabili precedenti come coppie chiave-valore:

81aa222a2b17b2cc.png

Fai clic sul pulsante Salva nella parte inferiore della pagina per applicare le modifiche.

7. Configura una pipeline

In Jenkins, fai clic su "Nuovo elemento":

8d1270ce4d7b6a8a.png

Inserisci "jenkins-integration-sample" come nome, seleziona "Multibranch Pipeline" come tipo di progetto e fai clic su OK:

eb071ecfbb4d775b.png

Ti reindirizzeremo alla pagina di configurazione della pipeline. In Branch Sources (Origini ramo), inserisci https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git come Project Repository (Repository del progetto). In Configurazione build, inserisci "gke/Jenkinsfile" come Percorso script.

5135bd6b0374508c.png

Fai clic su Salva per applicare queste impostazioni. Al salvataggio, Jenkins avvierà una scansione del repository e una successiva compilazione per ogni ramo. Man mano che procede, vedrai i pod creati, eseguiti e distrutti man mano che le build avanzano nella pagina Carichi di lavoro Kubernetes.

Al termine delle build, nella pagina Carichi di lavoro Kubernetes troverai due elementi denominati jenkins-integration-samples-gke, ciascuno corrispondente al cluster di produzione o di test. Lo stato sarà OK:

bdec6b1753d1ba07.png

Utilizzando il seguente comando gcloud, vedremo di aver caricato un'immagine container in Google Container Registry corrispondente alla nostra pipeline:

gcloud container images list

Per visualizzare il workload nel browser, ottieni le credenziali per il cluster di produzione:

gcloud container clusters get-credentials prod --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Quindi esegui il seguente comando per configurare un port forwarding dalla porta 8081 della shell alla porta 8080 del tuo carico di lavoro:

export POD_NAME=$(kubectl get pods -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8081:8080 >> /dev/null &

Nella parte superiore di Cloud Shell, fai clic sull'icona Anteprima web e seleziona "Anteprima sulla porta 8081".

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. Esegui la pulizia

Abbiamo esplorato come eseguire il deployment di Jenkins e di una pipeline multibranch di esempio su Kubernetes. Ora è il momento di eliminare dal progetto le risorse che abbiamo creato.

Eliminare il progetto

Se preferisci, puoi eliminare l'intero progetto. Nella console di Google Cloud, vai alla pagina Cloud Resource Manager:

Nell'elenco dei progetti, seleziona il progetto su cui hai lavorato e fai clic su Elimina. Ti verrà chiesto di digitare l'ID progetto. Inseriscilo e fai clic su Chiudi.

In alternativa, puoi eliminare l'intero progetto direttamente da Cloud Shell con gcloud:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Se preferisci eliminare i diversi componenti fatturabili uno alla volta, vai alla sezione successiva.

Cluster Kubernetes

Elimina l'intero cluster Kubernetes con gcloud:

gcloud container clusters delete jenkins-cd --zone=us-east1-d

Bucket di archiviazione

Rimuovi tutti i file caricati ed elimina il bucket con gsutil:

gsutil rm -r gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket

Immagini di Google Container Registry

Elimineremo le immagini di Google Container Registry utilizzando i digest delle immagini. Innanzitutto, recupera i digest con il seguente comando:

gcloud container images list-tags gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke --format="value(digest)"

Poi, per ogni digest restituito:

gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>

9. Complimenti!

Evvai! Ce l'hai fatta! Hai imparato a eseguire il deployment di Jenkins su GKE e a inviare job ai cluster Kubernetes.

Argomenti trattati

  • Abbiamo eseguito il deployment di un cluster Kubernetes e utilizzato Helm per installare Jenkins
  • Abbiamo installato e configurato il plug-in GKE per consentire a Jenkins di eseguire il deployment degli elementi di build nei cluster Kubernetes
  • Abbiamo configurato Jenkins per impostare una pipeline multiramo che invia il lavoro ai cluster GKE