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

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

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

מה תעשו

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

מה תצטרכו

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

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

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

Cloud Shell

במהלך ה-codelab הזה, נספק ונגידר משאבים ושירותים שונים בענן באמצעות שורת הפקודה דרך 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 שלנו, כולל הפודים שישמשו כצמתי עובדים. היקף ההרשאות הנוסף שמצוין על ידי הדגל --scopes יאפשר ל-Jenkins לגשת אל Cloud Source Repositories ו-Container Registry. ב-Cloud Console, מריצים את הפקודה הבאה:

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

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

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

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

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

cd ~/continuous-deployment-on-kubernetes/

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

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}

מורידים את קובץ ה-Helm הבינארי ל-Cloud Console:

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

הפלט צריך להציג את ה-pod של Jenkins עם הסטטוס RUNNING:

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

כשלוחצים על Sign in (כניסה), אמורים להיות מועברים לדף הראשי של 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 שייצור תפקיד מותאם אישית ב-GCP IAM עם הרשאות מוגבלות, וגם חשבון שירות ב-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 לדיסק המקומי על ידי גישה לפריט Download File (הורדת קובץ) מתפריט 3 הנקודות של Cloud Shell:

c40378e72013b843.png

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

חוזרים לדף Jenkins, בחלונית בצד ימין לוחצים על Credentials (פרטי כניסה) ואז על System (מערכת).

6c140f7e6bb82f8.png

3b874912cdc8019b.png

בקטע מערכת בדף,לוחצים על 'פרטי כניסה גלובליים' ואז על 'הוספת פרטי כניסה' בצד ימין:

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' שלנו, לצורכי הדגמה הוא 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

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

81aa222a2b17b2cc.png

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

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

ב-Jenkins, לוחצים על New Item (פריט חדש):

8d1270ce4d7b6a8a.png

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

eb071ecfbb4d775b.png

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

5135bd6b0374508c.png

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

כשהבנייה מסתיימת, מופיעים שני פריטים בדף Kubernetes Workloads (עומסי עבודה של Kubernetes) בשם jenkins-integration-samples-gke, כל אחד מהם תואם לאשכול prod או לאשכול testing. הסטטוס יהיה 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:

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

אפשר גם למחוק את כל הפרויקט ישירות מ-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