Як запустити Istio, використовуючи Kubernetes в production. Частина 1

Що таке Істіо? Це так званий Service mesh, технологія яка додає рівень абстракції над мережею. Ми перехоплюємо весь або частину трафіку в кластері та виконуємо певний набір операцій із ним. Який саме? Наприклад, робимо розумний роутинг, або реалізуємо підхід circuit breaker, можемо організовувати canary deployment, частково перемикаючи трафік на нову версію сервісу, а можемо обмежувати зовнішні взаємодії і контролювати всі походи з кластера в зовнішню мережу. Є можливість задавати policy правила контролю походів між різними мікросервісами. Нарешті, ми можемо отримати всю карту взаємодії через мережу і зробити уніфікований збір метрик повністю прозоро для додатків.

Про механізм роботи можна прочитати в офіційної документації. Istio - це дійсно потужний інструмент, який дозволяє вирішити безліч завдань та проблем. У цій статті я хотів би відповісти на основні питання, які зазвичай виникають на початку роботи з Istio. Це допоможе вам розібратися з ним швидше.

Як запустити Istio, використовуючи Kubernetes в production. Частина 1

Принцип роботи

Istio і двох основних зон — control plane і data plane. Control plane містить у собі основні компоненти, які забезпечують коректну роботу решти. У поточній версії (1.0) control plane має три основні компоненти: Pilot, Mixer, Citadel. Citadel ми не будемо розглядати, він потрібен для генерації сертифікатів для забезпечення роботи mutual TLS між сервісами. Давайте подивимося докладніше на пристрій та призначення Pilot та Mixer.

Як запустити Istio, використовуючи Kubernetes в production. Частина 1

Pilot - це головний керуючий компонент, який поширює всю інформацію про те, що у нас є в кластері - сервіси, їх endpoint'и та routing правила (наприклад, правила для Canary deployment або правила circuit breaker).

Mixer - опціональний компонент control plane, який надає можливість збору метрик, логів та будь-якої інформації про мережеву взаємодію. Також він стежить за дотриманням Policy правил та дотриманням rate limit'ів.

Data plane реалізується за допомогою sidecar контейнерів-проксі. За замовчуванням використовується потужний проксі-сервер envoy. Він може бути замінений іншою реалізацією, наприклад nginx (nginmesh).

Для того, щоб Istio працював повністю прозоро для додатків, є система автоматичного inject'інгу. Остання реалізація підходить для версій Kubernetes 1.9+ (mutational admission webhook). Для Kubernetes версій 1.7, 1.8 можна використовувати Initializer.

Sidecar контейнери з'єднуються з Pilot за протоколом GRPC, що дозволяє оптимізувати модель пушингу змін, які у кластері. GRPC почав використовуватися в Envoy починаючи з версії 1.6, в Istio він використовується з версії 0.8 і є pilot-agent — обгорткою на golang над envoy, яка конфігурує параметри запуску.

Pilot і Mixer є повністю stateless компонентами, весь стан тримають у пам'яті. Конфігурація для них визначається як Kubernetes Custom Resources, які зберігаються в etcd.
Istio-agent отримує адресу Pilot та відкриває GRPC stream до нього.

Як я вже сказав, Istio реалізує всю функціональність повністю прозоро додатків. Давайте розберемося як. Алгоритм такий:

  1. Деплоймо нову версію сервісу.
  2. Залежно від підходу injecting'а sidecar контейнера додаються istio-init контейнер та istio-agent контейнер (envoy) на етапі застосування конфігурації, або вони можуть бути вже вручну вставлені в опис Pod сутності Kubernetes.
  3. istio-init контейнер являє собою скрипт, який застосовує правила iptables для подавання. Є два варіанти для налаштування загортання трафіку в istio-agent контейнер: використовувати redirect правила iptables, або TPROXY. На момент написання статті за промовчанням використовується підхід із реdirect правилами. У istio-init є можливість налаштувати який саме трафік потрібно перехоплювати та спрямовувати в istio-agent. Наприклад, щоб перехоплювати весь вхідний і весь вихідний трафік, потрібно встановити параметри -i и -b на значення *. Можна вказати конкретні порти, які потрібно перехоплювати. Для того, щоб не перехоплювати певну підсітку, можна вказати її за допомогою прапора -x.
  4. Після виконання init контейнерів, запускаються основні, та включаючи pilot-agent (envoy). Він підключається до вже розгорнутого Pilot по GRPC та отримує інформацію про всі існуючі сервіси та routing політиків у кластері. За отриманими даними, він конфігурує cluster'и і прописує їм безпосередньо endpoint'и наших додатків у кластері Kubernetes. Також необхідно відзначити важливий момент: envoy динамічно налаштовує listeners (пари IP, port), які починає слухати. Тому, коли запити входять у під, перенаправляються за допомогою redirect iptables правил у sidecar, envoy вже успішно може обробляти ці з'єднання і розуміти, куди потрібно далі проксувати трафік. Також на цьому етапі відбувається відправлення інформації в Mixer, який ми розглянемо пізніше, та відправлення tracing span'ів.

У результаті ми отримуємо цілу мережу envoy проксі-серверів, які ми можемо налаштовувати з однієї точки (Pilot). Всі inbound та outbound запити проходять через envoy. Причому перехоплюється лише TCP трафік. Це означає, що Kubernetes service IP резолвується за допомогою kube-dns UDP без зміни. Потім вже після резолву відбувається перехоплення вихідного запиту та обробка envoy'ем, який вже вирішує, на який endpoint потрібно відправити запит (або не відправити, у разі політик доступу або спрацювання circuit breaker алгоритму).

З Pilot розібралися, тепер потрібно зрозуміти як працює Mixer і навіщо він потрібний. Прочитати офіційну документацію щодо нього можна тут.

Mixer у поточному вигляді являє собою два компоненти: istio-telemetry, istio-policy (до версії 0.8 це був один компонент istio-mixer). І той, і інший являють собою mixer, кожен з яких відповідають за своє завдання. Istio telemetry приймає GRPC від sidecar контейнерів Report інформацію про те, хто куди йде і з якими параметрами. Istio-policy приймає Check запити для перевірки задоволення Policy правил. Poilicy check проводяться, звичайно, не на кожен запит, а кешуються на клієнті (sidecar) на певний час. Report check'і відправляються batch запитами. Як налаштовувати і які саме параметри потрібно відсилати подивимося трохи згодом.

Mixer передбачається як високодоступний компонент, який забезпечує безперебійну роботу зі збирання та обробки телеметрії даних. Система виходить у результаті як багаторівневий буфер. Спочатку дані буферизуються на стороні sidecar контейнерів, потім на стороні mixer і потім відправляються в так звані mixer backend'и. У результаті, якщо якийсь із компонентів системи відмовляє, буфер росте і після відновлення системи флашиться. Mixer backend'и являють собою кінцеві точки відправки даних про телеметрію: statsd, newrelic і тд. Можна написати свій backend, це досить просто, і ми подивимося, як це зробити.

Як запустити Istio, використовуючи Kubernetes в production. Частина 1

Якщо підсумувати, схема роботи з istio-telemetry така.

  1. Сервіс 1 надсилає запит у сервіс 2.
  2. При виході з сервісу 1 запит загортається в його ж sidecar.
  3. Sidecar envoy стежить за тим, як проходить запит у сервіс 2 та готує необхідну інформацію.
  4. Потім надсилає її в istio-telemetry за допомогою Report запиту.
  5. Istio-telemetry визначає, чи потрібно відправляти цей Report у backend'и, у які саме та які дані потрібно відправляти.
  6. Istio-telemetry відправляє Report дані у backend якщо це необхідно.

Тепер подивимося, як розгорнути в системі Istio, що складається лише з основних компонентів (Pilot та sidecar envoy).

Спочатку подивимося на основну конфігурацію (mesh), яку читає Pilot:

apiVersion: v1
kind: ConfigMap
metadata:
  name: istio
  namespace: istio-system
  labels:
    app: istio
    service: istio
data:
  mesh: |-

    # пока что не включаем отправку tracing информации (pilot настроит envoy’и таким образом, что отправка не будет происходить)
    enableTracing: false

    # пока что не указываем mixer endpoint’ы, чтобы sidecar контейнеры не отправляли информацию туда
    #mixerCheckServer: istio-policy.istio-system:15004
    #mixerReportServer: istio-telemetry.istio-system:15004

    # ставим временной промежуток, с которым будет envoy переспрашивать Pilot (это для старой версии envoy proxy)
    rdsRefreshDelay: 5s

    # default конфигурация для envoy sidecar
    defaultConfig:
      # аналогично как rdsRefreshDelay
      discoveryRefreshDelay: 5s

      # оставляем по умолчанию (путь к конфигурации и бинарю envoy)
      configPath: "/etc/istio/proxy"
      binaryPath: "/usr/local/bin/envoy"

      # дефолтное имя запущенного sidecar контейнера (используется, например, в именах сервиса при отправке tracing span’ов)
      serviceCluster: istio-proxy

      # время, которое будет ждать envoy до того, как он принудительно завершит все установленные соединения
      drainDuration: 45s
      parentShutdownDuration: 1m0s

      # по умолчанию используются REDIRECT правила iptables. Можно изменить на TPROXY.
      #interceptionMode: REDIRECT

      # Порт, на котором будет запущена admin панель каждого sidecar контейнера (envoy)
      proxyAdminPort: 15000

      # адрес, по которому будут отправляться trace’ы по zipkin протоколу (в начале мы отключили саму отправку, поэтому это поле сейчас не будет использоваться)
      zipkinAddress: tracing-collector.tracing:9411

      # statsd адрес для отправки метрик envoy контейнеров (отключаем)
      # statsdUdpAddress: aggregator:8126

      # выключаем поддержку опции Mutual TLS
      controlPlaneAuthPolicy: NONE

      # адрес, на котором будет слушать istio-pilot для того, чтобы сообщать информацию о service discovery всем sidecar контейнерам
      discoveryAddress: istio-pilot.istio-system:15007

Всі основні компоненти управління (control plane) розташуємо в namespace istio-system в Kubernetes.

Мінімально нам потрібно розгорнути лише Pilot. Для цього скористаємося такою конфігурацією.

І налаштуємо вручну injecting sidecar контейнера.

Init container:

initContainers:
 - name: istio-init
   args:
   - -p
   - "15001"
   - -u
   - "1337"
   - -m
   - REDIRECT
   - -i
   - '*'
   - -b
   - '*'
   - -d
   - ""
   image: istio/proxy_init:1.0.0
   imagePullPolicy: IfNotPresent
   resources:
     limits:
       memory: 128Mi
   securityContext:
     capabilities:
       add:
       - NET_ADMIN

І sidecar:

       name: istio-proxy
       args:
         - "bash"
         - "-c"
         - |
           exec /usr/local/bin/pilot-agent proxy sidecar 
           --configPath 
           /etc/istio/proxy 
           --binaryPath 
           /usr/local/bin/envoy 
           --serviceCluster 
           service-name 
           --drainDuration 
           45s 
           --parentShutdownDuration 
           1m0s 
           --discoveryAddress 
           istio-pilot.istio-system:15007 
           --discoveryRefreshDelay 
           1s 
           --connectTimeout 
           10s 
           --proxyAdminPort 
           "15000" 
           --controlPlaneAuthPolicy 
           NONE
         env:
         - name: POD_NAME
           valueFrom:
             fieldRef:
               fieldPath: metadata.name
         - name: POD_NAMESPACE
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
         - name: INSTANCE_IP
           valueFrom:
             fieldRef:
               fieldPath: status.podIP
         - name: ISTIO_META_POD_NAME
           valueFrom:
             fieldRef:
               fieldPath: metadata.name
         - name: ISTIO_META_INTERCEPTION_MODE
           value: REDIRECT
         image: istio/proxyv2:1.0.0
         imagePullPolicy: IfNotPresent
         resources:
           requests:
             cpu: 100m
             memory: 128Mi
           limits:
             memory: 2048Mi
         securityContext:
           privileged: false
           readOnlyRootFilesystem: true
           runAsUser: 1337
         volumeMounts:
         - mountPath: /etc/istio/proxy
           name: istio-envoy

Для того, щоб все успішно запустилося, потрібно завести ServiceAccount, ClusterRole, ClusterRoleBinding, CRD для Pilot, опис яких можна знайти тут.

У результаті сервіс, в який ми inject'ім sidecar з envoy, повинен успішно запуститися, отримати весь discovery з пілота та обробляти запити.

Важливо розуміти, що всі компоненти control plane є stateless додатками і можуть бути без проблем горизонтально масштабовані. Усі дані лежать в etcd як кастомних описів ресурсів Kubernetes.

Також у Istio (поки що експериментально) є можливість запуску поза кластером та можливість дивитися та нишпорити service discovery між кількома Kubernetes кластерами. Докладніше про це можна почитати тут.

При мультикластерній установці слід враховувати такі обмеження:

  1. Pod CIDR та Service CIDR повинні бути унікальними по всіх кластерах і не повинні перетинатися.
  2. Всі Pod CIDR повинні бути доступні від будь-якого Pod CIDR між кластерами.
  3. Всі сервери Kubernetes API повинні бути доступні один для одного.

Це початкові відомості, які допоможуть вам розпочати роботу з Istio. Однак є ще безліч підводних каменів. Наприклад, особливості роутингу зовнішнього трафіку (назовні кластера), підходи до налагодження sidecar'ів, профільування, налаштування mixer та написання кастомного mixer backend, налаштування tracing механізму та його робота за допомогою envoy.
Все це ми розглянемо у наступних публікаціях. Ставте ваші запитання, постараюся їх висвітлити.

Джерело: habr.com

Додати коментар або відгук