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
אימות
אחרי שיוצרים את האשכולות, אפשר לוודא שהם פועלים באמצעות הפקודה 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
אימות
מוודאים ש-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
אימות
נבדוק את ה-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, לוחצים על סמל התצוגה המקדימה של האינטרנט
ובוחרים באפשרות 'תצוגה מקדימה ביציאה 8080'.

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

כשלוחצים על Sign in (כניסה), אמורים להיות מועברים לדף הראשי של Jenkins.

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:

מזינים את נתיב הקובץ /tmp/kaniko-secret.json ולוחצים על 'הורדה'.
חוזרים לדף Jenkins, בחלונית בצד ימין לוחצים על Credentials (פרטי כניסה) ואז על System (מערכת).


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


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

משתני סביבה
יש כמה משתני סביבה שצריך להגדיר ב-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:

ואז Configure System:

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

לוחצים על הלחצן שמירה בחלק התחתון של הדף כדי להחיל את השינויים.
7. הגדרת צינור עיבוד נתונים
ב-Jenkins, לוחצים על New Item (פריט חדש):

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

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

לוחצים על שמירה כדי להחיל את ההגדרות האלה. אחרי השמירה, Jenkins יתחיל לסרוק את המאגר וליצור build לכל ענף. במהלך התהליך, תוכלו לראות את הפודים נוצרים, מופעלים ונהרסים בדף Kubernetes Workloads (עומסי עבודה של Kubernetes).
כשהבנייה מסתיימת, מופיעים שני פריטים בדף Kubernetes Workloads (עומסי עבודה של Kubernetes) בשם jenkins-integration-samples-gke, כל אחד מהם תואם לאשכול prod או לאשכול testing. הסטטוס יהיה OK:

באמצעות פקודת 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'.


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