צינור עיבוד נתונים עם כמה הסתעפויות של Jenkins ב-GKE

1. סקירה כללית

Jenkins הוא אחד מהפתרונות הפופולריים ביותר לאינטגרציה רציפה (CI) שזמינים. הוא משמש להפיכת החלקים החיוניים בתהליך פיתוח התוכנה, שאינם אנושיים, לאוטומטיים. כשפורסים את Jenkins ב-Kubenetes ב-Google Cloud ומשתמשים בפלאגין של GKE, אפשר להתאים את היקף הפעילות של מבצעי ה-build במהירות ובאופן אוטומטי לפי הצורך. בשילוב עם Cloud Storage, אנחנו יכולים ליצור ולבדוק אפליקציה במאמץ מינימלי.

מה עליכם לעשות

  • פריסת Jenkins באשכול Kubernetes
  • פריסת הפלאגין של Jenkins ל-GKE והגדרתו כדי לאפשר ל-Jenkins ליצור ולעקור פקעות כצמתים של מבצעים
  • פיתוח ובדיקה של אפליקציית SpringBoot לדוגמה
  • פיתוח ופרסום של קונטיינר ב-Google Container Registry
  • פריסת האפליקציה לדוגמה בסביבת GKE ל-staging ולייצור

מה צריך להכין

  • פרויקט ב-Google Cloud שבו מוגדר חיוב. אם אין לכם חשבון, תצטרכו ליצור חשבון.

2. תהליך ההגדרה

אפשר להריץ את הקודלאב הזה לחלוטין ב-Google Cloud Platform בלי התקנה או הגדרה מקומית.

Cloud Shell

במהלך הקודלאב הזה, נקצה וננהל משאבים ושירותים שונים בענן באמצעות שורת הפקודה דרך Cloud Shell.

הפעלת ממשקי API

אלה ממשקי ה-API שנצטרך להפעיל בפרויקט:

  • Compute Engine API – יצירת מכונות וירטואליות והפעלתן
  • Kubernetes Engine API – פיתוח וניהול של אפליקציות מבוססות-קונטיינרים
  • Cloud Build API – פלטפורמת האינטגרציה וההפצה הרציפות של Google Cloud
  • Service Management API – מאפשר ליוצרים של שירותים לפרסם שירותים ב-Google Cloud Platform
  • Cloud Resource Manager API – יצירת מטא-נתונים, קריאה להם ועדכון שלהם בקונטיינרים של משאבים ב-Google Cloud

מפעילים את ממשקי ה-API הנדרשים באמצעות הפקודה הבאה ב-gcloud:

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

יצירת קטגוריה ב-GCS

נצטרך קטגוריה ב-GCS כדי להעלות את עבודת הבדיקה שלנו. נשתמש במזהה הפרויקט בשם הקטגוריה כדי להבטיח שהיא תהיה ייחודית:

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

3. יצירת אשכולות Kubernetes

יצירת האשכול

בשלב הבא נוצר אשכול GKE שיארח את מערכת Jenkins, כולל הפקדים (pods) שיישלחו כצומתי עבודה. ההיקף הנוסף שמצוין בדגל --scopes יאפשר ל-Jenkins לגשת ל-Cloud Source Repositories ול-Container Registry. מריצים את הפקודה הבאה במסוף Cloud:

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

נפרוס גם 2 אשכולות כדי לארח את גרסאות ה-build של האפליקציה לדוגמה בשלב ההרצה המקדימות ובייצור:

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 אימות

אחרי שיוצרים את האשכולות, אפשר לוודא שהם פועלים באמצעות gcloud container clusters list

הפלט אמור לכלול את הערך RUNNING בעמודה 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. פריסת Jenkins באמצעות Helm

התקנת Helm

כדי להתקין את Jenkins באשכול שלנו, נשתמש ב-Helm, מנהל חבילות אפליקציות ל-Kubernetes. כדי להתחיל, מורידים את הפרויקט שכולל את המניפסטים של Kubernetes שבהם נשתמש כדי לפרוס את Jenkins:

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

משנים את ספריית העבודה הנוכחית לספריית הפרויקט:

cd ~/continuous-deployment-on-kubernetes/

יוצרים קישור תפקידים באשכול כדי להקצות לעצמכם הרשאות של תפקיד אדמין באשכול:

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

מקבלים את פרטי הכניסה של האשכולות של Jenkins כדי להתחבר אליהם:

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

ומורידים את קובץ ה-binary של Helm למסוף Cloud:

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

מבטלים את האריזה של הקובץ ומעתיקים את קובץ ה-helm המצורף לספריית העבודה הנוכחית:

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

Tiller הוא צד השרת של Helm שפועל באשכול Kubernetes. נלמד ליצור חשבון שירות בשם tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

וגם לקשר אותו לתפקיד באשכול cluster-admin כדי שיוכל לבצע שינויים:

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

עכשיו אפשר לאתחל את Helm ולעדכן את המאגר:

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

28b45298e1e82748.png אימות

מוודאים ש-Helm מוכן לשימוש באמצעות ./helm version – הפקודה הזו אמורה להציג את מספרי הגרסה של הלקוח והשרת:

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

התקנת Jenkins

עכשיו, אחרי ש-Helm מותקן באשכול, אנחנו מוכנים להתקנה של Jenkins:

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

28b45298e1e82748.png אימות

נבדוק את ה-pods:

kubectl get pods

בפלט אמור להופיע הסטטוס RUNNING של אשכול Jenkins:

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

מוודאים ששירות Jenkins נוצר בצורה תקינה:

kubectl get svc

הפלט אמור להיראות כך:

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

התקנת Jenkins תשתמש בפלאגין של Kubernetes כדי ליצור סוכני build. הן יופעלו באופן אוטומטי על ידי המאסטר של Jenkins לפי הצורך. כשהעבודה שלהם מסתיימת, הם מסתיימים באופן אוטומטי והמשאבים שלהם מתווספים חזרה למאגר המשאבים של האשכולות.

התחברות ל-Jenkins

Jenkins פועל באשכול שלנו, אבל כדי לגשת לממשק המשתמש, צריך להגדיר העברה אוטומטית של יציאות מ-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 &

סיסמת אדמין נוצרה במהלך ההתקנה. נשלוף אותו:

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

בחלק העליון של Cloud Shell, לוחצים על סמל התצוגה המקדימה באינטרנט 7ddf5a65fd556dd6.png ובוחרים באפשרות 'תצוגה מקדימה ביציאה 8080'.

1d614c831a621cff.png

אמור להופיע מסך התחברות של Jenkins, שבו נוכל להזין את admin עבור שם המשתמש ואת הסיסמה שהוחזרה בשלב הקודם:

9cba23e856cbc84f.png

כשלוחצים על כניסה, אמורה להופיע הפניה לדף הראשי של Jenkins.

9261f3e914829137.png

5. התקנה והגדרה של הפלאגין של GKE

הפלאגין של Google Kubernetes Engine מאפשר לנו לפרסם פריסות שנוצרו ב-Jenkins באשכולות Kubernetes שלנו שפועלים ב-GKE. צריך לבצע הגדרות מסוימות עם הרשאות IAM בפרויקט. נפרוס את התצורה הזו באמצעות Terraform.

קודם כול, מורידים את פרויקט הפלאגין של GKE:

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

הגדרה אוטומטית של הרשאות IAM

מעבירים את ספריית העבודה הנוכחית לספרייה rbac של פרויקט GKE ששכפלנו מקודם:

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

gcp-sa-setup.tf הוא קובץ תצורה של Terraform שיוצר תפקיד IAM בהתאמה אישית ב-GCP עם הרשאות מוגבלות, יחד עם חשבון שירות ב-GCP שאותו תפקיד יוקצה אליו. בקובץ צריך לציין ערכים למשתני השם של הפרויקט, האזור וחשבון השירות. כדי לספק את הערכים האלה, קודם כול מגדירים את משתני הסביבה הבאים:

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

מפעילים את Terraform, יוצרים תוכנית ומחילים אותה:

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

לחשבון השירות יידרשו הרשאות אדמין לאחסון כדי לשמור בקטגוריה שלנו ב-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'

בנוסף, נדרשות הרשאות לקונטיינרים בשלבים של הפריסה בצינור עיבוד הנתונים שלנו:

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

עכשיו אפשר להשתמש ב-Helm כדי להגדיר הרשאות אשכול לתוסף GKE באמצעות הכלי לפריסה של הרובוט של GKE. משנים את ספריית העבודה לספריית ה-helm של פרויקט GKE:

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

והתקנה באמצעות תרשים Helm שסופק:

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

6. הגדרת Jenkins

מפתחות לחשבונות שירות

כדי שחשבון השירות יפעל כמו שצריך, נצטרך ליצור קובץ מפתח פרטי ולהוסיף אותו כסוד ב-Kubernetes. קודם יוצרים את הקובץ באמצעות הפקודה הבאה ב-gcloud:

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

נשתמש בקובץ הזה כדי ליצור מפתח סודי במאגר הסודות של Kubernetes:

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

מורידים את קובץ ה-JSON לדיסק המקומי על ידי כניסה לפריט 'הורדת קובץ' בתפריט של 3 הנקודות ב-Cloud Shell:

c40378e72013b843.png

מזינים את נתיב הקובץ /tmp/kaniko-secret.json ולוחצים על 'הורדה'.

חזרה לדף Jenkins, בחלונית הצדדית שבצד ימין, לוחצים על Credentials ואז על System.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

בקטע System (מערכת) שבצד ימין,לוחצים על Global credentials (פרטי כניסה ברמת המערכת) ואז על Add credentials (הוספת פרטי כניסה):

4350c0e68561119b.png

3d3526551cdae8b.png

בתפריט הנפתח Kind, בוחרים באפשרות Google Service Account from private key. מזינים את השם 'kaniko-role', מעלים את מפתח ה-JSON שנוצר בשלבים הקודמים ולוחצים על OK.

b0502213408e730e.png

משתני סביבה

יש כמה משתני סביבה שצריך להגדיר ב-Jenkins לפני שיוצרים צינור עיבוד נתונים עם כמה הסתעפויות. סוגי המשנה הם:

  • JENK_INT_IT_ZONE – האזור של אשכול Kubernetes. במקרה שלנו us-east1-d
  • JENK_INT_IT_PROJECT_ID – המשתנה הזה מתייחס למזהה הפרויקט ב-GCP שמארח את המכונה הזו של Jenkins
  • JENK_INT_IT_STAGING – שם האשכול שלנו ל'הרצה מוקדמת'. למטרות הדגמה, השם הוא staging
  • JENK_INT_IT_PROD – שם האשכול 'prod' שלנו. למטרות הדגמה, הערך הוא prod
  • JENK_INT_IT_BUCKET – הקטגוריה של Google Cloud Storage שנוצרה בשלב הקודם
  • JENK_INT_IT_CRED_ID – מתייחס לפרטי הכניסה שנוצרו באמצעות קובץ ה-JSON בשלב הקודם. הערך צריך להתאים לשם שנתתם לו, kaniko-role

כדי להוסיף אותם, עוברים אל Manage Jenkins:

d54f279190a07878.png

לאחר מכן Configure System (הגדרת המערכת):

ce79d218b2799640.png

יופיע קטע בשם Global properties (מאפיינים גלובליים), וכשתסמנו את התיבה Environment variables (משתני סביבה) יופיע הלחצן Add (הוספה). לוחצים עליו כדי להוסיף את המשתנים שלמעלה כזוגות של מפתח/ערך:

81aa222a2b17b2cc.png

לוחצים על הלחצן Save (שמירה) שבתחתית הדף כדי להחיל את השינויים.

7. הגדרת צינור עיבוד נתונים

ב-Jenkins, לוחצים על 'פריט חדש':

8d1270ce4d7b6a8a.png

מזינים את השם jenkins-integration-sample, בוחרים באפשרות Multibranch Pipeline בתור סוג הפרויקט ולוחצים על OK:

eb071ecfbb4d775b.png

המערכת תפנה אותנו לדף ההגדרה של צינור עיבוד הנתונים. בקטע Branch Sources (מקורות ההסתעפות), מזינים את הכתובת https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git כמאגר הפרויקט. בקטע Build Configuration (הגדרת build), מזינים את 'gke/Jenkinsfile' כScript Path (נתיב הסקריפט).

5135bd6b0374508c.png

לוחצים על Save כדי להחיל את ההגדרות האלה. לאחר השמירה, Jenkins יתחיל לסרוק את המאגר ולבצע גרסה זמינה (build) לכל הסתעפות. ככל שהתהליך יתקדם, תוכלו לראות בדף Kubernetes Workloads את היצירה, ההפעלה וההשמדה של פקעות (pods) במהלך ה-build.

בסיום ה-builds, יופיעו שני פריטים בדף Kubernetes Workloads בשם jenkins-integration-samples-gke, כל אחד מהם תואם לאשכולות הייצור או הבדיקה. הסטטוס יופיע כ'OK':

bdec6b1753d1ba07.png

באמצעות הפקודה הבאה של gcloud, נראה שהעלינו קובץ אימג' בקונטיינר ל-Google Container Registry שתואם לצינור עיבוד הנתונים שלנו:

gcloud container images list

כדי לראות את עומס העבודה בדפדפן, צריך לקבל את פרטי הכניסה לאשכולות הייצור:

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

מריצים את הפקודה הבאה כדי להגדיר העברה ליציאה אחרת מיציאה 8081 של המעטפת ליציאה 8080 של עומס העבודה:

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

בחלק העליון של Cloud Shell, לוחצים על סמל התצוגה המקדימה באינטרנט ובוחרים באפשרות 'תצוגה מקדימה ביציאה 8081'.

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. הסרת המשאבים

הראינו איך לפרוס Jenkins וצינור עיבוד נתונים לדוגמה עם כמה הסתעפויות ב-Kubernetes. עכשיו הגיע הזמן לנקות את הפרויקט מכל המשאבים שיצרנו.

מחיקת הפרויקט

אם תרצו, תוכלו למחוק את הפרויקט כולו. במסוף GCP, נכנסים לדף Cloud Resource Manager:

ברשימת הפרויקטים, בוחרים את הפרויקט שבו עבדנו ולוחצים על Delete. תתבקשו להקליד את מזהה הפרויקט. מזינים אותו ולוחצים על Shutdown.

לחלופין, אפשר למחוק את הפרויקט כולו ישירות מ-Cloud Shell באמצעות gcloud:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

אם אתם מעדיפים למחוק את הרכיבים השונים לחיוב בנפרד, תוכלו להמשיך לקטע הבא.

אשכול Kubernetes

מוחקים את כל אשכול Kubernetes באמצעות gcloud:

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

קטגוריות אחסון

מסירים את כל הקבצים שהועלו ומוחקים את הקטגוריה באמצעות gsutil:

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

תמונות ב-Google Container Registry

נמחק את התמונות ב-Google Container Registry באמצעות תמציות התמונות. קודם כול, מאחזרים את הסיכומים באמצעות הפקודה הבאה:

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

לאחר מכן, לכל סיכום שנוצר:

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

9. מעולה!

יש! הצלחת. למדתם איך לפרוס את Jenkins ב-GKE ולשלוח משימות לאשכולות Kubernetes.

מה עסקנו בו

  • פרסנו אשכול Kubernetes והשתמשנו ב-Helm כדי להתקין את Jenkins
  • התקננו והגדרתנו את הפלאגין של GKE כדי לאפשר ל-Jenkins לפרוס ארטיפקטים של גרסאות build לאשכולות Kubernetes
  • הגדרנו את Jenkins להגדרת צינור עיבוד נתונים עם כמה ענפים ששולח משימות לאשכולות GKE