استفاده از Istio Multicluster برای "Burst" بارهای کاری بین خوشه ها

استفاده از Istio Multicluster برای "Burst" بارهای کاری بین خوشه ها

درباره این codelab

subjectآخرین به‌روزرسانی: مارس ۳۰, ۲۰۲۱
account_circleنویسنده: یکی از کارمندان Google

1. خوش آمدید

از اینکه به ما در آزمایشگاه کد Istio Multi Cloud Burst توسط Google ملحق شدید متشکریم. این آزمایشگاه کد به تجربه عملی سطح مبتدی با Kubernetes، Node و Go نیاز دارد.

آنچه شما نیاز خواهید داشت

  • حساب Google Cloud Platform (از موجود استفاده کنید، در غیر این صورت حساب‌های رایگان ارائه می‌کنیم)
  • لپ تاپ خود («kubectl»، «gcloud» و غیره را نصب کنید) یا می توانید از Google Cloud Shell استفاده کنید.

آنچه خواهید آموخت

  • نحوه ایجاد یک خوشه Kubernetes در GKE
  • نحوه نصب Istio روی خوشه Kubernetes با Helm
  • نحوه نصب Istio Multicluster با Helm
  • استقرار یک برنامه وب از منبع به Kubernetes
  • نوشتن و اعمال قوانین مسیریابی ترافیک در ایستیو
  • متریک پرومتئوس
  • تصاویر ظرف را در یک خوشه Kubernetes بسازید و فشار دهید

2. در حال راه اندازی

می توانید این کد لبه را در یکی از موارد زیر دنبال کنید:

  • Google Cloud Shell (توصیه می شود) : پوسته درون مرورگر، همراه با ابزارهای نصب شده
  • لپ تاپ شما (دستورالعمل های زیر را دنبال کنید)

با Google Cloud Platform شروع کنید

  1. اگر حساب کاربری GCP ندارید، کارت حساب کاربری رایگان خود را از مربی دریافت کنید.
  2. به Google Cloud Console بروید و روی «انتخاب پروژه» کلیک کنید: 5c2d9bf74c78f7e4.png
  3. "ID" پروژه را در جایی یادداشت کنید ، سپس روی پروژه کلیک کنید تا آن را انتخاب کنید: ecc5e8e97bfa6559.png

Cloud Shell یک پوسته خط فرمان را در داخل مرورگر شما با ابزارهایی که نیاز دارید نصب کرده و به طور خودکار در حساب Google Cloud Platform شما احراز هویت می شود فراهم می کند. (اگر نمی خواهید این تمرین را در Cloud Shell اجرا کنید، به بخش بعدی بروید.)

به Cloud Console بروید و روی "Activate Cloud Shell" در نوار ابزار بالا سمت راست کلیک کنید:

68a17b036ce24ccb.png

ابزارها را به Cloud Shell اضافه کنید

  1. kubectx **** را نصب کنید : با دانلود اسکریپت های bash از اینجا در مکانی در $PATH.
  2. 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.

اگر در استفاده از محیط ایستگاه کاری خود نسبت به Cloud Shell احساس راحتی می کنید، ابزارهای زیر را تنظیم کنید:

  1. نصب gcloud: (از پیش نصب شده در Cloud Shell.) دستورالعمل ها را برای نصب gcloud بر روی پلت فرم خود دنبال کنید . ما از این برای ایجاد یک خوشه Kubernetes استفاده خواهیم کرد.
  2. Kubectl را نصب کنید kubectl: (از قبل در Cloud Shell نصب شده است.) دستور زیر را برای نصب اجرا کنید:
gcloud components install kubectl

برای احراز هویت gcloud دستور زیر را اجرا کنید. از شما می خواهد که با حساب Google خود وارد شوید. سپس، پروژه از پیش ساخته شده (در بالا) را به عنوان پروژه پیش فرض انتخاب کنید. (می توانید از پیکربندی منطقه محاسبه صرفنظر کنید):

gcloud init
  1. Install curl: در اکثر سیستم‌های Linux/macOS از قبل نصب شده است. احتمالاً قبلاً آن را دارید. در غیر این صورت، نحوه نصب آن را در اینترنت جستجو کنید.
  2. kubectx **** را نصب کنید : با دانلود اسکریپت های bash از اینجا در مکانی در $PATH
  3. helm **** را نصب کنید : این دستورالعمل ها را دنبال کنید.

3. راه اندازی پروژه GCP

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. خوشه "burst" را ایجاد کنید

دستور زیر یک خوشه Kubernetes ایجاد می کند:

  • به نام "ترکیدن"،
  • در منطقه us-west1-a،
  • آخرین نسخه Kubernetes موجود،
  • با 1 گره اولیه
  • مقیاس خودکار تا 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

ما هر دو کلاستر خود را راه‌اندازی کرده‌ایم و آماده هستیم تا برنامه و ایستیو خود را روی آنها مستقر کنیم!

7. مقدمه ای بر ایستیو

ایستیو چیست؟

ایستیو یک صفحه کنترل مش سرویس است که هدف آن "اتصال، ایمن سازی، کنترل و مشاهده سرویس ها" است. این کار را به روش‌های مختلفی انجام می‌دهد، اما عمدتاً با قرار دادن یک محفظه پراکسی ( Envoy ) در هر یک از Kubernetes Pods مستقر شده شما. کانتینر پروکسی تمام ارتباطات شبکه بین میکروسرویس ها را به صورت پشت سر هم با یک خط مشی همه منظوره و هاب تله متری ( میکسر ) کنترل می کند.

a25613cd581825da.png

این خط‌مشی‌ها می‌توانند مستقل از استقرار و سرویس‌های Kubernetes شما اعمال شوند، به این معنی که اپراتور شبکه می‌تواند فعالیت‌های شبکه را مشاهده کند، خط‌مشی‌های شبکه را محدود کند، هدایت کند یا بازنویسی کند، بدون اینکه برنامه‌های کاربردی مرتبط را دوباره مستقر کند.

برخی از ویژگی های مدیریت ترافیک پشتیبانی ایستیو عبارتند از:

  • کلیدهای مدار
  • تقسیم ترافیک مبتنی بر درصد
  • بازنویسی URL
  • خاتمه TLS
  • بررسی های سلامت
  • تعادل بار

برای اهداف این کارگاه، ما بر تقسیم ترافیک مبتنی بر درصد تمرکز خواهیم کرد.

شرایط Istio ما با آنها کار خواهیم کرد

سرویس مجازی

VirtualService مجموعه ای از قوانین مسیریابی ترافیک را برای اعمال در هنگام آدرس دهی یک میزبان تعریف می کند.

دروازه

Gateway یک متعادل کننده بار است که در لبه مش کار می کند و اتصالات HTTP/TCP ورودی یا خروجی را دریافت می کند. دروازه ها می توانند پورت ها، پیکربندی های SNI و غیره را مشخص کنند.

قانون مقصد

یک DestinationRule خط مشی هایی را تعریف می کند که برای ترافیک در نظر گرفته شده برای یک سرویس پس از انجام مسیریابی اعمال می شود. آنها پیکربندی را برای متعادل کردن بار، اندازه استخر اتصال از کالسکه کناری و تنظیمات تشخیص بیرون را مشخص می کنند.

چند خوشه ایستیو

ممکن است متوجه شده باشید زمانی که ما دو خوشه خود را ایجاد کردیم، که خوشه primary ما 4 گره بدون مقیاس خودکار، و خوشه burst ما 1 گره با مقیاس خودکار تا 5 گره بود.

دو دلیل برای این پیکربندی وجود دارد.

ابتدا می خواهیم یک سناریوی "on-prem" را در Cloud شبیه سازی کنیم. در یک محیط on-prem، به دلیل داشتن زیرساخت ثابت، به خوشه‌های مقیاس خودکار دسترسی ندارید.

دوم، راه اندازی 4 گره (همانطور که در بالا تعریف شد) حداقل الزامات برای اجرای Istio است. این سوال پیش می آید: اگر Istio به حداقل 4 گره نیاز دارد، چگونه خوشه burst ما می تواند Istio را با 1 گره اجرا کند؟ پاسخ این است که Istio Multicluster مجموعه بسیار کوچکتری از سرویس های Istio را نصب می کند و با نصب Istio در خوشه اولیه برای بازیابی قوانین خط مشی و انتشار اطلاعات تله متری ارتباط برقرار می کند.

8. نمای کلی معماری برنامه

بررسی اجمالی اجزاء

ما یک برنامه سه لایه را با استفاده از NodeJS و Redis اجرا خواهیم کرد.

کارگر

برنامه کارگر در NodeJS نوشته شده است و به درخواست های دریافتی POST HTTP گوش می دهد، عملیات هش را روی آنها انجام می دهد و اگر یک متغیر محیطی به نام PREFIX تعریف شده باشد، هش را با آن مقدار آماده می کند. هنگامی که هش محاسبه شد، برنامه نتیجه را در کانال " calculation " در سرور Redis مشخص شده ارسال می کند.

بعداً از متغیر محیطی PREFIX برای نشان دادن عملکرد چند خوشه ای استفاده خواهیم کرد.

برای مرجع: اینها بسته هایی هستند که برنامه استفاده می کند.

  • body-parser: به ما امکان می‌دهد تا درخواست‌های http خود را تجزیه کنیم
  • cors: امکان استفاده از Cross Origin Resource Sharing را می دهد
  • dotenv: تجزیه آسان متغیرهای محیطی
  • express: میزبانی آسان وب سایت
  • ioredis: کتابخانه مشتری برای ارتباط با پایگاه های داده Redis
  • morgan: گزارش ساختاری خوبی را ارائه می دهد

Frontend

ظاهر ما همچنین یک برنامه NodeJS است که یک صفحه وب را با استفاده از express میزبانی می کند. فرکانس ورودی کاربر را می گیرد و درخواست ها را با آن نرخ به برنامه worker ما ارسال می کند. این برنامه همچنین در پیام‌هایی در یک کانال Redis به نام " calculation " مشترک می‌شود و نتایج را در یک صفحه وب نمایش می‌دهد.

این برنامه از وابستگی های زیر استفاده می کند.

  • body-parser: به ما امکان می‌دهد تا درخواست‌های http خود را تجزیه کنیم
  • dotenv: تجزیه آسان متغیرهای محیطی
  • express: میزبانی آسان وب سایت
  • ioredis: کتابخانه مشتری برای ارتباط با پایگاه های داده Redis
  • morgan: سیاهههای مربوط به ساختار خوبی را ارائه می دهد
  • request: امکان ایجاد درخواست های HTTP را فراهم می کند
  • socket.io: امکان ارتباط دو طرفه از صفحه وب به سرور را فراهم می کند

این صفحه وب از Bootstrap برای یک ظاهر طراحی شده استفاده می کند و در هنگام اجرا به شکل زیر است

e5e3b9cbede4cac4.png

نمودار معماری

7ae4bc22a58f80a6.png

نمودار استقرار

ما برنامه نهایی خود را در دو خوشه ای که ایجاد کردیم، مستقر خواهیم کرد. خوشه primary همه مؤلفه‌ها ( frontend ، worker و Redis) روی آن مستقر شده است، اما خوشه burst فقط برنامه worker را دارد.

در اینجا نموداری است که این دو خوشه را توصیف می کند. جعبه‌هایی که با رنگ قرمز مشخص شده‌اند سرویس‌های Kubernetes و آنهایی که به رنگ آبی هستند، Kubernetes Deployments هستند. جعبه های زرد نشان دهنده نصب ما از Istio است.

561db37c510944bd.png

توجه کنید که چگونه خوشه burst هنوز یک سرویس برای Redis در آن مستقر شده است، حتی اگر هیچ Deployment برای Redis در خوشه وجود نداشته باشد. ما باید این سرویس را در کلاستر داشته باشیم تا Kubernetes DNS بتواند درخواست را حل کند، اما زمانی که درخواست واقعاً انجام شد، پروکسی Istio درخواست را به استقرار Redis در خوشه primary تغییر مسیر می دهد.

برنامه نهایی دارای یک Deployment اضافی خواهد بود که در خوشه primary به نام istiowatcher. این همان چیزی است که به ما امکان می‌دهد تا زمانی که ترافیک ما از یک آستانه خاص عبور می‌کند، ترافیک را به‌صورت خودکار به burst تغییر مسیر دهیم.

8f6183bdfc3f813c.png

9. ایجاد فایل های استقرار برنامه

ما باید مجموعه ای از مانیفست های Kubernetes ایجاد کنیم تا برنامه خود را به کار بگیریم

به دایرکتوری ریشه پروژه تغییر دهید و یک پوشه جدید به نام kubernetes ایجاد کنید

mkdir ${proj}/kubernetes && cd ${proj}/kubernetes

frontend.yaml بنویسید

با این کار هم یک Kubernetes Deployment و هم سرویس برای دسترسی به تصویر frontend ما ایجاد می شود.

موارد زیر را در 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 ساخته شده در ویژگی DNS برای حل سرویس به دست آمده استفاده خواهیم کرد.
  • ما آدرس REDIS_URL خود را به عنوان " redis-cache-service:6379 " تنظیم کرده ایم و از Kubernetes ساخته شده در ویژگی DNS برای حل آدرس های IP حاصل استفاده خواهیم کرد.
  • ما همچنین کاوشگرهای liveness و readiness را روی کانتینر تنظیم کرده‌ایم تا به کوبرنتس در زمان آماده‌بودن کانتینر اطلاع دهیم.

worker-service.yaml را بنویسید

ما در حال نوشتن تعریف سرویس Kubernetes در یک فایل جداگانه از تعریف Deployment هستیم، زیرا از این سرویس در چندین خوشه استفاده خواهیم کرد، اما یک Deployment متفاوت برای هر خوشه می نویسیم.

موارد زیر را در 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 است. بعداً هنگامی که مسیریابی ترافیک را در چند کلاستر ایستیو انجام می دهیم از آن استفاده خواهیم کرد

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 Deployment ما ارائه می دهد.

10. برنامه را مستقر کنید

از آنجایی که تصاویر ما به GCR فشار داده شده اند و مانیفست های Kubernetes ما نوشته شده اند، این نکته خوبی برای استقرار برنامه ما و دیدن نحوه عملکرد آن است!

دستورات زیر را برای استقرار برنامه اجرا کنید

  1. اطمینان حاصل کنید که در خوشه مناسبی هستیم
kubectx primary
  1. Redis Cache را مستقر کنید
kubectl apply -f redis.yaml
  1. سرویس Redis را مستقر کنید
kubectl apply -f redis-service.yaml
  1. استقرار frontend
kubectl apply -f frontend.yaml
  1. اعزام کارگر
kubectl apply -f worker-primary.yaml
  1. سرویس کارگر را مستقر کنید
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" کلیک کنید و "Preview on port 8080" را انتخاب کنید.

bdb5dc75f415be11.png

شما باید قسمت جلویی را ببینید! و اگر عددی را در کادر "فرکانس" وارد کنید، باید شاهد ظاهر شدن هش ها باشید

1caafaffab26897a.png

تبریک؛ همه چیز در حال اجراست!

Ctrl+C را فشار دهید تا فوروارد پورت متوقف شود.

11. برنامه نصب شده پاکسازی

ما می‌خواهیم Istio را در کلاستر خود اعمال کنیم و سپس برنامه خود را مجدداً مستقر کنیم، بنابراین اجازه دهید ابتدا برنامه فعلی خود را پاکسازی کنیم.

دستورات زیر را اجرا کنید تا همه Deployments و سرویس هایی که ایجاد کرده اید حذف شوند

  1. redis-cache-service را حذف کنید
kubectl delete -f redis-service.yaml
  1. redis حذف کنید
kubectl delete -f redis.yaml
  1. frontend حذف کنید
kubectl delete -f frontend.yaml
  1. حذف worker
kubectl delete -f worker-primary.yaml
  1. حذف worker-service
kubectl delete -f worker-service.yaml

12. Istio را روی کلاستر اولیه نصب کنید

ایستیو بگیر

نسخه های ایستیو در گیت هاب میزبانی می شود. دستورات زیر نسخه 1.0.0 istio را دانلود کرده و آن را باز می کند.

  1. به ریشه پروژه خود تغییر دهید
cd ${proj}
  1. آرشیو را دانلود کنید
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
  1. بایگانی را استخراج و حذف کنید
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-system ایجاد کنیم که استقرارها و سرویس‌های Istio بتوانند در آن اجرا شوند.

kubectl create namespace istio-system

و در نهایت فایل istio-primary.yaml را که با Helm ساختیم اعمال کنید

kubectl apply -f istio-primary.yaml

فضای نام پیش‌فرض را برچسب بزنید

Istio با تزریق یک سرویس پروکسی sidecar به هر یک از Deployment های شما کار می کند. این کار بر اساس انتخاب انجام می‌شود، بنابراین باید فضای نام default خود را با istio-injection=enabled برچسب‌گذاری کنیم تا Istio بتواند به طور خودکار سایدکار را برای ما تزریق کند.

kubectl label namespace default istio-injection=enabled

تبریک میگم ما یک کلاستر با Istio آماده و در حال اجرا داریم تا بتوانیم برنامه خود را اجرا کنیم!

13. برنامه ما را با مدیریت ترافیک ایستیو مستقر کنید

فایل های پیکربندی مدیریت ترافیک Istio را ایجاد کنید

Istio مشابه Kubernetes کار می کند زیرا از فایل های yaml برای پیکربندی استفاده می کند. در این راستا، ما باید مجموعه‌ای از فایل‌ها را ایجاد کنیم که به Istio بگوییم چگونه ترافیک ما را در معرض دید قرار دهد و مسیریابی کند.

یک دایرکتوری به نام istio-manifests ایجاد کنید و آن را تغییر دهید

mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests

frontend-gateway.yaml را بنویسید

این فایل خوشه Kubernetes ما را به روشی شبیه به GKE LoadBalancer نشان می دهد و تمام ترافیک ورودی را به سرویس frontend ما هدایت می کند.

یک فایل به نام 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 انجام می‌شود.

  1. دروازه ما را اعمال کنید
kubectl apply -f frontend-gateway.yaml
  1. Redis VirtualService ما را اعمال کنید
kubectl apply -f redis-virtualservice.yaml
  1. از Worker VirtualService ما استفاده کنید
kubectl apply -f worker-virtualservice.yaml

استقرار برنامه

  1. به دایرکتوری kubernetes ما برگردید
cd ${proj}/kubernetes
  1. Redis Cache را مستقر کنید
kubectl apply -f redis.yaml
  1. سرویس Redis را مستقر کنید
kubectl apply -f redis-service.yaml
  1. استقرار frontend
kubectl apply -f frontend.yaml
  1. اعزام کارگر
kubectl apply -f worker-primary.yaml
  1. سرویس کارگر را مستقر کنید
kubectl apply -f worker-service.yaml

تأیید کنید

در این مرحله، ما برنامه خود را مجدداً در یک خوشه با خط‌مشی‌های ایستیو و مدیریت ترافیک مستقر کرده‌ایم.

بیایید منتظر باشیم تا همه بارهای کاری ما آنلاین شود

وقتی همه آنها آنلاین شدند، 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 35.199.158.10
<!doctype html>
<html>

<head>
    <title>String Hashr</title>
    <!-- Bootstrap -->
...

14. Istio On "burst" Cluster را نصب کنید

ما زمان زیادی را صرف راه اندازی و استقرار در خوشه primary خود کرده ایم، اما یک خوشه کامل دیگر برای استقرار داریم!

در این بخش باید متغیرهای پیکربندی را در هر دو خوشه خود بگیریم، بنابراین به این نکته توجه کنید که برای هر دستور به کدام خوشه اشاره می کنیم.

Istio Remote Manifest را ایجاد کنید

درست مانند زمانی که ما Istio را در خوشه primary مستقر کردیم، از Helm برای الگوبرداری از استقرار istio remote در خوشه 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 خود، باید همان مراحلی را که هنگام نصب روی خوشه 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 برای آن ایجاد کنیم.

  1. نام خوشه را دریافت کنید
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
  1. نام سرور کلاستر را دریافت کنید
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
  1. نام راز حساب istio-multi Service Certificate Authority را دریافت کنید
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
  1. اطلاعات مرجع صدور گواهی را که در راز قبلی ذخیره شده است دریافت کنید
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
  1. توکن ذخیره شده در راز قبلی را دریافت کنید
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 را برای "burst" اعمال کنید

kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system

راز را برچسب بزنید تا ایستیو بداند که از آن برای احراز هویت چند خوشه ای استفاده کند

kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system

تبریک میگم ما هر دو خوشه را احراز هویت کرده ایم و از طریق Istio Multicluster با یکدیگر در ارتباط هستیم. بیایید برنامه Cross-Cluster خود را مستقر کنیم

15. استقرار یک برنامه Cross-Cluster

ایجاد استقرار

به دایرکتوری kubernetes تغییر دهید

cd ${proj}/kubernetes

ایجاد استقرار کارگر برای خوشه "burst": 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 ما از هر دو استقرار ما استفاده نمی کنند. 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 بین دو خوشه تقسیم می کند.

به Cluster مستقر شود

برای burst cluster، redis-service.yaml را مستقر کنید

به burst kubeconfig تغییر دهید

kubectx burst

به ریشه پروژه ما تغییر دهید

cd ${proj}

سپس مستقر کنید

redis-service.yaml را در خوشه burst مستقر کنید

kubectl apply -f kubernetes/redis-service.yaml

worker-burst.yaml را در خوشه burst مستقر کنید

kubectl apply -f kubernetes/worker-burst.yaml

worker-service.yaml را در خوشه burst مستقر کنید

kubectl apply -f kubernetes/worker-service.yaml

Istio VirtualServices را اعمال کنید

به kubeconfig primary تغییر دهید

kubectx primary

سپس Deploy

kubectl apply -f istio-manifests/worker-virtualservice.yaml

تایید کنید کار می کند

برای تأیید کارکرد آن، به نقطه ورود Istio خود بروید و متوجه شوید که چگونه حدود 50٪ از هش ها با "burst-" پیشوند شده اند.

78fb6e235e9f4a07.png

این به این معنی است که ما با موفقیت در حال صحبت کردن در میان خوشه‌ای هستیم! سعی کنید وزن سرویس های مختلف را تغییر دهید و فایل worker-virtualservice.yaml را اعمال کنید. این یک راه عالی برای متعادل کردن ترافیک بین خوشه‌ها است، اما اگر بتوانیم آن را به صورت خودکار انجام دهیم، چه؟

16. استفاده از متریک پرومتئوس

مقدمه ای بر پرومتئوس

Prometheus ، یک جعبه ابزار مانیتورینگ و هشدار سیستم منبع باز است که در ابتدا در SoundCloud ساخته شد. این یک مدل داده چند بعدی با داده‌های سری زمانی که با نام متریک و جفت‌های کلید/مقدار شناسایی می‌شوند، حفظ می‌کند.

برای مرجع، در اینجا نمودار معماری پرومتئوس آمده است:

601e1155a825e0c2.png

ایستیو، هنگامی که با Prometheus مستقر می شود، به طور خودکار معیارهای مختلف را به سرور Prometheus گزارش می دهد. ما می توانیم از این معیارها برای مدیریت خوشه های خود در پرواز استفاده کنیم.

کاوش معیارهای پرومتئوس ما

برای شروع، باید Prometheus Deployment را افشا کنیم.

به برگه Workloads در GKE بروید، به حجم کاری «prometheus» بروید.

b4a7a3cd67db05b3.png

هنگامی که جزئیات استقرار را مشاهده کردید، به Actions -> Expose بروید.

c04a482e55bdfd41.png

انتقال به پورت 9090 را انتخاب کنید و "Load balancer" را تایپ کنید

d5af3ba22a7a6ebb.png

و "Expose" را انتخاب کنید

این یک سرویس در یک آدرس IP در دسترس عموم ایجاد می کند که می توانیم از آن برای کاوش معیارهای Prometheus خود استفاده کنیم

منتظر بمانید تا نقطه پایانی عملیاتی شود و یکبار روی آدرس IP در کنار "External endpoints" کلیک کنید. b1e40ad90851da29.png

اکنون باید به رابط کاربری Prometheus نگاه کنید.

ed273552270337ec.png

پرومتئوس معیارهای کافی برای تبدیل شدن به کارگاه خود را ارائه می دهد. در حال حاضر، ما با بررسی متریک istio_requests_total شروع خواهیم کرد.

اجرای آن پرس و جو دسته ای از داده ها را برمی گرداند. این معیارها در مورد تمام درخواست هایی است که از طریق مش سرویس ایستیو می گذرند، و این بسیار است! ما عبارت خود را تغییر می دهیم تا به آنچه واقعاً به آن علاقه داریم فیلتر شود:

درخواست‌هایی که در آن سرویس مقصد 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]

و مجموعه ای بسیار قابل مدیریت از داده ها را برای کار به ما می دهد

19d551fd5eac3785.png

اما هنوز کمی متراکم است. ما می خواهیم درخواست ها را در هر ثانیه بدانیم، نه همه درخواست ها را.

برای بدست آوردن آن، می توانیم از تابع rate داخلی استفاده کنیم

rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

dbb9dc063a18da9b.png

این ما را نزدیک‌تر می‌کند، اما باید این معیارها را کمی بیشتر به یک گروه منطقی کاهش دهیم.

برای این کار می‌توانیم 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)

898519966930ec56.png

کامل! ما می توانیم معیارهای دقیق مورد نیاز خود را از 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 آنها برای دریافت متریک استفاده کنیم.

ما می‌توانیم با درخواست http GET مانند آن، api آن‌ها را با کوئری خود جویا شویم. <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 استخراج کنیم

پاکسازی

ما باید سرویسی را که برای افشای پرومته استفاده کردیم حذف کنیم. در Google Cloud Console، به بالای سرویسی که ایجاد کردیم بروید و روی «Delete» کلیک کنید.

d58cb51b4c922751.png

مراحل بعدی:

با یافتن راهی برای کشف اینکه چگونه ترافیک در خوشه حرکت می کند و با چه سرعتی، گام بعدی ما این است که یک باینری کوچک بنویسیم که به طور دوره ای پرومتئوس را پرس و جو کند، و اگر درخواست ها در هر ثانیه به worker بالاتر از یک آستانه خاص باشد، اعمال می شود. وزن های مختلف مقصد در سرویس مجازی کارگر ما برای ارسال تمام ترافیک به خوشه burst . هنگامی که درخواست‌ها در ثانیه به زیر آستانه پایین‌تر می‌رسند، همه ترافیک را به primary بازگردانید.

17. یک Cross Cluster Burst ایجاد کنید

راه اندازی

تمام ترافیک برای worker-service را روی خوشه اصلی تنظیم کنید

ما تمام ترافیکی را که برای 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

istiowacher daemon را بنویسید

ما از Go برای نوشتن این سرویس برای سرعت و قابلیت حمل آن استفاده خواهیم کرد. جریان کلی برنامه شروع به کار خواهد بود و هر ثانیه، درخواست پرومته،

یک دایرکتوری جدید در 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 ایستیو را در مرحله اول دانلود و استخراج می کند. مرحله دوم همه چیز را از دایرکتوری ما در تصویر کپی می کند، سپس 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

ساخت و فشار istiowacher

برای ارسال دایرکتوری فعلی به Google Could Build (GCB)، که تصویر را در GCR ساخته و برچسب گذاری می کند، موارد زیر را اجرا کنید.

gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher

istiowacher را مستقر کنید

به دایرکتوری 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 وجود ندارد).

تماشا کنید که ترافیک به طور خودکار تغییر می کند!

حالا برای لحظه جادویی! بیایید به قسمت جلویی خود برویم و req/second را به 20 برسانیم

توجه داشته باشید که چند ثانیه طول می کشد، اما ما آن را افزایش می دهیم و همه هش های ما پیشوند "bursty-" دارند!

این به این دلیل است که ما در حال نمونه برداری از پرومته در محدوده 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

رو به جلو