1. Übersicht
Jenkins ist eine der beliebtesten Lösungen für Continuous Integration. Sie wird verwendet, um die wesentlichen nicht manuellen Teile des Softwareentwicklungsprozesses zu automatisieren. Durch die Bereitstellung von Jenkins in Kubernetes in der Google Cloud und die Verwendung des GKE-Plug-ins können wir Build-Executors schnell und automatisch skalieren, wenn dies erforderlich ist. 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
- Eine SpringBoot-Beispielanwendung erstellen und testen
- Einen Container erstellen und in Google Container Registry veröffentlichen
- Die Beispielanwendung in einer GKE-Staging- und -Produktionsumgebung bereitstellen
Voraussetzungen
- Ein Google Cloud-Projekt mit eingerichtetem Abrechnungskonto. Wenn Sie noch kein Projekt haben, müssen Sie eines erstellen.
2. Einrichtung
Dieses Codelab kann vollständig in 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 in der 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 : Plattform für Continuous Integration und Continuous Delivery von Google Cloud
- Service Management API : Ermöglicht Dienstanbietern, Dienste in der Google Cloud Platform zu veröffentlichen
- Cloud Resource Manager API : Erstellt, liest und aktualisiert Metadaten für Google Cloud-Ressourcencontainer
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 Testarbeit hochzuladen. Erstellen wir 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, der unser Jenkins-System hostet, einschließlich der Pods, die als Worker-Knoten gesendet 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 unsere 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
Bestätigen
Nachdem die Cluster erstellt wurden, können wir mit gcloud container clusters list bestätigen, dass sie ausgeführt werden.
In der Spalte STATUS sollte RUNNING stehen:
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:
git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes
Ändern Sie das aktuelle Arbeitsverzeichnis in das Projektverzeichnis:
cd ~/continuous-deployment-on-kubernetes/
Erstellen Sie eine Clusterrollenbindung, um sich die Berechtigungen der Clusteradministratorrolle zu gewähren:
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 es 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
Bestätigen
Bestätigen Sie mit ./helm version, dass Helm bereit ist. 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
Nachdem Helm in unserem Cluster installiert ist, können wir Jenkins installieren:
./helm install stable/jenkins -n cd \ -f jenkins/values.yaml \ --version 1.2.2 --wait
Bestätigen
Prüfen wir die Pods:
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
Bestätigen Sie, dass der Jenkins-Dienst ordnungsgemäß 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-Plug-in zum Erstellen von Builder-Agents. Diese 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. Rufen wir es ab:
printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
Klicken Sie oben in der Cloud Shell auf das Symbol für die Webvorschau
und wählen Sie „Vorschau auf Port 8080“ aus.

Wir sollten einen Anmeldebildschirm für Jenkins sehen, auf dem wir admin als Nutzernamen und das im vorherigen Schritt zurückgegebene Passwort eingeben können:

Wenn wir auf Anmelden klicken, sollten wir zur Hauptseite von Jenkins weitergeleitet werden.

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. Es sind einige Konfigurationen mit IAM-Berechtigungen für Ihr Projekt erforderlich. 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 für Projekt, Region und Dienstkontoname. Wir geben diese Werte an, 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 Administratorberechtigungen für Cloud Storage, um 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 unserer 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 mit Helm Clusterberechtigungen für das GKE-Plug-in einrichten, indem wir den GKE-Robot-Deployer verwenden. Ändern Sie das Arbeitsverzeichnis in das Helm-Verzeichnis des GKE-Projekts:
cd ~/google-kubernetes-engine-plugin/docs/helm/
Installieren Sie das Plug-in 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 zuerst die Datei 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ü der Cloud Shell auf „Datei herunterladen“ klicken:

Geben Sie den Dateipfad /tmp/kaniko-secret.json ein und klicken Sie auf „Herunterladen“.
Klicken Sie auf der Jenkins-Seite im linken Bereich auf Anmeldedaten und dann auf System.


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


Wählen Sie in der Drop-down-Liste „Art“ die Option Google Service Account from private key aus. Geben Sie „kaniko-role“ als Namen ein, laden Sie dann Ihren JSON-Schlüssel hoch, der in den vorherigen Schritten erstellt wurde, und klicken Sie auf „OK“.

Umgebungsvariablen
Es gibt einige Umgebungsvariablen, die wir in Jenkins definieren müssen, bevor wir die mehrzweigige Pipeline erstellen. Diese sind:
- JENK_INT_IT_ZONE: Die Zone des Kubernetes-Clusters. In unserem Fall
us-east1-d - JENK_INT_IT_PROJECT_ID: Die GCP-Projekt-ID, die diese Instanz von Jenkins hostet
- 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 er
prod - JENK_INT_IT_BUCKET: Der im vorherigen Schritt erstellte Google Cloud Storage-Bucket
- JENK_INT_IT_CRED_ID: Die Anmeldedaten, die im vorherigen Schritt mit der JSON-Datei erstellt wurden. Der Wert sollte mit dem Namen übereinstimmen, den wir ihm gegeben haben:
kaniko-role
Um diese hinzuzufügen, gehen Sie zu Manage Jenkins (Jenkins verwalten):

Dann Configure System (System konfigurieren):

Es gibt einen Abschnitt mit dem Namen Global properties (Globale Eigenschaften). Wenn wir das Kästchen für Environment variables (Umgebungsvariablen) anklicken, wird die Schaltfläche Add (Hinzufügen) angezeigt. Klicken Sie darauf, um die oben genannten Variablen als Schlüssel-Wert-Paare hinzuzufügen:

Klicken Sie unten auf der Seite auf die Schaltfläche Save (Speichern), um die Änderungen zu übernehmen.
7. Pipeline einrichten
Klicken Sie in Jenkins auf „New Item“ (Neues Element):

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

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

Klicken Sie auf Save (Speichern), um diese Einstellungen anzuwenden. Nach dem Speichern startet Jenkins einen Scan des Repositorys und einen anschließenden Build für jeden Zweig. Auf der Seite „Kubernetes-Arbeitslasten“ sehen Sie, wie Pods erstellt, ausgeführt und gelöscht werden, während die Builds ausgeführt werden.
Nach Abschluss der Builds 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 ist „OK“:

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 sehen 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 der Cloud Shell auf das Symbol für die Webvorschau und wählen Sie „Vorschau auf Port 8081“ aus.


8. Bereinigen
Wir haben uns angesehen, wie Sie eine Jenkins- und eine mehrzweigige Beispielpipeline in Kubernetes bereitstellen. Jetzt ist es an der Zeit, alle von uns erstellten Ressourcen aus unserem Projekt zu entfernen.
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 Beenden.
Alternativ können Sie das gesamte Projekt direkt über die Cloud Shell mit gcloud löschen:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Wenn Sie die verschiedenen kostenpflichtigen Komponenten 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 mit den 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 Digest Folgendes aus:
gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>
9. Glückwunsch!
Hurra! Sie haben 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 Helm verwendet, um Jenkins zu installieren.
- 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 mehrzweigige Pipeline eingerichtet wird, die Arbeit an GKE-Cluster sendet.