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
אימות
אחרי שיוצרים את האשכולות, אפשר לוודא שהם פועלים באמצעות 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
אימות
מוודאים ש-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
בפלט אמור להופיע הסטטוס 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, לוחצים על סמל התצוגה המקדימה באינטרנט ובוחרים באפשרות 'תצוגה מקדימה ביציאה 8080'.
אמור להופיע מסך התחברות של Jenkins, שבו נוכל להזין את admin
עבור שם המשתמש ואת הסיסמה שהוחזרה בשלב הקודם:
כשלוחצים על כניסה, אמורה להופיע הפניה לדף הראשי של 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 שיוצר תפקיד 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:
מזינים את נתיב הקובץ /tmp/kaniko-secret.json
ולוחצים על 'הורדה'.
חזרה לדף Jenkins, בחלונית הצדדית שבצד ימין, לוחצים על Credentials ואז על System.
בקטע System (מערכת) שבצד ימין,לוחצים על Global credentials (פרטי כניסה ברמת המערכת) ואז על Add credentials (הוספת פרטי כניסה):
בתפריט הנפתח 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
- 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 (הגדרת המערכת):
יופיע קטע בשם Global properties (מאפיינים גלובליים), וכשתסמנו את התיבה Environment variables (משתני סביבה) יופיע הלחצן Add (הוספה). לוחצים עליו כדי להוסיף את המשתנים שלמעלה כזוגות של מפתח/ערך:
לוחצים על הלחצן Save (שמירה) שבתחתית הדף כדי להחיל את השינויים.
7. הגדרת צינור עיבוד נתונים
ב-Jenkins, לוחצים על 'פריט חדש':
מזינים את השם jenkins-integration-sample, בוחרים באפשרות Multibranch Pipeline בתור סוג הפרויקט ולוחצים על OK:
המערכת תפנה אותנו לדף ההגדרה של צינור עיבוד הנתונים. בקטע Branch Sources (מקורות ההסתעפות), מזינים את הכתובת https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git כמאגר הפרויקט. בקטע Build Configuration (הגדרת build), מזינים את 'gke/Jenkinsfile' כScript Path (נתיב הסקריפט).
לוחצים על Save כדי להחיל את ההגדרות האלה. לאחר השמירה, Jenkins יתחיל לסרוק את המאגר ולבצע גרסה זמינה (build) לכל הסתעפות. ככל שהתהליך יתקדם, תוכלו לראות בדף Kubernetes Workloads את היצירה, ההפעלה וההשמדה של פקעות (pods) במהלך ה-build.
בסיום ה-builds, יופיעו שני פריטים בדף Kubernetes Workloads בשם jenkins-integration-samples-gke, כל אחד מהם תואם לאשכולות הייצור או הבדיקה. הסטטוס יופיע כ'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:
ברשימת הפרויקטים, בוחרים את הפרויקט שבו עבדנו ולוחצים על 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