1. مرحبًا
نشكرك على الانضمام إلينا في درس تطبيقي حول الترميز عن Istio Multi Cloud Burst من Google.تتطلّب هذه التجربة العملية خبرة عملية على مستوى المبتدئين في Kubernetes وNode وGo. المتطلبات
|
|
ما ستتعلمه
- كيفية إنشاء مجموعة Kubernetes على GKE
- كيفية تثبيت Istio على مجموعة Kubernetes باستخدام Helm
- كيفية تثبيت Istio Multicluster باستخدام Helm
- نشر تطبيق ويب من المصدر إلى Kubernetes
- كتابة قواعد توجيه الزيارات وتطبيقها على Istio
- مقاييس Prometheus
- إنشاء صور حاويات ونقلها إلى داخل مجموعة Kubernetes
2. الإعداد
يمكنك اتّباع هذا الدرس التطبيقي حول الترميز على أيّ من:
- Google Cloud Shell (يُنصح به): واجهة سطر أوامر في المتصفّح، تتضمّن أدوات مثبَّتة
- جهاز الكمبيوتر المحمول (اتّبِع التعليمات أدناه)
بدء استخدام Google Cloud Platform
- احصل على بطاقة حساب المستخدم المجاني من المدرّب إذا لم يكن لديك حساب على GCP.
- انتقِل إلى Google Cloud Console وانقر على "اختيار مشروع":

- دوِّن "رقم التعريف" الخاص بالمشروع في مكان ما، ثم انقر على المشروع لاختياره:

الخيار 1: استخدام Google Cloud Shell (يُنصح به)
توفّر Cloud Shell واجهة سطر أوامر داخل المتصفّح مع الأدوات التي تحتاج إليها مثبّتة ومصادق عليها تلقائيًا في حسابك على Google Cloud Platform. (إذا كنت لا تريد تنفيذ هذا التمرين على Cloud Shell، انتقِل إلى القسم التالي).
انتقِل إلى Cloud Console وانقر على "تفعيل Cloud Shell" في شريط الأدوات أعلى يسار الصفحة:

إضافة أدوات إلى Cloud Shell
- تثبيت
kubectx****: نزِّل نصوص bash البرمجية من هنا إلى موقع في $PATH. - ثبِّت
helm****: باتّباع هذه التعليمات.
يمكنك بدلاً من ذلك تشغيل هذه الأوامر لتثبيت كليهما في ~/.bin وإضافته إلى $PATH:
mkdir -p ~/.bin && \
cd ~/.bin && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubectx && \
chmod +x kubectx && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubens && \
chmod +x kubens && \
curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz && \
tar xzf helm-v2.12.0-linux-amd64.tar.gz && \
rm helm-v2.12.0-linux-amd64.tar.gz && \
mv linux-amd64/helm ./helm && \
rm -r linux-amd64 && \
export PATH=${HOME}/.bin:${PATH}
في ما يلي بعض النصائح السريعة التي يمكن أن تسهّل استخدام Cloud Shell:
1. فصل الصدفة في نافذة جديدة: |
|
2. استخدام أداة تعديل الملفات: انقر على رمز القلم الرصاص في أعلى يسار الشاشة لتشغيل أداة تعديل الملفات في المتصفّح. سيكون هذا الإجراء مفيدًا لأنّنا سننسخ مقتطفات الرموز إلى الملفات. |
|
3. بدء علامات تبويب جديدة: إذا كنت بحاجة إلى أكثر من طلب واحد في Terminal |
|
4. تكبير النص: قد يكون حجم الخط التلقائي في Cloud Shell صغيرًا جدًا بحيث لا يمكن قراءته. | Ctrl-+ على Linux/Windows و⌘-+ على macOS |
الخيار 2: إعداد الكمبيوتر المحمول (لا يُنصح به)
إذا كنت تفضّل استخدام بيئة محطة العمل الخاصة بك بدلاً من Cloud Shell، عليك إعداد الأدوات التالية:
- تثبيت
gcloud:(مثبَّت مسبقًا على Cloud Shell) اتّبِع التعليمات لتثبيتgcloudعلى منصتك. سنستخدم هذا لإنشاء مجموعة Kubernetes. - تثبيت
kubectl:(مثبَّت مسبقًا على Cloud Shell) نفِّذ الأمر التالي للتثبيت:
gcloud components install kubectl
نفِّذ الأمر التالي للمصادقة على gcloud. سيُطلب منك تسجيل الدخول باستخدام حسابك على Google. بعد ذلك، اختَر المشروع الذي تم إنشاؤه مسبقًا (الموضّح أعلاه) كمشروع تلقائي. (يمكنك تخطّي ضبط منطقة حساب):
gcloud init
- ثبِّت
curl:، وهو مثبَّت مسبقًا على معظم أنظمة Linux/macOS. من المحتمل أن يكون لديك هذا التطبيق. وإلا، ابحث على الإنترنت عن كيفية تثبيته. - تثبيت
kubectx****: يمكنك إجراء ذلك عن طريق تنزيل نصوص bash البرمجية من هنا إلى موقع في $PATH - ثبِّت
helm****: باتّباع هذه التعليمات.
3- إعداد مشروع Google Cloud Platform
فعِّل واجهات برمجة التطبيقات GKE (Google Kubernetes Engine) وGCR (Google Container Registry) وGCB (Google Cloud Build) في مشروعك:
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
إعداد متغيّرات البيئة
سنعمل مع مشروع Google Cloud بشكل مكثّف أثناء عملية الإعداد، لذا لنضبط متغيّر بيئة للرجوع إليه بسرعة.
export GCLOUD_PROJECT=$(gcloud config get-value project)
سننشئ بعض الرموز البرمجية وملفات الإعدادات خلال ورشة العمل هذه، لذا لننشئ دليل مشروع وننتقل إليه.
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. إنشاء مجموعة Kubernetes "أساسية"
يمكنك إنشاء مجموعة Kubernetes مُدارة بسهولة باستخدام Google Kubernetes Engine (GKE).
سينشئ الأمر التالي مجموعة Kubernetes:
- الذي يحمل الاسم "أساسي"،
- في المنطقة us-west1-a،
- أحدث إصدار من Kubernetes متاح
- مع 4 عُقد أولية
export cluster=primary
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(قد تستغرق هذه العملية حوالي 5 دقائق. يمكنك مشاهدة عملية إنشاء المجموعة في Cloud Console.)
بعد إنشاء مجموعة Kubernetes، يضبط gcloud إعدادات kubectl باستخدام بيانات الاعتماد التي تشير إلى المجموعة.
gcloud container clusters get-credentials $cluster --zone=$zone
من المفترض أن تتمكّن الآن من استخدام kubectl مع مجموعتك الجديدة.
نفِّذ الأمر التالي لإدراج عُقد Kubernetes في مجموعتك (يجب أن تعرض الحالة "جاهز"):
kubectl get nodes
تعديل أسماء ملفات Kubeconfig لتسهيل الاستخدام
سنبدّل بين السياقات بشكل متكرّر، لذا من المفيد أن يكون لدينا اسم مستعار قصير للمجموعات.
سيؤدي هذا الأمر إلى إعادة تسمية إدخال kubeconfig الذي أنشأته للتوّ إلى primary
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
ضبط الأذونات:
يتطلّب نشر Istio أن تكون مشرفًا على المجموعة. سيؤدي هذا الأمر إلى ضبط عنوان البريد الإلكتروني المرتبط بحسابك على Google Cloud كمشرف على المجموعة
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
5- إنشاء مجموعة "اللقطات المتتالية"
سينشئ الأمر التالي مجموعة Kubernetes:
- المسمّى "burst"،
- في المنطقة us-west1-a،
- أحدث إصدار من Kubernetes متاح
- مع عقدة أولية واحدة
- تفعيل التوسيع التلقائي لما يصل إلى 5 عُقد
export cluster=burst
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "1" --enable-autoscaling --min-nodes=1 --max-nodes=5 \
--network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(قد تستغرق هذه العملية حوالي 5 دقائق. يمكنك مشاهدة عملية إنشاء المجموعة في Cloud Console.)
بعد إنشاء مجموعة Kubernetes، يضبط gcloud إعدادات kubectl باستخدام بيانات الاعتماد التي تشير إلى المجموعة.
gcloud container clusters get-credentials $cluster --zone=$zone
من المفترض أن تتمكّن الآن من استخدام kubectl مع مجموعتك الجديدة.
نفِّذ الأمر التالي لإدراج عُقد Kubernetes في مجموعتك (يجب أن تعرض الحالة "جاهز"):
kubectl get nodes
تعديل أسماء ملفات Kubeconfig لتسهيل الاستخدام
سيعدّل هذا الأمر إدخال kubeconfig الذي أنشأته للتوّ إلى burst
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
ضبط الأذونات:
يتطلّب نشر Istio Remote أن تكون مشرفًا على المجموعة. سيؤدي هذا الأمر إلى ضبط عنوان البريد الإلكتروني المرتبط بحسابك على Google Cloud كمشرف على المجموعة
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. تطبيق قواعد جدار الحماية
لكي تتواصل مجموعتانا مع بعضهما البعض، علينا إنشاء قاعدة جدار حماية.
نفِّذ الأوامر التالية لإنشاء قاعدة جدار حماية في Google Cloud Platform تسمح للمجموعات بالتواصل
function join_by { local IFS="$1"; shift; echo "$*"; }
ALL_CLUSTER_CIDRS=$(gcloud container clusters list \
--filter="(name=burst OR name=primary) AND zone=$zone" \
--format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list \
--filter="(metadata.cluster-name=burst OR metadata.cluster-name=primary) AND metadata.cluster-location=us-west1-a" \
--format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
gcloud compute firewall-rules create istio-multicluster-test-pods \
--allow=tcp,udp,icmp,esp,ah,sctp \
--direction=INGRESS \
--priority=900 \
--source-ranges="${ALL_CLUSTER_CIDRS}" \
--target-tags="${ALL_CLUSTER_NETTAGS}" --quiet
لقد أعددنا المجموعتين العنقوديتين وأصبحتا جاهزتين لنشر تطبيقنا وIstio عليهما.
7. مقدمة حول Istio
ما هي Istio؟
Istio هي لوحة تحكّم في شبكة الخدمات تهدف إلى "ربط الخدمات وتأمينها والتحكّم فيها ومراقبتها". ويتم ذلك بعدة طرق، ولكن في المقام الأول من خلال إضافة حاوية وكيل ( Envoy) إلى كل من وحدات Kubernetes Pod التي تم نشرها. يتحكّم حاوية الخادم الوكيل في جميع عمليات الاتصال بالشبكة بين الخدمات المصغّرة بالتزامن مع سياسة عامة الغرض ومركز القياس عن بُعد ( Mixer).

يمكن تطبيق هذه السياسات بشكل مستقل عن عمليات النشر والخدمات في Kubernetes، ما يعني أنّه يمكن لمشغّل الشبكة مراقبة نشاط الشبكة أو تقييده أو إعادة توجيهه أو إعادة كتابة سياسات الشبكة بدون إعادة نشر التطبيقات المرتبطة بها.
في ما يلي بعض ميزات إدارة الزيارات التي يتيحها Istio:
- قواطع الدائرة الكهربائية
- تقسيم عدد الزيارات استنادًا إلى النسبة المئوية
- إعادة كتابة عناوين URL
- إنهاء بروتوكول أمان طبقة النقل (TLS)
- فحوص صحية
- موازنة الحمل
لأغراض ورشة العمل هذه، سنركّز على تقسيم عدد الزيارات استنادًا إلى النسبة المئوية.
مصطلحات Istio التي سنتعامل معها
VirtualService
تحدّد VirtualService مجموعة من قواعد توجيه حركة البيانات التي يجب تطبيقها عند توجيه الطلب إلى مضيف.
بوابة الدفع
البوابة هي جهاز موازنة حمل يعمل على حافة الشبكة المتداخلة ويتلقّى اتصالات HTTP/TCP الواردة أو الصادرة. يمكن أن تحدّد البوابات المنافذ وإعدادات SNI وما إلى ذلك.
DestinationRule
تحدّد DestinationRule السياسات التي تنطبق على الزيارات الموجّهة إلى إحدى الخدمات بعد حدوث التوجيه. تحدّد هذه الإعدادات إعدادات موازنة التحميل وحجم مجموعة الاتصالات من الحاوية الجانبية وإعدادات رصد القيم الشاذة.
Istio Multicluster
ربما لاحظت عند إنشاء مجموعتَينا أنّ المجموعة primary كانت تتضمّن 4 عُقد بدون قياس تلقائي، بينما كانت المجموعة burst تتضمّن عقدة واحدة مع قياس تلقائي يصل إلى 5 عُقد.
هناك سببان لهذا الإعداد.
أولاً، نريد محاكاة سيناريو "من بيئة محلية إلى السحابة الإلكترونية". في بيئة محلية، لا يمكنك الوصول إلى المجموعات التي يتم توسيع نطاقها تلقائيًا لأنّ لديك بنية أساسية ثابتة.
ثانيًا، يشكّل إعداد 4 عُقد (كما هو موضّح أعلاه) الحد الأدنى من المتطلبات لتشغيل Istio. وهذا يطرح السؤال التالي: إذا كان Istio يتطلّب 4 عقد على الأقل، كيف يمكن لمجموعة burst تشغيل Istio بعقدة واحدة؟ والسبب هو أنّ Istio Multicluster يثبّت مجموعة أصغر بكثير من خدمات Istio، ويتواصل مع عملية تثبيت Istio في المجموعة الأساسية لاسترداد قواعد السياسات ونشر معلومات القياس عن بُعد.
8. نظرة عامة على بنية التطبيق
نظرة عامة على المكوّنات
سننشر تطبيقًا بثلاث طبقات باستخدام NodeJS وRedis.
عامل
تمت كتابة تطبيق العامل بلغة NodeJS وسيستمع إلى طلبات HTTP POST الواردة، وينفّذ عملية تجزئة عليها، وإذا تم تحديد متغيّر بيئة باسم PREFIX، سيضيف القيمة إلى بداية التجزئة. بعد احتساب التجزئة، يرسل التطبيق النتيجة إلى القناة "calculation" على خادم Redis المحدّد.
سنستخدم متغيّر البيئة PREFIX لاحقًا لتوضيح وظيفة المجموعات المتعددة.
للعلم، هذه هي الحِزم التي يستخدمها التطبيق.
body-parser:يسمح لنا بتحليل طلبات httpcors:يسمح باستخدام مشاركة الموارد المشتركة النطاقdotenv:سهولة تحليل متغيرات البيئةexpress:استضافة سهلة للمواقع الإلكترونيةioredis:مكتبة برامج للعميل للتواصل مع قواعد بيانات Redismorgan:توفير سجلّ منظَّم بشكل جيد
Frontend
واجهتنا الأمامية هي أيضًا تطبيق NodeJS يستضيف صفحة ويب باستخدام express. يأخذ هذا البرنامج معدّل تكرار يحدّده المستخدم ويرسل الطلبات إلى تطبيق worker بهذا المعدّل. يشترك هذا التطبيق أيضًا في تلقّي الرسائل على قناة Redis باسم "calculation" ويعرض النتائج في صفحة ويب.
يستخدم التطبيق التبعيات التالية.
body-parser:يسمح لنا بتحليل طلبات httpdotenv:سهولة تحليل متغيرات البيئةexpress:استضافة سهلة للمواقع الإلكترونيةioredis:مكتبة برامج للعميل للتواصل مع قواعد بيانات Redismorgan:توفير سجلات منظَّمة بشكل جيدrequest:السماح بإجراء طلبات HTTPsocket.io:تتيح هذه السمة الاتصال في اتجاهين من صفحة الويب إلى الخادم
تستخدم صفحة الويب هذه Bootstrap لتحديد الأنماط، وعند تشغيلها، ستظهر على النحو التالي

مخطط البنية

مخطط النشر
سننشر تطبيقنا النهائي على المجموعتين اللتين أنشأناهما. سيحتوي مجموعة primary على جميع المكوّنات (frontend وworker وRedis) التي تم نشرها فيها، بينما سيحتوي مجموعة burst على تطبيق worker فقط.
في ما يلي مخطط بياني يصف المجموعتين. المربّعات المحدّدة باللون الأحمر هي "خدمات Kubernetes"، والمربّعات المحدّدة باللون الأزرق هي "عمليات نشر Kubernetes". تشير المربّعات الصفراء إلى عملية تثبيت Istio.
لاحظ كيف أنّ المجموعة burst لا تزال تتضمّن خدمة Redis تم نشرها فيها على الرغم من عدم توفّر عملية نشر لـ Redis في المجموعة. نحتاج إلى توفير هذه الخدمة في المجموعة لكي يتمكّن نظام أسماء النطاقات في Kubernetes من حلّ الطلب، ولكن عند تقديم الطلب فعليًا، سيعيد Istio Proxy توجيه الطلب إلى عملية نشر Redis في مجموعة primary.
سيحتوي التطبيق النهائي على عملية نشر إضافية تعمل في المجموعة primary باسم istiowatcher.. سيسمح لنا ذلك بإعادة توجيه الزيارات ديناميكيًا إلى burst تلقائيًا عندما تتجاوز الزيارات حدًا معيّنًا.

9- إنشاء ملفات نشر التطبيق
علينا إنشاء مجموعة من بيانات Kubernetes لتوزيع تطبيقنا.
انتقِل إلى الدليل الجذر للمشروع وأنشِئ مجلدًا جديدًا باسم kubernetes
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
كتابة frontend.yaml
سيؤدي ذلك إلى إنشاء كلّ من عملية نشر Kubernetes وخدمة للوصول إلى صورة الواجهة الأمامية.
أدرِج ما يلي في frontend.yaml.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend-deployment
labels:
app: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: gcr.io/istio-burst-workshop/frontend
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PROCESSOR_URL
value: "http://worker-service"
- name: REDIS_URL
value: "redis-cache-service:6379"
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
نقاط أساسية يجب ملاحظتها في Deployment
- لقد حدّدنا المنفذ الذي سيتم تشغيل التطبيق عليه ليكون
8080 - لقد ضبطنا عنوان العامل على "
http://worker-service" وسنستخدم ميزة نظام أسماء النطاقات المضمّنة في Kubernetes لتحويل الخدمة الناتجة - لقد ضبطنا عنوان
REDIS_URLعلى "redis-cache-service:6379" وسنستخدم ميزة نظام أسماء النطاقات المضمّنة في Kubernetes لتحويل عناوين IP الناتجة. - لقد ضبطنا أيضًا عمليات فحص
livenessوreadinessللحاوية للمساعدة في إعلام Kubernetes عندما تكون الحاوية قيد التشغيل.
كتابة worker-service.yaml
نكتب تعريف خدمة Kubernetes في ملف منفصل عن تعريف النشر لأنّنا سنعيد استخدام هذه الخدمة في عدة مجموعات، ولكن سنكتب عملية نشر مختلفة لكل مجموعة.
أدرِج ما يلي في worker-service.yaml
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
كتابة worker-primary.yaml
سيكون هذا هو نشر worker الذي سنرسله إلى المجموعة الأساسية.
أدرِج ما يلي في worker-primary.yaml.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: primary-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
لاحظ في هذا المثال أنّنا نتبع النمط نفسه لتوفير عمليات التحقّق liveness وreadiness، بالإضافة إلى تحديد متغيّرات البيئة PORT وREDIS_URL التي سيستخدمها تطبيقنا.
من الأمور الأخرى التي يجب ملاحظتها في عملية النشر هذه عدم توفّر متغيّر البيئة PREFIX. وهذا يعني أنّ نتائج الحساب ستكون عبارة عن قيم تجزئة أولية (بدون أي بادئة).
النقطة الأساسية الأخيرة في عملية النشر هذه هي التصنيف cluster-type: primary-cluster. سنستخدم ذلك لاحقًا عند تنفيذ توجيه الزيارات على Istio Multicluster.
كتابة redis.yaml
يتم التواصل من العامل إلى الواجهة الأمامية من خلال قناة Redis، وبالتالي نحتاج إلى نشر تطبيق Redis في مجموعتنا.
أدخِل ما يلي إلى redis.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
template:
metadata:
labels:
app: redis-cache
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
هذا هو النشر شبه العادي لتطبيق Redis. يتم إنشاء حاوية استنادًا إلى صورة redis:alpine، ويتم عرض المنافذ المناسبة وضبط حدود معقولة للموارد.
كتابة redis-service.yaml
نحتاج إلى خدمة Kubernetes للتواصل مع تطبيق Redis
أدخِل ما يلي إلى redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
توفّر هذه السمة خدمة باسم redis-cache-service للوصول إلى عملية نشر Redis.
10. نشر التطبيق
بعد نقل صورنا إلى GCR وكتابة بيانات Kubernetes، يمكننا الآن نشر تطبيقنا والاطّلاع على طريقة عمله.
نفِّذ الأوامر التالية لنشر التطبيق
- التأكّد من أنّنا في المجموعة الصحيحة
kubectx primary
- تفعيل ذاكرة التخزين المؤقت Redis
kubectl apply -f redis.yaml
- نشر خدمة Redis
kubectl apply -f redis-service.yaml
- نشر الواجهة الأمامية
kubectl apply -f frontend.yaml
- Deploy Worker
kubectl apply -f worker-primary.yaml
- نشر خدمة العامل
kubectl apply -f worker-service.yaml
لقد نشرنا تطبيقنا على GKE. تهانينا!
الاختبار
الانتظار إلى حين توفّر الحاويات على الإنترنت
kubectl get pods -w
بعد أن تصبح جميع الحاويات في حالة "قيد التشغيل"، اضغط على Ctrl + C.
NAME READY STATUS RESTARTS AGE frontend-deployment-695d95fbf7-76sd8 1/1 Running 0 2m redis-cache-7475999bf5-nxj8x 1/1 Running 0 2m worker-deployment-5b9cf9956d-g975p 1/1 Running 0 2m
ستلاحظ أنّنا لم نعرض الواجهة الأمامية من خلال LoadBalancer. ويرجع ذلك إلى أنّنا سنصل إلى التطبيق لاحقًا من خلال Istio. للتأكّد من أنّ كل شيء يعمل بشكل صحيح، سنستخدم kubectl port-forward. شغِّل الأمر التالي لإعادة توجيه المنفذ 8080 على جهازك (أو Cloud Shell) إلى المنفذ 8080 الذي يشغّل عملية النشر frontend.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
إذا كنت تستخدم التطبيق على جهازك: افتح متصفّح ويب وانتقِل إلى http://localhost:8080
إذا كنت تستخدم Cloud Shell: انقر على الزر "معاينة الويب" (Web Preview) واختَر "معاينة على المنفذ 8080" (Preview on port 8080).

من المفترض أن تظهر لك الواجهة الأمامية. وإذا أدخلت رقمًا في مربّع "معدّل الظهور"، من المفترض أن تبدأ علامات التجزئة بالظهور

تهانينا، تم إعداد كل شيء وتشغيله.
انقر على Ctrl+C لإيقاف إعادة توجيه المنفذ.
11. تنظيف التطبيق الذي تم نشره
سنطبّق Istio على مجموعتنا ثم نعيد نشر تطبيقنا، لذا لنبدأ أولاً بتنظيف تطبيقنا الحالي.
نفِّذ الأوامر التالية لحذف جميع عمليات النشر والخدمات التي أنشأتها للتو
- حذف
redis-cache-service
kubectl delete -f redis-service.yaml
- حذف
redis
kubectl delete -f redis.yaml
- حذف
frontend
kubectl delete -f frontend.yaml
- حذف
worker
kubectl delete -f worker-primary.yaml
- حذف
worker-service
kubectl delete -f worker-service.yaml
12. تثبيت Istio على المجموعة الأساسية
تثبيت Istio
تتم استضافة إصدارات Istio على GitHub. ستؤدي الأوامر التالية إلى تنزيل الإصدار 1.0.0 من istio وفك حزمه.
- الانتقال إلى جذر مشروعك
cd ${proj}
- تنزيل الأرشيف
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- استخراج الأرشيف وإزالته
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
إنشاء نموذج Istio
سيؤدي تنفيذ أمر Helm التالي إلى إنشاء النموذج لتثبيت Istio على مجموعتك.
helm template istio-1.0.0/install/kubernetes/helm/istio \ --name istio --namespace istio-system \ --set prometheus.enabled=true \ --set servicegraph.enabled=true > istio-primary.yaml
سيؤدي ذلك إلى إنشاء ملف باسم istio-primary.yaml في الدليل الحالي يحتوي على جميع التعريفات والمواصفات اللازمة لنشر Istio وتشغيله.
لاحظ المَعلمتَين --set. تضيف هذه الحزمة إمكانية استخدام Prometheus وServiceGraph في نظام Istio. سنستخدم خدمة Prometheus لاحقًا في التمرين العملي.
نشر Istio
لنشر Istio، علينا أولاً إنشاء مساحة اسم باسم istio-system يمكن أن تعمل فيها عمليات نشر وخدمات Istio.
kubectl create namespace istio-system
وأخيرًا، طبِّق ملف istio-primary.yaml الذي أنشأناه باستخدام Helm
kubectl apply -f istio-primary.yaml
مساحة الاسم التلقائية للتصنيف
تعمل Istio من خلال إدخال خدمة وكيل sidecar في كل عمليات النشر. يتم ذلك على أساس الاشتراك، لذا علينا تصنيف مساحة الاسم default باستخدام istio-injection=enabled حتى يتمكّن Istio من إدخال الحاوية الجانبية تلقائيًا.
kubectl label namespace default istio-injection=enabled
تهانينا! لدينا مجموعة تعمل بشكل جيد مع Istio وجاهزة لنشر تطبيقنا.
13. نشر تطبيقنا باستخدام ميزة إدارة الزيارات في Istio
إنشاء ملفات إعداد إدارة الزيارات في Istio
تعمل Istio بشكل مشابه لـ Kubernetes لأنّها تستخدم ملفات yaml للإعداد. في هذا السياق، نحتاج إلى إنشاء مجموعة من الملفات لإخبار Istio بكيفية عرض الزيارات وتوجيهها.
أنشئ دليلاً باسم istio-manifests وانتقِل إليه
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
كتابة frontend-gateway.yaml
سيعرض هذا الملف مجموعة Kubernetes بطريقة مشابهة لـ GKE LoadBalancer وسيوجه كل الزيارات الواردة إلى خدمة الواجهة الأمامية.
أنشئ ملفًا باسم frontend-gateway.yaml وأدرِج ما يلي.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: frontend-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress-virtual-service
spec:
hosts:
- "*"
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend-service
port:
number: 80
كتابة redis-virtualservice.yaml
أنشئ ملفًا باسم redis-virtualservice.yaml وأدرِج ما يلي
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: redis-virtual-service
spec:
hosts:
- redis-cache-service
gateways:
- mesh
tcp:
- route:
- destination:
host: redis-cache-service.default.svc.cluster.local
كتابة worker-virtualservice.yaml
أنشئ ملفًا باسم worker-virtualservice.yaml وأدرِج ما يلي
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
port:
number: 80
نشر سياسات إدارة الزيارات في Istio
يتم نشر سياسات Istio بالطريقة نفسها التي يتم بها نشر موارد Kubernetes الأخرى، باستخدام kubectl apply
- تطبيق "بوابة الدفع"
kubectl apply -f frontend-gateway.yaml
- تطبيق Redis VirtualService
kubectl apply -f redis-virtualservice.yaml
- تطبيق Worker VirtualService
kubectl apply -f worker-virtualservice.yaml
نشر التطبيق
- الرجوع إلى الدليل
kubernetes
cd ${proj}/kubernetes
- تفعيل ذاكرة التخزين المؤقت Redis
kubectl apply -f redis.yaml
- نشر خدمة Redis
kubectl apply -f redis-service.yaml
- نشر الواجهة الأمامية
kubectl apply -f frontend.yaml
- Deploy Worker
kubectl apply -f worker-primary.yaml
- نشر خدمة العامل
kubectl apply -f worker-service.yaml
التحقّق
في هذه المرحلة، أعدنا نشر تطبيقنا على مجموعة تتضمّن Istio وسياسات إدارة الزيارات.
لننتظر إلى أن تصبح جميع أحمال العمل متاحة على الإنترنت
بعد أن تصبح جميعها متاحة على الإنترنت، احصل على IngressGateway الذي أعددناه في frontend-ingressgateway.yaml
$ kubectl -n istio-system get svc istio-ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.36.3.112 35.199.158.10 80:31380/TCP,
إما أن تتصفّح العنوان <EXTERNAL-IP> أو أن تستخدم الأمر curl، وسيظهر لك الواجهة الأمامية.
$ curl 35.199.158.10
<!doctype html>
<html>
<head>
<title>String Hashr</title>
<!-- Bootstrap -->
...
14. تثبيت Istio على مجموعة "burst"
لقد أمضينا الكثير من الوقت في إعداد ونشر مجموعة primary، ولكن لدينا مجموعة أخرى كاملة لنشرها.
في هذا القسم، سنحتاج إلى الحصول على متغيّرات الإعدادات في كلتا المجموعتين، لذا يجب الانتباه جيدًا إلى المجموعة التي نشير إليها لكل أمر.
إنشاء بيان Istio البعيد
كما فعلنا عند نشر Istio في المجموعة primary، سنستخدم Helm لإنشاء نموذج لعملية نشر Istio عن بُعد في المجموعة burst. قبل أن نتمكّن من ذلك، نحتاج إلى الحصول على بعض المعلومات حول مجموعة primary.
جمع معلومات المجموعة الأساسية
التغيير إلى مجموعة primary
kubectx primary
تستردّ الأوامر التالية عناوين IP الخاصة بالعديد من الحاويات في المجموعة الأساسية. يتم استخدامها من خلال Istio Remote للتواصل مع المجموعة الأساسية.
export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')
إنشاء نموذج عن بُعد
سنستخدم الآن helm لإنشاء ملف باسم istio-remote-burst.yaml يمكننا بعد ذلك نشره في مجموعة burst.
التغيير إلى جذر المشروع
cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \
--name istio-remote \
--set global.remotePilotAddress=${PILOT_POD_IP} \
--set global.remotePolicyAddress=${POLICY_POD_IP} \
--set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set global.proxy.envoyStatsd.enabled=true \
--set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \
--set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml
تثبيت Istio Remote على مجموعة Burst
لتثبيت Istio على مجموعة burst، علينا اتّباع الخطوات نفسها كما هو الحال عند التثبيت على مجموعة primary، ولكن علينا استخدام الملف istio-remote-burst.yaml بدلاً من ذلك.
تغيير kubecontext إلى burst
kubectx burst
إنشاء مساحة الاسم istio-system
kubectl create ns istio-system
تطبيق istio-burst.yaml
kubectl apply -f istio-remote-burst.yaml
مساحة الاسم التلقائية للتصنيف
مرة أخرى، علينا تصنيف مساحة الاسم default حتى يمكن إدخال الخادم الوكيل تلقائيًا.
kubectl label namespace default istio-injection=enabled
تهانينا! في هذه المرحلة، نكون قد أعددنا Istio Remote على مجموعة burst. في هذه المرحلة، لا تزال المجموعات غير قادرة على التواصل. علينا إنشاء ملف kubeconfig لمجموعة burst التي يمكننا نشرها في مجموعة primary لربطها معًا.
إنشاء ملف kubeconfig لمجموعة "burst"
التبديل إلى مجموعة اللقطات المتتالية
kubectx burst
إعداد البيئة
يجب جمع بعض المعلومات حول المجموعة من أجل إنشاء ملف kubeconfig لها.
- الحصول على اسم المجموعة
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- الحصول على اسم خادم المجموعة
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
- احصل على اسم سرّ هيئة إصدار الشهادات لحساب الخدمة
istio-multi
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- الحصول على بيانات هيئة إصدار الشهادات المخزّنة في كلمة المرور السابقة
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- الحصول على الرمز المميز المخزّن في السر السابق
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
إنشاء ملف kubeconfig
بعد ضبط جميع متغيّرات البيئة هذه، علينا إنشاء ملف kubeconfig
cat <<EOF > burst-kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${CA_DATA}
server: ${SERVER}
name: ${CLUSTER_NAME}
contexts:
- context:
cluster: ${CLUSTER_NAME}
user: ${CLUSTER_NAME}
name: ${CLUSTER_NAME}
current-context: ${CLUSTER_NAME}
kind: Config
preferences: {}
users:
- name: ${CLUSTER_NAME}
user:
token: ${TOKEN}
EOF
سيؤدي ذلك إلى إنشاء ملف جديد باسم burst-kubeconfig في الدليل الحالي يمكن أن تستخدمه مجموعة primary للمصادقة على مجموعة burst وإدارتها.
الرجوع إلى المجموعة الأساسية
kubectx primary
تطبيق ملف kubeconfig على "الزيادة المفاجئة" من خلال إنشاء مفتاح سرّي وتصنيفه
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
صنِّف كلمة المرور السرية لكي يعرف Istio كيفية استخدامها للمصادقة على مستوى عدة مجموعات.
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
تهانينا! تمت مصادقة المجموعتين وتواصلهما مع بعضهما البعض من خلال Istio Multicluster. لنبدأ بنشر تطبيقنا على مستوى عدة مجموعات
15. نشر تطبيق على مستوى عدة مجموعات
إنشاء عمليات نشر
تغيير إلى الدليل kubernetes
cd ${proj}/kubernetes
إنشاء عملية نشر عامل لمجموعة "الزيادة المفاجئة": worker-burst.yaml
أنشئ ملفًا باسم worker-burst.yaml وأدرِج فيه ما يلي:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: burst-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
لاحظ أنّ هذا الملف مطابق تقريبًا لملف worker-primary.yaml الذي أنشأناه سابقًا. هناك اختلافان رئيسيان.
أول اختلاف رئيسي هو أنّنا أضفنا متغير البيئة PREFIX بالقيمة "bursty-".
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
وهذا يعني أنّ العامل في مجموعة الخوادم burst سيضيف البادئة "bursty-" إلى جميع قيم التجزئة التي يرسلها، ويمكننا استخدام ذلك لمعرفة أنّ تطبيقنا يعمل على مستوى مجموعات الخوادم المختلفة.
الاختلاف الرئيسي الثاني هو أنّنا غيّرنا التصنيف cluster-type في عملية النشر هذه من primary-cluster إلى burst-cluster
labels:
app: worker
cluster-type: burst-cluster
سنستخدم هذه التصنيفات لاحقًا عند تعديل VirtualService.
تعديل خدمات Istio
في الوقت الحالي، لا تستفيد خدمات Istio من كلا عمليات النشر. يتم توجيه% 100 من الزيارات إلى المجموعة "الأساسية". لنغيّر ذلك.
التغيير إلى دليل istio-manifests
cd ${proj}/istio-manifests
تعديل worker-virtualservice.yaml لتضمين DestinationRules
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 50
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 50
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
يمكنك ملاحظة أنّنا أضفنا وجهة ثانية إلى VirtualService. لا يزال يشير إلى المضيف نفسه (worker-service.default.svc.cluster.local))، ولكن يتم توجيه% 50 من الزيارات إلى المجموعة الفرعية primary، ويتم توجيه% 50 الأخرى إلى المجموعة الفرعية burst.
لقد حدّدنا المجموعة الفرعية primary لتكون عمليات النشر التي تحمل التصنيف cluster-type: primary-cluster، والمجموعة الفرعية burst لعمليات النشر التي تحمل التصنيف cluster-type: burst-cluster.
يؤدي ذلك إلى تقسيم عدد الزيارات بشكل فعّال بنسبة 50/50 بين المجموعتَين.
النشر في المجموعة
نشر redis-service.yaml إلى مجموعة Burst
التغيير إلى ملف kubeconfig burst
kubectx burst
الانتقال إلى جذر مشروعنا
cd ${proj}
ثمّ انشر
نشر redis-service.yaml في مجموعة الحوسبة السريعة
kubectl apply -f kubernetes/redis-service.yaml
نشر worker-burst.yaml إلى مجموعة burst
kubectl apply -f kubernetes/worker-burst.yaml
نشر worker-service.yaml إلى مجموعة الحوسبة السحابية المؤقتة
kubectl apply -f kubernetes/worker-service.yaml
تطبيق Istio VirtualServices
التغيير إلى ملف kubeconfig primary
kubectx primary
ثم النشر
kubectl apply -f istio-manifests/worker-virtualservice.yaml
التأكّد من أنّها تعمل
للتأكّد من عملها، انتقِل إلى نقطة Istio Ingress، ولاحظ كيف أنّ حوالي% 50 من قيم التجزئة مسبوقة بـ "burst-".

هذا يعني أنّنا نتواصل بنجاح مع المجموعات المتعددة. جرِّب تغيير الأوزان على الخدمات المختلفة وتطبيق ملف worker-virtualservice.yaml. هذه طريقة رائعة لتحقيق التوازن في عدد الزيارات بين المجموعات، ولكن ماذا لو أمكننا إجراء ذلك تلقائيًا؟
16. الاستفادة من مقاييس Prometheus
مقدّمة عن Prometheus
Prometheus هي مجموعة أدوات مفتوحة المصدر لمراقبة الأنظمة وإرسال التنبيهات، وقد تم إنشاؤها في الأصل في SoundCloud. تحتفظ هذه الخدمة بنموذج بيانات متعدّد الأبعاد يتضمّن بيانات السلسلة الزمنية التي يتم تحديدها من خلال اسم المقياس وأزواج المفتاح/القيمة.
للعلم، إليك مخطط بنية Prometheus:

عند نشر Istio مع Prometheus، يتم تلقائيًا إرسال مقاييس مختلفة إلى خادم Prometheus. يمكننا استخدام هذه المقاييس لإدارة مجموعاتنا أثناء التنقل.
استكشاف مقاييس Prometheus
للبدء، علينا إتاحة عملية نشر Prometheus.
انتقِل إلى علامة التبويب "أحمال العمل" في GKE، ثم انتقِل إلى حمل العمل "prometheus".

بعد الاطّلاع على تفاصيل عملية النشر، انتقِل إلى "الإجراءات" (Actions) -> "عرض" (Expose).

اختَر إعادة التوجيه إلى المنفذ 9090، واكتب "موازن التحميل".

واختَر "عرض"
سيؤدي ذلك إلى إنشاء خدمة على عنوان IP يمكن الوصول إليه بشكل علني ويمكننا استخدامه لاستكشاف مقاييس Prometheus.
انتظِر إلى أن يصبح نقطة النهاية جاهزة للتشغيل، ثم انقر على عنوان IP بجانب "نقاط النهاية الخارجية" 
من المفترض أن تظهر لك الآن واجهة مستخدم Prometheus.

توفّر Prometheus مقاييس كافية لتكون ورشة عمل مستقلة. في الوقت الحالي، سنبدأ باستكشاف مقياس istio_requests_total.
سيؤدي تنفيذ طلب البحث هذا إلى عرض مجموعة من البيانات. وهي مقاييس لجميع الطلبات التي تمر عبر شبكة خدمات Istio، وهذا عدد كبير. سنغيّر التعبير لفلترة النتائج وعرض ما يهمّنا فقط:
الطلبات التي تكون فيها الخدمة الوجهة worker-service.default.svc.cluster.local، ويكون مصدرها frontend-deployment محدودًا بآخر 15 ثانية
يبدو هذا الاستعلام على النحو التالي:
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
ويمنحنا مجموعة بيانات أسهل بكثير للتعامل معها

لكنّها لا تزال معقّدة بعض الشيء. نريد معرفة عدد الطلبات في الثانية، وليس كل الطلبات.
للحصول على ذلك، يمكننا استخدام الدالة المضمّنة rate
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

هذا يقربنا من الهدف، ولكن علينا تقليل هذه المقاييس أكثر قليلاً إلى مجموعة منطقية.
لإجراء ذلك، يمكننا استخدام الكلمتَين الرئيسيتَين sum وby لتجميع نتائجنا وجمعها.
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)

ممتاز. يمكننا الحصول على المقاييس التي نحتاج إليها بالضبط من Prometheus.
طلب بحث Prometheus النهائي
بعد كل ما تعلّمناه، يكون الاستعلام النهائي الذي نحتاج إلى طرحه على Prometheus هو
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)
يمكننا الآن استخدام HTTP API للحصول على المقياس.
يمكننا طلب بيانات من واجهة برمجة التطبيقات باستخدام طلبنا من خلال إرسال طلب استرداد بيانات باستخدام GET HTTP على النحو التالي. استبدِل <prometheus-ip-here>
curl http://<prometheus-ip-here>/api/v1/query?query=sum\(rate\(istio_requests_total%7Breporter%3D%22destination%22%2C%0Adestination_service%3D%22worker-service.default.svc.cluster.local%22%2C%0Asource_workload%3D%22frontend-deployment%22%7D%5B15s%5D\)\)%20by%20\(source_workload%2C%0Asource_app%2C%20destination_service\)
في ما يلي مثال على الرد:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"destination_service": "worker-service.default.svc.cluster.local",
"source_app": "frontend",
"source_workload": "frontend-deployment"
},
"value": [
1544404907.503,
"18.892886390062788"
]
}
]
}
}
الآن، يمكننا استخراج قيمة المقياس من JSON
تنظيف
علينا حذف الخدمة التي استخدمناها للتو لعرض Prometheus. في Google Cloud Console، انتقِل إلى أعلى الخدمة التي أنشأناها للتوّ وانقر على "حذف".

الخطوات التالية:
بعد أن توصّلنا إلى طريقة لاستكشاف كيفية انتقال الزيارات عبر المجموعة ومعدّل انتقالها، تتمثّل خطوتنا التالية في كتابة برنامج ثنائي صغير يطلب بيانات من Prometheus بشكل دوري، وإذا تجاوزت الطلبات في الثانية إلى worker حدًا معيّنًا، يتم تطبيق أوزان وجهات مختلفة على الخدمة الافتراضية للعامل لإرسال جميع الزيارات إلى مجموعة burst. بعد أن ينخفض عدد الطلبات في الثانية إلى ما دون الحد الأدنى، أعِد توجيه كل الزيارات إلى primary.
17. إنشاء Cross Cluster Burst
الإعداد
توجيه كل الزيارات إلى خدمة العامل إلى المجموعة الأساسية
سنعتبر أنّ توجيه جميع الزيارات المتّجهة إلى worker-service إلى مجموعة primary هو الحالة "التلقائية" لتطبيقنا.
عدِّل $proj/istio-manifests/worker-virtualservice.yaml ليصبح على النحو التالي
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
التأكّد من اتصالك بمجموعة primary
kubectx primary
تطبيق istio-manifests/worker-virtualservice.yaml
kubectl apply -f istio-manifests/worker-virtualservice.yaml
كتابة برنامج istiowatcher الخفي
سنستخدم لغة البرمجة Go لكتابة هذه الخدمة بسبب سرعتها وإمكانية نقلها. سيكون سير التطبيق العام على النحو التالي: بدء التشغيل، ثم طلب البحث من Prometheus كل ثانية،
أنشئ دليلاً جديدًا في src باسم istiowatcher
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
سنتصل بالرقم istioctl من داخل الحاوية من أجل التحكّم في لوحة تحكّم Istio من داخل المجموعة.
كتابة istiowatcher.go
أنشئ ملفًا في هذا الدليل باسم istiowatcher.go وأدرِج فيه ما يلي
package main
import (
"github.com/tidwall/gjson"
"io/ioutil"
"log"
"net/http"
"os/exec"
"time"
)
func main() {
//These are in requests per second
var targetLow float64 = 10
var targetHigh float64 = 15
// This is for the ticker in milliseconds
ticker := time.NewTicker(1000 * time.Millisecond)
isBurst := false
// Our prometheus query
reqQuery := `/api/v1/query?query=sum(rate(istio_requests_total{reporter="destination",destination_service="worker-service.default.svc.cluster.local",source_workload="frontend-deployment"}[15s]))by(source_workload,source_app,destination_service)`
for t := range ticker.C {
log.Printf("Checking Prometheus at %v", t)
// Check prometheus
// Note that b/c we are querying over the past 5 minutes, we are getting a very SLOW ramp of our reqs/second
// If we wanted this to be a little "snappier" we can scale it down to say 30s
resp, err := http.Get("http://prometheus.istio-system.svc.cluster.local:9090" + reqQuery)
if err != nil {
log.Printf("Error: %v", err)
continue
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
val := gjson.Get(string(body), "data.result.0.value.1")
log.Printf("Value: %v", val)
currentReqPerSecond := val.Float()
log.Printf("Reqs per second %f", currentReqPerSecond)
if currentReqPerSecond > targetHigh && !isBurst {
applyIstio("burst.yaml")
log.Println("Entering burst mode")
isBurst = true
} else if currentReqPerSecond < targetLow && isBurst {
applyIstio("natural.yaml")
log.Println("Returning to natural state.")
isBurst = false
}
}
}
func applyIstio(filename string) {
cmd := exec.Command("istioctl", "replace", "-f", filename)
if err := cmd.Run(); err != nil {
log.Printf("Error hit applying istio manifests: %v", err)
}
}
كتابة ملف Dockerfile
أنشئ ملفًا جديدًا باسم Dockerfile وأدرِج فيه ما يلي.
FROM golang:1.11.2-stretch as base
FROM base as builder
WORKDIR /workdir
RUN curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
RUN tar xzf istio-1.0.0-linux.tar.gz
RUN cp istio-1.0.0/bin/istioctl ./istioctl
FROM base
WORKDIR /go/src/istiowatcher
COPY . .
COPY --from=builder /workdir/istioctl /usr/local/bin/istioctl
RUN go get -d -v ./...
RUN go install -v ./...
CMD ["istiowatcher"]
يؤدي ملف Dockerfile المتعدد المراحل هذا إلى تنزيل الإصدار 1.0.0 من Istio واستخراجه في المرحلة الأولى. في المرحلة الثانية، يتم نسخ كل شيء من الدليل إلى الصورة، ثم يتم نسخ istioctl من مرحلة الإنشاء إلى /usr/local/bin (حتى يتمكّن تطبيقنا من استدعائه)، ويتم الحصول على التبعيات وتجميع الرمز وضبط CMD على "istiowatcher".
كتابة ملف burst.yaml
سيتم تطبيق هذا الملف istiowatcher عندما يتجاوز عدد الطلبات في الثانية worker من frontend 15 طلبًا.
أنشئ ملفًا جديدًا باسم burst.yaml وأدرِج فيه ما يلي.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 0
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 100
كتابة ملف natural.yaml
سنعتبر هذه الحالة "طبيعية" ونعود إليها عندما ينخفض عدد الطلبات في الثانية من frontend إلى worker إلى أقل من 10. في هذه الحالة، يتم توجيه جميع الزيارات إلى مجموعة primary.
أنشئ ملفًا جديدًا باسم natural.yaml وأدرِج فيه ما يلي
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
إنشاء تطبيق istiowatcher ونشره
نفِّذ الأمر التالي لإرسال الدليل الحالي إلى Google Cloud Build (GCB)، الذي سينشئ الصورة ويضع عليها علامة في GCR.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
تفعيل istiowatcher
التغيير إلى دليل kubernetes
cd ${proj}/kubernetes/
كتابة ملف نشر: istiowatcher.yaml
أنشئ ملفًا باسم istiowatcher.yaml وأدرِج ما يلي (استبدِل <your-project-id>).
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: istiowatcher-deployment
labels:
app: istiowatcher
spec:
replicas: 1
selector:
matchLabels:
app: istiowatcher
template:
metadata:
labels:
app: istiowatcher
spec:
serviceAccountName: istio-pilot-service-account
automountServiceAccountToken: true
containers:
- name: istiowatcher
image: gcr.io/<your-project-id>/istiowatcher
imagePullPolicy: Always
تفعيل
التأكّد من أنّنا نعمل في المجموعة الأساسية
kubectx primary
نشر istiowatcher.yaml في مساحة الاسم istio-system
kubectl apply -n istio-system -f istiowatcher.yaml
من المهم ملاحظة التوجيهَين serviceAccountName وautomountServiceAccountToken في ملف yaml. يمنحنا ذلك بيانات الاعتماد اللازمة لتشغيل istioctl من داخل المجموعة.
علينا أيضًا نشر هذا الرمز البرمجي ضمن مساحة الاسم istio-system لضمان توفّر بيانات الاعتماد الخاصة بـ istio-pilot-service-account. (غير متوفّر في مساحة الاسم default).
شاهِد حركة المرور وهي تنتقل تلقائيًا!
حان وقت اللحظة السحرية! لننتقل إلى الواجهة الأمامية ونرفع عدد الطلبات في الثانية إلى 20
لاحظ أنّ الأمر يستغرق بضع ثوانٍ، ولكنّه يزداد تدريجيًا إلى أن يتم إضافة البادئة "bursty-" إلى جميع رموز التجزئة.
ويرجع ذلك إلى أنّنا نأخذ عينات من Prometheus على مدى نطاق 15s، ما يؤدي إلى تأخُّر وقت الاستجابة قليلاً. إذا أردنا نطاقًا أكثر دقة، يمكننا تغيير طلب البحث إلى Prometheus ليصبح 5s.
18 ما هي الخطوات التالية؟
تنظيف
لا داعي لتنظيف الحساب إذا كنت تستخدم حسابًا مؤقتًا تم توفيره لهذه الورشة التدريبية.
يمكنك حذف مجموعات Kubernetes وقاعدة جدار الحماية والصور في GCR.
gcloud container clusters delete primary --zone=us-west1-a
gcloud container clusters delete burst --zone=us-west1-a
gcloud compute firewall-rules delete istio-multicluster-test-pods
gcloud container images delete gcr.io/$GCLOUD_PROJECT/istiowatcher
المضي قدمًا
- حضور بعض جلسات Istio Talks
- الحصول على شهادة: إنشاء تطبيقك التالي باستخدام Kubernetes وIstio
- الجلسة الافتتاحية: Kubernetes وIstio وKnative: حزمة السحابة المفتوحة الجديدة - Aparna Sinha، مديرة منتجات مجموعة Kubernetes في Google
- برنامج تعليمي: استخدام Istio - Lee Calcote وGirish Ranganathan، SolarWinds
- Istio - The Packet's-Eye View - Matt Turner, Tetrate
- هل Istio هو أفضل جدار حماية من الجيل التالي على الإطلاق؟ - جون موريلو، Twistlock
- اطّلِع على مستندات Istio.
- الانضمام إلى مجموعات عمل Istio
- متابعة @IstioMesh على Twitter




