Использование Istio Multicluster для «Burst» Рабочие нагрузки между кластерами

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.
  • Разработка и применение правил маршрутизации трафика в Istio
  • Метрики Прометея
  • Создание и загрузка образов контейнеров внутри кластера Kubernetes.

2. Настройка

Вы можете пройти этот практический урок на одной из следующих платформ:

  • Google Cloud Shell (рекомендуется) : оболочка в браузере, поставляется с предустановленными инструментами.
  • ваш ноутбук (следуйте инструкциям ниже)

Начните с Google Cloud Platform.

  1. Если у вас нет учетной записи GCP, получите бесплатную карту пользователя у инструктора.
  2. Перейдите в консоль Google Cloud и нажмите «Выберите проект»: 5c2d9bf74c78f7e4.png
  3. Запишите где-нибудь идентификатор проекта, затем щелкните по проекту, чтобы выбрать его: ecc5e8e97bfa6559.png

Cloud Shell предоставляет командную оболочку внутри вашего браузера с установленными необходимыми инструментами и автоматической аутентификацией в вашей учетной записи Google Cloud Platform. (Если вы не хотите выполнять это упражнение в Cloud Shell, перейдите к следующему разделу.)

Перейдите в Cloud Console и нажмите «Активировать 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: (Предустановлен в Cloud Shell.) Для установки выполните следующую команду:
gcloud components install kubectl

Выполните следующую команду для аутентификации в gcloud. Вам будет предложено войти в систему с помощью вашей учетной записи Google. Затем выберите предварительно созданный проект (показанный выше) в качестве проекта по умолчанию. (Вы можете пропустить настройку вычислительной зоны):

gcloud init
  1. Установите curl: он предустановлен в большинстве систем Linux/macOS. Вероятно, он у вас уже есть. В противном случае, найдите в интернете информацию о том, как его установить.
  2. Установите kubectx ****: загрузив bash-скрипты отсюда в папку, указанную в $PATH.
  3. Установите helm , следуя этим инструкциям .

3. Настройка проекта GCP

Включите API 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.

С помощью Google Kubernetes Engine (GKE) вы можете легко создать управляемый кластер Kubernetes.

Следующая команда создаст кластер 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 вашего кластера (они должны отображать статус "Ready"):

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:

  • названный "взрывом",
  • в зоне 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 вашего кластера (они должны отображать статус "Ready"):

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 ).

a25613cd581825da.png

Эти политики могут применяться независимо от ваших развертываний и служб Kubernetes, что означает, что сетевой оператор может отслеживать сетевую активность, ограничивать, перенаправлять или изменять сетевые политики без повторного развертывания соответствующих приложений.

Среди функций управления трафиком, поддерживаемых Istio, можно выделить следующие:

  • Автоматические выключатели
  • Разделение трафика на основе процентов
  • переписывание URL-адресов
  • завершение TLS
  • Медицинские осмотры
  • Балансировка нагрузки

В рамках этого семинара мы сосредоточимся на распределении трафика в процентном соотношении.

Условия Istio, с которыми мы будем работать

Виртуальная Служба

Виртуальный сервис определяет набор правил маршрутизации трафика, применяемых при обращении к хосту.

Врата

Шлюз — это балансировщик нагрузки, работающий на границе сети и принимающий входящие или исходящие HTTP/TCP-соединения. Шлюзы могут задавать порты, конфигурации SNI и т. д.

DestinationRule

Объект DestinationRule определяет политики, применяемые к трафику, предназначенному для сервиса, после завершения маршрутизации. Он задает конфигурацию для балансировки нагрузки, размер пула соединений из sidecar-контейнера и параметры обнаружения выбросов.

Istio Multicluster

Возможно, вы заметили, что при создании двух кластеров наш primary кластер состоял из 4 узлов без автомасштабирования, а кластер burst — из 1 узла с автомасштабированием до 5 узлов.

Такая конфигурация обусловлена ​​двумя причинами.

Во-первых, мы хотим смоделировать сценарий перехода из локальной среды в облако. В локальной среде у вас нет доступа к кластерам с автоматическим масштабированием, поскольку у вас фиксированная инфраструктура.

Во-вторых, для работы Istio требуется минимум 4 узла (как описано выше). Возникает вопрос: если для Istio требуется минимум 4 узла, как наш кластер burst может запустить Istio с одним узлом? Ответ заключается в том, что Istio Multicluster устанавливает гораздо меньший набор служб Istio и взаимодействует с установкой Istio в основном кластере для получения правил политики и публикации телеметрической информации.

8. Обзор архитектуры приложения

Обзор компонентов

Мы будем развертывать трехзвенное приложение с использованием NodeJS и Redis .

Рабочий

Рабочее приложение написано на NodeJS и будет прослушивать входящие HTTP-запросы POST, выполнять над ними операцию хеширования и, если определена переменная окружения с именем PREFIX , добавлять к хешу это значение. После вычисления хеша приложение отправляет результат в канал " calculation " на указанном сервере Redis.

Позже мы будем использовать переменную среды PREFIX для демонстрации функциональности многокластерной архитектуры.

Для справки: это пакеты, которые использует приложение.

  • body-parser: Позволяет нам анализировать наши HTTP-запросы.
  • cors: Позволяет использовать совместное использование ресурсов между источниками (Cross Origin Resource Sharing).
  • dotenv: Простой анализ переменных окружения
  • express: Простой веб-хостинг
  • ioredis: Клиентская библиотека для взаимодействия с базами данных Redis.
  • morgan: Предоставляет хорошо структурированный журнал.

Внешний интерфейс

Наш фронтенд также представляет собой приложение на 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. Желтые прямоугольники обозначают нашу установку Istio.

561db37c510944bd.png

Обратите внимание, что в кластере burst по-прежнему развернут сервис Redis, несмотря на отсутствие развертывания Redis в кластере. Нам необходимо наличие этого сервиса в кластере, чтобы Kubernetes DNS мог обрабатывать запрос, но когда запрос фактически поступает, Istio Proxy перенаправляет запрос к развертыванию Redis в primary кластере.

В финальной версии приложения будет запущено дополнительное развертывание в primary кластере под названием istiowatcher. Это позволит нам автоматически динамически перенаправлять трафик на burst , когда наш трафик превысит определенный порог.

8f6183bdfc3f813c.png

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 функцию DNS для разрешения имени результирующего сервиса.
  • Мы установили адрес для нашего REDIS_URL равным " redis-cache-service:6379 " и будем использовать встроенную в Kubernetes функцию DNS для разрешения результирующих IP-адресов.
  • Мы также настроили для контейнера проверки liveness и readiness , чтобы помочь Kubernetes понять, когда контейнер запущен и работает.

Напишите файл worker-service.yaml

Мы пишем определение сервиса Kubernetes в отдельном файле от определения развертывания, поскольку будем повторно использовать этот сервис в нескольких кластерах, но для каждого кластера будем создавать отдельное развертывание.

Вставьте следующее в worker-service.yaml

apiVersion: v1
kind: Service
metadata:
 name: worker-service
spec:
 type: ClusterIP
 selector:
   app: worker
 ports:
 - name: http
   port: 80
   targetPort: 8081

Напишите файл worker-primary.yaml

Это будет развертывание worker , который мы перенесем в основной кластер.

Вставьте следующий код в файл worker-primary.yaml .

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: worker-deployment
 labels:
   app: worker
spec:
 replicas: 1
 selector:
   matchLabels:
     app: worker
 template:
   metadata:
     labels:
       app: worker
       cluster-type: primary-cluster
   spec:
     containers:
     - name: worker
       image: gcr.io/istio-burst-workshop/worker
       imagePullPolicy: Always
       ports:
       - containerPort: 8081
       readinessProbe:
           initialDelaySeconds: 10
           httpGet:
             path: "/_healthz"
             port: 8081
             httpHeaders:
             - name: "Cookie"
               value: "istio_session-id=x-readiness-probe"
       livenessProbe:
         initialDelaySeconds: 10
         httpGet:
           path: "/"
           port: 8081
           httpHeaders:
           - name: "Cookie"
             value: "istio_session-id=x-liveness-probe"
       env:
       - name: PORT
         value: "8081"
       - name: REDIS_URL
         value: "redis-cache-service:6379"

Обратите внимание, что здесь мы следуем тому же принципу, предоставляя проверки liveness и readiness , а также указывая переменные среды PORT и REDIS_URL для использования нашим приложением.

Ещё один важный момент в этой конфигурации — отсутствие переменной среды PREFIX . Это означает, что результаты вычислений будут представлять собой необработанные хеши (без префикса).

Ключевым заключительным элементом этого развертывания является метка cluster-type: primary-cluster . Мы будем использовать ее позже при настройке маршрутизации трафика в Istio Multicluster.

Напишите файл redis.yaml

Обмен данными между нашим рабочим процессом и фронтендом осуществляется через канал Redis, поэтому нам необходимо развернуть приложение Redis в нашем кластере.

Вставьте следующее в redis.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: redis-cache
spec:
 template:
   metadata:
     labels:
       app: redis-cache
   spec:
     containers:
     - name: redis
       image: redis:alpine
       ports:
       - containerPort: 6379
       readinessProbe:
         periodSeconds: 5
         tcpSocket:
           port: 6379
       livenessProbe:
         periodSeconds: 5
         tcpSocket:
           port: 6379
       volumeMounts:
       - mountPath: /data
         name: redis-data
       resources:
         limits:
           memory: 256Mi
           cpu: 125m
         requests:
           cpu: 70m
           memory: 200Mi
     volumes:
     - name: redis-data
       emptyDir: {}

Это полустандартное развертывание приложения Redis. Оно создает контейнер на основе образа redis:alpine , открывает соответствующие порты и устанавливает разумные ограничения на использование ресурсов.

Напишите файл redis-service.yaml

Нам нужен сервис Kubernetes для взаимодействия с нашим приложением Redis.

Вставьте следующее в файл redis-service.yaml

apiVersion: v1
kind: Service
metadata:
 name: redis-cache-service
spec:
 type: ClusterIP
 selector:
   app: redis-cache
 ports:
 - port: 6379
   targetPort: 6379

Это предоставляет сервис redis-cache-service для доступа к нашему развертыванию Redis.

10. Разверните приложение

После того, как наши образы загружены в GCR, а манифесты Kubernetes написаны, настало подходящее время для развертывания нашего приложения и проверки его работы!

Выполните следующие команды для развертывания приложения.

  1. Убедитесь, что мы находимся в правильном кластере.
kubectx primary
  1. Развернуть кэш Redis
kubectl apply -f redis.yaml
  1. Развернуть службу Redis
kubectl apply -f redis-service.yaml
  1. Развернуть интерфейс
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

Вы заметите, что мы не использовали балансировщик нагрузки для доступа к нашему фронтенду. Это потому, что позже мы будем получать доступ к приложению через 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».

bdb5dc75f415be11.png

Вы должны увидеть интерфейс! А если вы введете число в поле "частота", то увидите, как начнут появляться хеши.

1caafaffab26897a.png

Поздравляем! Всё работает!

Нажмите Ctrl+C , чтобы остановить переадресацию порта.

11. Очистка развернутого приложения

Мы собираемся установить Istio на наш кластер, а затем повторно развернуть наше приложение, поэтому давайте сначала удалим наше текущее приложение.

Выполните следующие команды, чтобы удалить все только что созданные развертывания и службы.

  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 на основной кластер.

Получить Istio

Релизы Istio размещаются на GitHub. Следующие команды загрузят и распакуют версию istio 1.0.0.

  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 нам сначала необходимо создать пространство имен с именем 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 Traffic Management.

Создание конфигурационных файлов Istio Traffic Management

Istio работает аналогично Kubernetes, используя YAML-файлы для конфигурации. В этом смысле нам необходимо создать набор файлов, которые укажут Istio, как предоставлять доступ к нашему трафику и маршрутизировать его.

Создайте директорию с именем istio-manifests и перейдите в неё.

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

Напишите файл frontend-gateway.yaml

Этот файл позволит настроить наш кластер Kubernetes аналогично балансировщику нагрузки GKE и направлять весь входящий трафик на наш фронтенд-сервис.

Создайте файл с именем 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.
kubectl apply -f redis-virtualservice.yaml
  1. Воспользуйтесь нашей услугой виртуального трудоустройства.
kubectl apply -f worker-virtualservice.yaml

Развертывание приложения

  1. Вернитесь обратно в наш каталог kubernetes
cd ${proj}/kubernetes
  1. Развернуть кэш Redis
kubectl apply -f redis.yaml
  1. Развернуть службу Redis
kubectl apply -f redis-service.yaml
  1. Развернуть интерфейс
kubectl apply -f frontend.yaml
  1. Развернуть рабочего
kubectl apply -f worker-primary.yaml
  1. Служба развертывания рабочих мест
kubectl apply -f worker-service.yaml

Проверять

На данный момент мы повторно развернули наше приложение в кластере с использованием Istio и политик управления трафиком.

Давайте подождем, пока все наши рабочие нагрузки не будут запущены.

Как только все устройства подключятся к сети, получите доступ к IngressGateway, который мы настроили в frontend-ingressgateway.yaml

$ kubectl -n istio-system get svc istio-ingressgateway
NAME                   TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                                                                                                     AGE
istio-ingressgateway   LoadBalancer   10.36.3.112   35.199.158.10   80:31380/TCP,

Перейдите по адресу <EXTERNAL-IP> через веб-браузер или выполните команду curl, и вы увидите интерфейс!

$ curl 35.199.158.10
<!doctype html>
<html>

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

14. Установите Istio на кластер "burst".

Мы потратили много времени на настройку и развертывание на нашем primary кластере, но нам предстоит развернуть систему еще на одном кластере!

В этом разделе нам потребуется получить переменные конфигурации для обоих наших кластеров, поэтому внимательно следите за тем, к какому кластеру мы обращаемся при выполнении каждой команды.

Создайте удаленный манифест Istio.

Как и при развертывании Istio на primary кластере, мы будем использовать Helm для создания шаблона развертывания Istio на удаленном кластере burst . Однако прежде чем это сделать, нам необходимо получить некоторую информацию о нашем primary кластере.

Соберите основную информацию о кластере.

Переключиться на primary кластер

kubectx primary

Следующие команды получают IP-адреса различных модулей в основном кластере. Эти адреса используются Istio Remote для обратной связи с основным кластером.

export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')

Создать удаленный шаблон

Теперь мы воспользуемся helm для создания файла с именем istio-remote-burst.yaml , который затем сможем развернуть в кластере burst .

Перейдите в корневую папку проекта.

cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \
--name istio-remote \
--set global.remotePilotAddress=${PILOT_POD_IP} \
--set global.remotePolicyAddress=${POLICY_POD_IP} \
--set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set global.proxy.envoyStatsd.enabled=true \
--set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \
--set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml

Установите Istio Remote на кластер Burst.

Для установки Istio на нашем кластере burst необходимо выполнить те же шаги, что и при установке на primary кластере, но вместо этого использовать файл istio-remote-burst.yaml .

Измените kubecontext на burst

kubectx burst

Создайте пространство имен istio-system.

kubectl create ns istio-system

Примените файл istio-burst.yaml

kubectl apply -f istio-remote-burst.yaml

Пространство имен меток по умолчанию

Ещё раз, нам нужно указать метку для пространства имён default , чтобы прокси-объект мог быть внедрен автоматически.

kubectl label namespace default istio-injection=enabled

Поздравляем! На данный момент мы настроили Istio Remote на кластере burst . Однако пока кластеры по-прежнему не могут взаимодействовать. Нам необходимо сгенерировать файл kubeconfig для кластера burst , который мы сможем развернуть на primary кластере, чтобы связать их между собой.

Создайте файл kubeconfig для кластера "burst".

Переключитесь на кластер с пакетной передачей данных.

kubectx burst

Настройка среды

Нам необходимо собрать некоторую информацию о кластере, чтобы создать для него файл kubeconfig .

  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
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

Пометьте секретный ключ, чтобы Istio знал, как использовать его для аутентификации в нескольких кластерах.

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

Поздравляем! Оба кластера аутентифицированы и взаимодействуют друг с другом через Istio Multicluster. Давайте развернем наше приложение в кросс-кластерном режиме.

15. Развертывание межкластерного приложения

Создание развертываний

Перейдите в каталог 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

Мы будем использовать эту метку позже, при обновлении нашего виртуального сервиса.

Изменить службы 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 в кластере Burst.

Измените kubeconfig на burst

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

Перейдите к primary kubeconfig.

kubectx primary

Затем выполните развертывание.

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

Проверьте, работает ли это.

Чтобы убедиться в его работоспособности, перейдите к точке доступа Istio Ingress и обратите внимание, что примерно 50% хешей имеют префикс "burst-".

78fb6e235e9f4a07.png

Это значит, что мы успешно взаимодействуем между кластерами! Попробуйте изменить веса для разных сервисов и применить файл worker-virtualservice.yaml . Это отличный способ сбалансировать трафик между кластерами, но что, если мы сможем делать это автоматически?

16. Использование метрик Prometheus

Введение в «Прометей»

Prometheus — это инструментарий с открытым исходным кодом для мониторинга и оповещения о системах, первоначально разработанный в SoundCloud. Он поддерживает многомерную модель данных с временными рядами, идентифицируемыми по имени метрики и парам ключ/значение.

Для справки, вот схема архитектуры Prometheus:

601e1155a825e0c2.png

При развертывании Istio совместно с Prometheus, система автоматически отправляет различные метрики на сервер Prometheus. Мы можем использовать эти метрики для оперативного управления кластерами.

Изучение показателей Prometheus

Для начала нам необходимо предоставить доступ к развертыванию Prometheus.

Перейдите на вкладку «Рабочие нагрузки» в GKE и найдите рабочую нагрузку «Prometheus».

b4a7a3cd67db05b3.png

После просмотра сведений о развертывании перейдите в раздел Действия -> Показать.

c04a482e55bdfd41.png

Выберите переадресацию на порт 9090 и введите "Балансировщик нагрузки".

d5af3ba22a7a6ebb.png

И выберите "Показать"

Это создаст службу на общедоступном IP-адресе, которую мы сможем использовать для анализа метрик Prometheus.

Дождитесь, пока конечная точка станет работоспособной, и как только это произойдет, щелкните по IP-адресу рядом с надписью «Внешние конечные точки». b1e40ad90851da29.png

Теперь вы должны видеть пользовательский интерфейс Prometheus.

ed273552270337ec.png

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]

И это дает нам гораздо более удобный для работы набор данных.

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.

Наш заключительный запрос к 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 для получения метрики.

Мы можем запросить их API, используя наш собственный запрос, выполнив HTTP GET-запрос следующим образом. Замените <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 перейдите в верхнюю часть только что созданного сервиса и нажмите «Удалить».

d58cb51b4c922751.png

Следующие шаги:

Разработав способ отслеживания движения трафика в кластере и его скорости, следующим шагом станет написание небольшого исполняемого файла, который будет периодически запрашивать 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 , когда количество запросов в секунду от frontend к worker превысит 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

Собрать и отправить проект isiowatcher

Выполните следующую команду, чтобы отправить текущий каталог в Google Cloud Build (GCB), который соберет образ и пометит его в GCR.

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

Разверните IstioWatcher

Перейдите в наш каталог kubernetes

cd ${proj}/kubernetes/

Создайте файл развертывания: istiowatcher.yaml

Создайте файл с именем istiowatcher.yaml и вставьте в него следующий код (замените <ваш-идентификатор-проекта>).

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. Что дальше?

Уборка

Если вы используете временную учетную запись, предоставленную для этого семинара, вам не нужно ничего удалять.

В GCR можно удалить кластеры Kubernetes, правило брандмауэра и образы.

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

Дальнейшие шаги