لمحة عن هذا الدرس التطبيقي حول الترميز
1. مرحبًا
نشكرك على الانضمام إلينا في ورشة عمل Istio Multi Cloud Burst codelab من Google.تتطلّب ورشة العمل هذه خبرة عملية على مستوى المبتدئين في Kubernetes وNode وGo. المتطلبات
|
ما الذي ستتعرّف عليه
- كيفية إنشاء مجموعة Kubernetes على Google Kubernetes Engine
- كيفية تثبيت Istio على مجموعة Kubernetes باستخدام Helm
- كيفية تثبيت Istio Multicluster باستخدام Helm
- نشر تطبيق ويب من المصدر إلى Kubernetes
- كتابة قواعد توجيه الزيارات وتطبيقها على Istio
- مقاييس Prometheus
- إنشاء صور حاويات ودفعها داخل مجموعة Kubernetes
2. الإعداد
يمكنك اتّباع هذا الدرس التطبيقي حول الترميز على أيّ من الرابطَين التاليَين:
- Google Cloud Shell (مُقترَح): واجهة مستخدِم داخل المتصفّح، تأتي مع أدوات مثبّتة
- الكمبيوتر المحمول (اتّبِع التعليمات أدناه)
البدء باستخدام Google Cloud Platform
- استلم بطاقة حساب المستخدم المجانية من المدرّس إذا لم يكن لديك حساب على Google Cloud Platform.
- انتقِل إلى Google Cloud Console وانقر على "اختيار مشروع":
- دوِّن رقم تعريف المشروع في مكان ما، ثم انقر على المشروع لاختياره:
الخيار 1: استخدام Google Cloud Shell (يُنصح به)
توفّر Cloud Shell بيئة سطر أوامر داخل المتصفّح تتضمّن الأدوات التي تحتاجها مثبّتة ومصادقة تلقائيًا على حسابك على Google Cloud Platform. (إذا كنت لا تريد تنفيذ هذا التمرين على Cloud Shell، انتقِل إلى القسم التالي).
انتقِل إلى وحدة تحكّم السحابة الإلكترونية وانقر على "تفعيل 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. بدء علامات تبويب جديدة: إذا كنت بحاجة إلى أكثر من طلب واحد في المحطة الطرفية. | |
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:
- باسم "primary"،
- في منطقة 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 الخاصة بمجموعة 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 الخاصة بمجموعة 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 المُنشَأة. تتحكّم حاوية الوكيل في جميع عمليات الاتصال بالشبكة بين الخدمات الصغيرة مع سياسة للأغراض العامة ومركز بيانات إحصاءات ( 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.
العامل
تم كتابة تطبيق Worker بتنسيق NodeJS وسيستمع إلى طلبات POST HTTP الواردة، وسينفّذ عملية تجزئة عليها، وإذا تم تعريف متغيّر بيئة باسم PREFIX
، سيضيف هذا المتغيّر إلى القيمة المجزّأة. بعد احتساب التجزئة، يرسل التطبيق النتيجة على القناة "calculation
" على خادم Redis المحدّد.
سنستخدم متغيّر البيئة PREFIX
لاحقًا لعرض وظيفة المجموعات المتعددة.
يُرجى العِلم أنّ هذه هي الحِزم التي يستخدمها التطبيق.
body-parser:
يسمح لنا بتحليل طلبات httpcors:
السماح باستخدام ميزة "مشاركة الموارد مع نطاقات خارجية"dotenv:
تحليل متغيرات البيئة بسهولةexpress:
استضافة المواقع الإلكترونية بسهولةioredis:
مكتبة العميل للتواصل مع قواعد بيانات Redismorgan:
يوفّر سجلّاً منظَّمًا جيدًا
الواجهة الأمامية
الواجهة الأمامية هي أيضًا تطبيق NodeJS يستضيف صفحة ويب باستخدام express. يأخذ هذا الإجراء معدّل تكرار يُدخله المستخدم ويرسل طلبات إلى تطبيق worker
وفقًا لهذا المعدّل. يشترك هذا التطبيق أيضًا في الرسائل على قناة Redis باسم "calculation
" ويعرض النتائج في صفحة ويب.
يستخدم التطبيق التبعيات التالية.
body-parser:
يسمح لنا بتحليل طلبات httpdotenv:
تحليل متغيرات البيئة بسهولةexpress:
استضافة المواقع الإلكترونية بسهولةioredis:
مكتبة العميل للتواصل مع قواعد بيانات Redismorgan:
توفير سجلّات منظَّمة بشكل جيد-
request:
السماح بإجراء طلبات HTTP socket.io:
السماح بالاتصال الثنائي الاتجاه من صفحة الويب إلى الخادم
تستخدم صفحة الويب هذه Bootstrap لتنسيق المحتوى، وعند تشغيلها، ستظهر على النحو التالي:
مخطّط البنية
مخطّط النشر
سننشر تطبيقنا النهائي على مجموعتَي البيانات اللتين أنشأناهما. ستتضمّن مجموعة primary
جميع المكوّنات (frontend
وworker
وRedis)، ولكن لن يتم نشر سوى تطبيق worker
في مجموعة burst
.
في ما يلي مخطّط بياني يصف مجموعتَي البيانات. المربّعات التي تم تحديدها باللون الأحمر هي خدمات 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.
كتابة 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
- نشر العامل
kubectl apply -f worker-primary.yaml
- نشر خدمة Worker
kubectl apply -f worker-service.yaml
لقد نشرنا تطبيقنا على GKE. تهانينا!
الاختبار
الانتظار إلى أن تظهر مجموعات التطبيقات على الإنترنت
kubectl get pods -w
بعد أن تصبح جميع وحدات pod "قيد التشغيل"، اضغط على 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: انقر على الزر "معاينة الويب" واختَر "معاينة على المنفذ 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 من خلال إدخال خدمة وكيل جانبي في كل عملية من عمليات النشر. يتم إجراء ذلك على أساس الموافقة، لذا نحتاج إلى تصنيف مساحة الاسم 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
- تطبيق 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
- نشر العامل
kubectl apply -f worker-primary.yaml
- نشر خدمة Worker
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 على "مجموعة الذروة"
لقد قضينا الكثير من الوقت في الإعداد والنشر على مجموعة 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 Cluster
لتثبيت 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
.
يؤدي ذلك إلى تقسيم الزيارات مناصفةً بين مجموعتَي البيانات.
النشر في المجموعة
نشر redis-service.yaml في مجموعة الفواصل الزمنية القصيرة
تغيير ملف 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 Architecture كمرجع:
عند نشر Istio مع Prometheus، يتم تلقائيًا إعداد تقارير عن مقاييس مختلفة لخادم Prometheus. يمكننا استخدام هذه المقاييس لإدارة مجموعاتنا على الفور.
استكشاف مقاييس Prometheus
للبدء، علينا إتاحة عملية نشر Prometheus.
انتقِل إلى علامة التبويب "الأحمال" في GKE، ثم انتقِل إلى "حمّل prometheus".
بعد عرض تفاصيل عملية النشر، انتقِل إلى "الإجراءات" -> "إظهار".
اختَر إعادة التوجيه إلى المنفذ 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. إنشاء ذروة على مستوى مجموعات متعددة
الإعداد
ضبط جميع الزيارات للخدمة العاملة على المجموعة الأساسية
سنعتبر أنّ جميع الزيارات المقصودة لـ 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 المتعدّد المراحل إصدار Istio 1.0.0 ويُستخرجه في المرحلة الأولى. تنسخ المرحلة الثانية كل شيء من الدليل إلى الصورة، ثم تنسخ 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. في هذه الحالة، يتم توجيه% 100 من الزيارات إلى مجموعة 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: حِزمة Open Cloud Stack الجديدة - أبرنا سينها، مديرة مجموعة منتجات Kubernetes في Google
- الدليل التعليمي: استخدام Istio - لي كالكوت وجيريش رانجاناناث، SolarWinds
- Istio - The Packet's-Eye View - Matt Turner, Tetrate
- هل Istio هو أفضل جدار حماية من الجيل التالي تم إنشاؤه على الإطلاق؟ - "جون موريللو"، Twistlock
- اطّلِع على مستندات Istio.
- الانضمام إلى مجموعات عمل Istio
- تابِع @IstioMesh على Twitter.