Jenkins-Pipeline mit mehreren Verzweigungen in GKE

1. Übersicht

Jenkins ist eine der beliebtesten Lösungen für Continuous Integration. Sie wird verwendet, um die wesentlichen nicht menschlichen Teile des Softwareentwicklungsprozesses zu automatisieren. Durch die Bereitstellung von Jenkins in Kubernetes in Google Cloud und die Nutzung des GKE-Plug-ins können wir Build-Executors bei Bedarf schnell und automatisch skalieren. In Kombination mit Cloud Storage können wir eine Anwendung mit minimalem Aufwand erstellen und testen.

Aufgaben

  • Jenkins in einem Kubernetes-Cluster bereitstellen
  • Das Jenkins-GKE-Plug-in bereitstellen und konfigurieren, damit Jenkins Pods als Executor-Knoten erstellen und löschen kann
  • SpringBoot-Beispielanwendung erstellen und testen
  • Container erstellen und in Google Container Registry veröffentlichen
  • Beispielanwendung in einer GKE-Staging- und ‑Produktionsumgebung bereitstellen

Voraussetzungen

  • Ein Google Cloud-Projekt mit eingerichteter Abrechnung. Wenn Sie noch kein Konto haben, müssen Sie eins erstellen.

2. Einrichtung

Dieses Codelab kann vollständig auf der Google Cloud Platform ausgeführt werden, ohne dass eine lokale Installation oder Konfiguration erforderlich ist.

Cloud Shell

In diesem Codelab stellen wir verschiedene Cloud-Ressourcen und -Dienste über die Befehlszeile über Cloud Shell bereit und verwalten sie.

APIs aktivieren

Die folgenden APIs müssen für unser Projekt aktiviert sein:

  • Compute Engine API: Erstellt und führt virtuelle Maschinen aus
  • Kubernetes Engine API: Erstellt und verwaltet containerbasierte Anwendungen
  • Cloud Build API: Die Plattform für Continuous Integration und Continuous Delivery von Google Cloud
  • Service Management API: Ermöglicht Dienstanbietern, Dienste auf der Google Cloud Platform zu veröffentlichen.
  • Cloud Resource Manager API: Erstellt, liest und aktualisiert Metadaten von Google Cloud-Ressourcencontainern.

Aktivieren Sie die erforderlichen APIs mit dem folgenden gcloud-Befehl:

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

GCS-Bucket erstellen

Wir benötigen einen GCS-Bucket, um unsere Testarbeiten hochzuladen. Wir erstellen einen Bucket mit unserer Projekt-ID im Namen, um die Eindeutigkeit zu gewährleisten:

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

3. Kubernetes-Cluster erstellen

Cluster erstellen

Als Nächstes erstellen wir einen GKE-Cluster, auf dem unser Jenkins-System gehostet wird, einschließlich der Pods, die als Worker-Knoten bereitgestellt werden. Der zusätzliche Bereich, der durch das Flag --scopes angegeben wird, ermöglicht Jenkins den Zugriff auf Cloud Source Repositories und Container Registry. Führen Sie in der Cloud Console Folgendes aus:

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

Wir stellen auch zwei Cluster bereit, um die Staging- und Produktions-Builds unserer Beispielanwendung zu hosten:

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 Bestätigen

Nachdem die Cluster erstellt wurden, können wir mit gcloud container clusters list prüfen, ob sie ausgeführt werden.

Die Ausgabe sollte in der Spalte STATUS Folgendes enthalten: RUNNING.

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. Jenkins mit Helm bereitstellen

Helm installieren

Wir verwenden Helm, einen Paketmanager für Kubernetes-Anwendungen, um Jenkins in unserem Cluster zu installieren. Laden Sie zuerst das Projekt herunter, das die Kubernetes-Manifeste enthält, mit denen wir Jenkins bereitstellen werden:

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

Wechseln Sie in das Projektverzeichnis:

cd ~/continuous-deployment-on-kubernetes/

Erstellen Sie eine Clusterrollenbindung, um sich selbst die Berechtigungen der Rolle „cluster-admin“ zu erteilen:

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

Stellen Sie eine Verbindung zu Ihrem Jenkins-Cluster her, indem Sie die Anmeldedaten abrufen:

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

Laden Sie die Helm-Binärdatei in Ihre Cloud Console herunter:

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

Entpacken Sie die Datei und kopieren Sie die enthaltene Helm-Datei in Ihr aktuelles Arbeitsverzeichnis:

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

Tiller ist die Serverseite von Helm, die im Kubernetes-Cluster ausgeführt wird. Erstellen wir ein Dienstkonto mit dem Namen tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

Binden Sie sie an die Clusterrolle cluster-admin, damit Änderungen vorgenommen werden können:

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

Jetzt können wir Helm initialisieren und das Repository aktualisieren:

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

28b45298e1e82748.png Bestätigen

Prüfen Sie, ob Helm mit ./helm version funktioniert. Dadurch sollten die Versionsnummern des Clients und des Servers zurückgegeben werden:

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

Jenkins installieren

Helm ist jetzt in unserem Cluster installiert. Wir können also mit der Jenkins-Installation fortfahren:

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

28b45298e1e82748.png Bestätigen

Sehen wir uns die Pods an:

kubectl get pods

In der Ausgabe sollte unser Jenkins-Pod mit dem Status „RUNNING“ angezeigt werden:

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

Prüfen Sie, ob der Jenkins-Dienst richtig erstellt wurde:

kubectl get svc

Die Ausgabe sollte in etwa so aussehen:

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

Die Jenkins-Installation verwendet das Kubernetes-Plugin zum Erstellen von Builder-Agents. Sie werden bei Bedarf automatisch vom Jenkins-Master gestartet. Wenn deren Aufgabe abgeschlossen ist, werden sie automatisch beendet und ihre Ressourcen wieder dem Ressourcenpool des Clusters hinzugefügt.

Verbindung zu Jenkins herstellen

Jenkins wird in unserem Cluster ausgeführt. Um auf die Benutzeroberfläche zuzugreifen, richten wir die Portweiterleitung von Cloud Shell ein:

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 &

Während der Installation wurde ein Administratorpasswort generiert. So rufen Sie sie ab:

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

Klicken Sie oben in Cloud Shell auf das Symbol für die Webvorschau 7ddf5a65fd556dd6.png und wählen Sie „Vorschau auf Port 8080“ aus.

1d614c831a621cff.png

Es sollte ein Anmeldebildschirm für Jenkins angezeigt werden, auf dem wir admin als Nutzernamen und das im vorherigen Schritt zurückgegebene Passwort eingeben können:

9cba23e856cbc84f.png

Wenn wir auf Sign in (Anmelden) klicken, sollten wir zur Hauptseite von Jenkins weitergeleitet werden.

9261f3e914829137.png

5. GKE-Plug-in installieren und konfigurieren

Mit dem Google Kubernetes Engine-Plug-in können wir in Jenkins erstellte Bereitstellungen in unseren Kubernetes-Clustern veröffentlichen, die in GKE ausgeführt werden. Für Ihr Projekt muss eine Konfiguration mit IAM-Berechtigungen vorgenommen werden. Wir stellen diese Konfiguration mit Terraform bereit.

Laden Sie zuerst das GKE-Plug-in-Projekt herunter:

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

Automatisierte Konfiguration von IAM-Berechtigungen

Ändern Sie das aktuelle Arbeitsverzeichnis in das RBAC-Verzeichnis des GKE-Projekts, das wir zuvor geklont haben:

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

gcp-sa-setup.tf ist eine Terraform-Konfigurationsdatei, mit der eine benutzerdefinierte GCP IAM-Rolle mit eingeschränkten Berechtigungen sowie ein GCP-Dienstkonto erstellt werden, dem diese Rolle zugewiesen wird. Die Datei erfordert Werte für die Variablen „Projekt“, „Region“ und „Name des Dienstkontos“. Wir stellen diese Werte bereit, indem wir zuerst die folgenden Umgebungsvariablen deklarieren:

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

Initialisieren Sie Terraform, generieren Sie einen Plan und wenden Sie ihn an:

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

Das Dienstkonto benötigt Speicheradministratorberechtigungen, um Daten in unserem Cloud Storage-Bucket zu speichern:

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

Außerdem sind Containerberechtigungen für die Bereitstellungsphasen der Pipeline erforderlich:

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

Jetzt können wir Helm verwenden, um Clusterberechtigungen für das GKE-Plug-in mit dem GKE-Roboter-Deployer einzurichten. Wechseln Sie in das Arbeitsverzeichnis des GKE-Projekts für Helm:

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

Installieren Sie die Software mit dem bereitgestellten Helm-Diagramm:

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

6. Jenkins konfigurieren

Dienstkontoschlüssel

Damit das Dienstkonto ordnungsgemäß funktioniert, müssen wir eine private Schlüsseldatei generieren und sie als Kubernetes-Secret hinzufügen. Generieren Sie die Datei zuerst mit dem folgenden gcloud-Befehl:

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

Wir erstellen mit dieser Datei einen geheimen Schlüssel im Kubernetes-Secret-Speicher:

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

Laden Sie die JSON-Datei auf Ihre lokale Festplatte herunter, indem Sie im Dreipunkt-Menü von Cloud Shell auf „Datei herunterladen“ klicken:

c40378e72013b843.png

Geben Sie den Dateipfad /tmp/kaniko-secret.json ein und klicken Sie auf „Herunterladen“.

Klicken Sie auf der Jenkins-Seite im linken Bereich auf Credentials (Anmeldedaten) und dann auf System.

6c140f7e6bb82f8.png3b874912cdc8019b.png

Klicken Sie auf der Seite im Abschnitt System links auf „Globale Anmeldedaten“ und dann auf „Anmeldedaten hinzufügen“:

4350c0e68561119b.png3d3526551cdae8b.png

Wählen Sie im Drop-down-Menü „Art“ die Option Google-Dienstkonto von privatem Schlüssel aus. Geben Sie „kaniko-role“ als Namen ein, laden Sie dann den JSON-Schlüssel hoch, der in den vorherigen Schritten erstellt wurde, und klicken Sie auf „OK“.

b0502213408e730e.png

Umgebungsvariablen

Es gibt einige Umgebungsvariablen, die wir in Jenkins definieren müssen, bevor wir die Pipeline mit mehreren Branches erstellen. Diese sind:

  • JENK_INT_IT_ZONE: Die Zone des Kubernetes-Clusters. In unserem Fall us-east1-d
  • JENK_INT_IT_PROJECT_ID: bezieht sich auf die GCP-Projekt-ID, in der diese Jenkins-Instanz gehostet wird.
  • JENK_INT_IT_STAGING – der Name unseres Staging-Clusters. Zu Demonstrationszwecken ist er staging.
  • JENK_INT_IT_PROD – der Name unseres Produktionsclusters. Zu Demonstrationszwecken ist das prod.
  • JENK_INT_IT_BUCKET: Der Google Cloud Storage-Bucket, der im vorherigen Schritt erstellt wurde
  • JENK_INT_IT_CRED_ID – bezieht sich auf die Anmeldedaten, die mit dem JSON-Code im vorherigen Schritt erstellt wurden. Der Wert sollte mit dem von uns angegebenen Namen kaniko-role übereinstimmen.

So fügen Sie sie hinzu: Manage Jenkins

d54f279190a07878.png

System konfigurieren:

ce79d218b2799640.png

Es gibt einen Bereich mit dem Namen Globale Eigenschaften. Wenn wir das Kästchen für Umgebungsvariablen anklicken, wird die Schaltfläche Hinzufügen angezeigt, auf die wir klicken, um die oben genannten Variablen als Schlüssel/Wert-Paare hinzuzufügen:

81aa222a2b17b2cc.png

Klicken Sie unten auf der Seite auf die Schaltfläche Speichern, um die Änderungen zu übernehmen.

7. Pipeline einrichten

Klicken Sie in Jenkins auf „New Item“ (Neues Element):

8d1270ce4d7b6a8a.png

Geben Sie „jenkins-integration-sample“ als Namen ein, wählen Sie „Multibranch Pipeline“ als Projekttyp aus und klicken Sie auf „OK“:

eb071ecfbb4d775b.png

Wir werden zur Seite für die Pipelinekonfiguration weitergeleitet. Geben Sie unter Branch Sources (Quell-Branches) https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git als Project Repository (Projekt-Repository) ein. Geben Sie unter Build-Konfiguration „gke/Jenkinsfile“ als Script Path (Skriptpfad) ein.

5135bd6b0374508c.png

Klicken Sie auf Speichern, um diese Einstellungen zu übernehmen. Nach dem Speichern startet Jenkins einen Scan des Repositorys und einen anschließenden Build für jeden Branch. Auf der Seite „Kubernetes-Arbeitslasten“ sehen Sie, wie Pods erstellt, ausgeführt und zerstört werden, während die Builds fortschreiten.

Wenn die Builds abgeschlossen sind, finden Sie auf der Seite „Kubernetes-Arbeitslasten“ zwei Elemente mit dem Namen „jenkins-integration-samples-gke“, die jeweils dem Produktions- oder Testcluster entsprechen. Der Status lautet „OK“:

bdec6b1753d1ba07.png

Mit dem folgenden gcloud-Befehl sehen wir, dass wir ein Container-Image in die Google Container Registry hochgeladen haben, das unserer Pipeline entspricht:

gcloud container images list

Wenn Sie die Arbeitslast in Ihrem Browser aufrufen möchten, rufen Sie die Anmeldedaten für den Produktionscluster ab:

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

Führen Sie den folgenden Befehl aus, um eine Portweiterleitung von Port 8081 Ihrer Shell zu Port 8080 Ihrer Arbeitslast einzurichten:

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

Klicken Sie oben in Cloud Shell auf das Symbol für die Webvorschau und wählen Sie „Vorschau auf Port 8081“ aus.

1b19b5b56f1bae7.pnge80e995e71763bb2.png

8. Bereinigen

Wir haben uns angesehen, wie Sie eine Jenkins-Instanz und eine Beispielpipeline mit mehreren Branches in Kubernetes bereitstellen. Jetzt ist es an der Zeit, alle Ressourcen zu entfernen, die wir in unserem Projekt erstellt haben.

Projekt löschen

Wenn Sie möchten, können Sie das gesamte Projekt löschen. Rufen Sie in der GCP Console die Seite Cloud Resource Manager auf:

Wählen Sie in der Projektliste das Projekt aus, in dem wir gearbeitet haben, und klicken Sie auf Löschen. Sie werden aufgefordert, die Projekt-ID einzugeben. Geben Sie sie ein und klicken Sie auf Herunterfahren.

Alternativ können Sie das gesamte Projekt direkt über Cloud Shell mit gcloud löschen:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Wenn Sie die verschiedenen abrechenbaren Komponenten lieber einzeln löschen möchten, fahren Sie mit dem nächsten Abschnitt fort.

Kubernetes-Cluster

Löschen Sie den gesamten Kubernetes-Cluster mit gcloud:

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

Storage-Buckets

Entfernen Sie alle hochgeladenen Dateien und löschen Sie unseren Bucket mit gsutil:

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

Google Container Registry-Images

Wir löschen die Google Container Registry-Images anhand der Image-Digests. Rufen Sie zuerst die Digests mit dem folgenden Befehl ab:

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

Führen Sie dann für jeden zurückgegebenen Kurzbeitrag die folgenden Schritte aus:

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

9. Glückwunsch!

Hurra! Du hast es geschafft. Sie haben gelernt, wie Sie Jenkins in GKE bereitstellen und Jobs an Kubernetes-Cluster senden.

Behandelte Themen

  • Wir haben einen Kubernetes-Cluster bereitgestellt und Jenkins mit Helm installiert.
  • Wir haben das GKE-Plug-in installiert und konfiguriert, damit Jenkins Build-Artefakte in Kubernetes-Clustern bereitstellen kann.
  • Wir haben Jenkins so konfiguriert, dass eine Multi-Branch-Pipeline eingerichtet wird, die Arbeit an GKE-Cluster weiterleitet.