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 non umane del processo di sviluppo del software. Eseguendo il deployment di Jenkins su Kubernetes su Google Cloud e utilizzando il plug-in GKE, possiamo scalare rapidamente e automaticamente gli esecutori di build in base alle esigenze. In combinazione con Cloud Storage, possiamo 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 ed eliminare i pod come nodi esecutori
  • Crea e testa un'applicazione SpringBoot di esempio
  • Crea e pubblica un container in Google Container Registry
  • Esegui il deployment dell'applicazione di esempio in un ambiente GKE di gestione temporanea 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 su Google Cloud Platform senza alcuna installazione o configurazione locale.

Cloud Shell

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

Abilita API

Ecco le API che dovremo abilitare 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 continua e distribuzione continua di Google Cloud
  • API Service Management: consente ai produttori di servizi di pubblicare servizi su Google Cloud
  • API 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

Avremo bisogno di un bucket GCS per caricare il nostro lavoro di test. Creiamo un bucket utilizzando l'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 questo comando:

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 gestione temporanea e 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 vengono eseguiti con gcloud container clusters list

L'output dovrebbe contenere 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

Installare Helm

Utilizzeremo Helm, un gestore di pacchetti di applicazioni per Kubernetes, per installare Jenkins sul 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 attuale con la directory del progetto:

cd ~/continuous-deployment-on-kubernetes/

Crea un cluster role binding per concederti le autorizzazioni del ruolo cluster-admin:

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

Connettiti al tuo 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 attuale:

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 service account denominato tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

e associa il ruolo 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 per l'uso 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 sul nostro cluster, possiamo procedere con 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 agenti di build. Verranno avviati automaticamente dal master Jenkins in base alle esigenze. Al termine del loro lavoro, vengono automaticamente terminati 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 alla UI, configuriamo 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 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.png e seleziona "Anteprima sulla porta 8080".

1d614c831a621cff.png

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

9cba23e856cbc84f.png

Quando facciamo clic su Accedi, dovremmo essere indirizzati alla 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 sul progetto. Eseguiremo il deployment di questa 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 attuale con la directory 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 creerà un ruolo IAM GCP personalizzato con autorizzazioni limitate insieme a un service account GCP a cui concedere il ruolo. Il file richiede valori per le variabili del progetto, della regione e del nome del service account. 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

Il service account avrà bisogno delle autorizzazioni di amministratore 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'

Avrà anche bisogno delle 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 robot di deployment GKE. Cambia la directory di lavoro in quella di Helm del progetto GKE:

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

e installa 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 service account

Affinché il service account funzioni correttamente, dobbiamo generare un file della chiave privata e aggiungerlo come secret di 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 dei 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.

Nella pagina Jenkins, nel riquadro a sinistra, fai clic su Credenziali,quindi su Sistema.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

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

4350c0e68561119b.png

3d3526551cdae8b.png

Nel menu a discesa Tipo, seleziona Service account Google da 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 multibranch, 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: fa riferimento all'ID progetto GCP che ospita questa istanza di Jenkins
  • JENK_INT_IT_STAGING: il nome del nostro cluster di "staging", a scopo dimostrativo è staging
  • JENK_INT_IT_PROD: il nome del nostro cluster "prod". A scopo dimostrativo, è prod
  • JENK_INT_IT_BUCKET: il bucket 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 Manage Jenkins (Gestisci Jenkins):

d54f279190a07878.png

Poi Configura sistema:

ce79d218b2799640.png

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

81aa222a2b17b2cc.png

Fai clic sul pulsante Salva in fondo alla pagina per applicare le modifiche.

7. Configurare una pipeline

In Jenkins, fai clic su "New Item" (Nuovo elemento):

8d1270ce4d7b6a8a.png

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

eb071ecfbb4d775b.png

Verrà visualizzata la pagina di configurazione della pipeline. In Branch Sources (Origini dei rami), inserisci https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git come Project Repository (Repository progetto). In Configurazione build, inserisci "gke/Jenkinsfile" come percorso dello script.

5135bd6b0374508c.png

Fai clic su Salva per applicare queste impostazioni. Al salvataggio, Jenkins avvierà una scansione del repository e una build successiva per ogni ramo. Man mano che avanza, vedrai i pod creati, eseguiti ed eliminati man mano che le build avanzano nella pagina Workload Kubernetes.

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

bdec6b1753d1ba07.png

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

gcloud container images list

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

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

Esegui questo comando per configurare un port forwarding dalla porta 8081 della shell alla porta 8080 del tuo workload:

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 esaminato come eseguire il deployment di Jenkins e di una pipeline multibranch di esempio su Kubernetes. Ora è il momento di liberare spazio nel nostro progetto da tutte le risorse che abbiamo creato.

Eliminare il progetto

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

Nell'elenco dei progetti, seleziona il progetto su cui abbiamo 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 nostro 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 riepilogo 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 distribuire i 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 artefatti di build nei cluster Kubernetes
  • Abbiamo configurato Jenkins per impostare una pipeline multibranch che distribuisce il lavoro ai cluster GKE