Circuit Breaker
Для выявления проблемных эндпоинтов используются настройки outlierDetection
в кастомном ресурсе DestinationRule.
Более подробно алгоритм Outlier Detection описан в документации Envoy.
Пример:
1apiVersion: networking.istio.io/v1beta1
2kind: DestinationRule
3metadata:
4 name: reviews-cb-policy
5spec:
6 host: reviews.prod.svc.cluster.local
7 trafficPolicy:
8 connectionPool:
9 tcp:
10 maxConnections: 100 # Максимальное число коннектов в сторону host, суммарно для всех эндпоинтов.
11 http:
12 maxRequestsPerConnection: 10 # Каждые 10 запросов коннект будет пересоздаваться.
13 outlierDetection:
14 consecutive5xxErrors: 7 # Допустимо 7 ошибок (включая пятисотые, TCP-таймауты и HTTP-таймауты)
15 interval: 5m # в течение пяти минут,
16 baseEjectionTime: 15m # после которых эндпоинт будет исключен из балансировки на 15 минут.
А также для настройки HTTP-таймаутов используется ресурс VirtualService. Эти таймауты также учитываются при подсчете статистики ошибок на эндпоинтах.
Пример:
1apiVersion: networking.istio.io/v1beta1
2kind: VirtualService
3metadata:
4 name: my-productpage-rule
5 namespace: myns
6spec:
7 hosts:
8 - productpage
9 http:
10 - timeout: 5s
11 route:
12 - destination:
13 host: productpage
Балансировка gRPC
Важно! Чтобы балансировка gRPC-сервисов заработала автоматически, присвойте name с префиксом или значением grpc
для порта в соответствующем Service.
Locality Failover
При необходимости ознакомьтесь с основной документацией.
Istio позволяет настроить приоритетный географический фейловер между эндпоинтами. Для определения зоны Istio использует лейблы узлов с соответствующей иерархией:
topology.istio.io/subzone
;topology.kubernetes.io/zone
;topology.kubernetes.io/region
.
Это полезно для межкластерного фейловера при использовании совместно с мультикластером.
Важно! Для включения Locality Failover используется ресурс DestinationRule, в котором также необходимо настроить
outlierDetection
.
Пример:
1apiVersion: networking.istio.io/v1beta1
2kind: DestinationRule
3metadata:
4 name: helloworld
5spec:
6 host: helloworld
7 trafficPolicy:
8 loadBalancer:
9 localityLbSetting:
10 enabled: true # Включили LF.
11 outlierDetection: # outlierDetection включить обязательно.
12 consecutive5xxErrors: 1
13 interval: 1s
14 baseEjectionTime: 1m
Retry
С помощью ресурса VirtualService можно настроить Retry для запросов.
Внимание! По умолчанию при возникновении ошибок все запросы (включая POST-запросы) выполняются повторно до трех раз.
Пример:
1apiVersion: networking.istio.io/v1beta1
2kind: VirtualService
3metadata:
4 name: ratings-route
5spec:
6 hosts:
7 - ratings.prod.svc.cluster.local
8 http:
9 - route:
10 - destination:
11 host: ratings.prod.svc.cluster.local
12 retries:
13 attempts: 3
14 perTryTimeout: 2s
15 retryOn: gateway-error,connect-failure,refused-stream
Canary
Важно! Istio отвечает лишь за гибкую маршрутизацию запросов, которая опирается на спецзаголовки запросов (например, cookie) или просто на случайность. За настройку этой маршрутизации и «переключение» между канареечными версиями отвечает CI/CD-система.
Подразумевается, что в одном пространстве имён развёрнуты два Deployment с разными версиями приложения. У подов разных версий разные лейблы (version: v1
и version: v2
).
Требуется настроить два кастомных ресурса:
- DestinationRule с описанием, как идентифицировать разные версии вашего приложения (subset’ы);
- VirtualService с описанием, как распределять трафик между разными версиями приложения.
Пример:
1apiVersion: networking.istio.io/v1beta1
2kind: DestinationRule
3metadata:
4 name: productpage-canary
5spec:
6 host: productpage
7 # subset'ы доступны только при обращении к хосту через VirtualService из пода под управлением Istio.
8 # Эти subset'ы должны быть указаны в маршрутах.
9 subsets:
10 - name: v1
11 labels:
12 version: v1
13 - name: v2
14 labels:
15 version: v2
Распределение по наличию cookie
1apiVersion: networking.istio.io/v1beta1
2kind: VirtualService
3metadata:
4 name: productpage-canary
5spec:
6 hosts:
7 - productpage
8 http:
9 - match:
10 - headers:
11 cookie:
12 regex: "^(.*;?)?(canary=yes)(;.*)?"
13 route:
14 - destination:
15 host: productpage
16 subset: v2 # Ссылка на subset из DestinationRule.
17 - route:
18 - destination:
19 host: productpage
20 subset: v1
Распределение по вероятности
1apiVersion: networking.istio.io/v1beta1
2kind: VirtualService
3metadata:
4 name: productpage-canary
5spec:
6 hosts:
7 - productpage
8 http:
9 - route:
10 - destination:
11 host: productpage
12 subset: v1 # Ссылка на subset из DestinationRule.
13 weight: 90 # Процент трафика, который получат поды с лейблом version: v1.
14 - route:
15 - destination:
16 host: productpage
17 subset: v2
18 weight: 10
Ingress для публикации приложений
Istio Ingress Gateway
Пример:
1apiVersion: deckhouse.io/v1alpha1
2kind: IngressIstioController
3metadata:
4 name: main
5spec:
6 # ingressGatewayClass содержит значение селектора меток, используемое при создании ресурса Gateway.
7 ingressGatewayClass: istio-hp
8 inlet: HostPort
9 hostPort:
10 httpPort: 80
11 httpsPort: 443
12 nodeSelector:
13 node-role/frontend: ''
14 tolerations:
15 - effect: NoExecute
16 key: dedicated.deckhouse.io
17 operator: Equal
18 value: frontend
19 resourcesRequests:
20 mode: VPA
1apiVersion: v1
2kind: Secret
3metadata:
4 name: app-tls-secert
5 namespace: d8-ingress-istio # Обратите внимание, пространство имён не является app-ns.
6type: kubernetes.io/tls
7data:
8 tls.crt: |
9 <tls.crt data>
10 tls.key: |
11 <tls.key data>
1apiVersion: networking.istio.io/v1beta1
2kind: Gateway
3metadata:
4 name: gateway-app
5 namespace: app-ns
6spec:
7 selector:
8 # Селектор меток для использования Istio Ingress Gateway main-hp.
9 istio.deckhouse.io/ingress-gateway-class: istio-hp
10 servers:
11 - port:
12 # Стандартный шаблон для использования протокола HTTP.
13 number: 80
14 name: http
15 protocol: HTTP
16 hosts:
17 - app.example.com
18 - port:
19 # Стандартный шаблон для использования протокола HTTPS.
20 number: 443
21 name: https
22 protocol: HTTPS
23 tls:
24 mode: SIMPLE
25 # Ресурс Secret с сертификатом и ключом, который должен быть создан в пространстве имён d8-ingress-istio.
26 # Поддерживаемые форматы ресурсов Secret можно посмотреть по ссылке https://istio.io/latest/docs/tasks/traffic-management/ingress/secure-ingress/#key-formats.
27 credentialName: app-tls-secrets
28 hosts:
29 - app.example.com
1apiVersion: networking.istio.io/v1alpha3
2kind: VirtualService
3metadata:
4 name: vs-app
5 namespace: app-ns
6spec:
7 gateways:
8 - gateway-app
9 hosts:
10 - app.example.com
11 http:
12 - route:
13 - destination:
14 host: app-svc
NGINX Ingress
Для работы с NGINX Ingress требуется подготовить:
- Ingress-контроллер, добавив к нему sidecar от Istio. В нашем случае включить параметр
enableIstioSidecar
в кастомном ресурсе IngressNginxController модуля ingress-nginx. - Ingress-ресурс, который ссылается на Service. Обязательные аннотации для Ingress-ресурса:
nginx.ingress.kubernetes.io/service-upstream: "true"
— с этой аннотацией Ingress-контроллер будет отправлять запросы на ClusterIP сервиса (из диапазона Service CIDR) вместо того, чтобы слать их напрямую в поды приложения. Sidecar-контейнерistio-proxy
перехватывает трафик только в сторону диапазона Service CIDR, остальные запросы отправляются напрямую;nginx.ingress.kubernetes.io/upstream-vhost: myservice.myns.svc
— с данной аннотацией sidecar сможет идентифицировать прикладной сервис, для которого предназначен запрос.
Примеры:
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4 name: productpage
5 namespace: bookinfo
6 annotations:
7 # Просим nginx проксировать трафик на ClusterIP вместо собственных IP подов.
8 nginx.ingress.kubernetes.io/service-upstream: "true"
9 # В Istio вся маршрутизация осуществляется на основе `Host:` заголовка запросов.
10 # Чтобы не сообщать Istio о существовании внешнего домена `productpage.example.com`,
11 # мы просто используем внутренний домен, о котором Istio осведомлен.
12 nginx.ingress.kubernetes.io/upstream-vhost: productpage.bookinfo.svc
13spec:
14 rules:
15 - host: productpage.example.com
16 http:
17 paths:
18 - path: /
19 pathType: Prefix
20 backend:
21 service:
22 name: productpage
23 port:
24 number: 9080
1apiVersion: v1
2kind: Service
3metadata:
4 name: productpage
5 namespace: bookinfo
6spec:
7 ports:
8 - name: http
9 port: 9080
10 selector:
11 app: productpage
12 type: ClusterIP
Примеры настройки авторизации
Алгоритм принятия решения
Важно! Как только для приложения создается AuthorizationPolicy
, начинает работать следующий алгоритм принятия решения о судьбе запроса:
- Если запрос попадает под политику DENY — запретить запрос.
- Если для данного приложения нет политик ALLOW — разрешить запрос.
- Если запрос попадает под политику ALLOW — разрешить запрос.
- Все остальные запросы — запретить.
Иными словами, если вы явно что-то запретили, работает только ваш запрет. Если же вы что-то явно разрешили, теперь разрешены только явно одобренные запросы (запреты никуда не исчезают и имеют приоритет).
Важно! Для работы политик, основанных на высокоуровневых параметрах, таких как пространства имён или principal, необходимо, чтобы все вовлеченные сервисы работали под управлением Istio. Также между приложениями должен быть организован Mutual TLS.
Примеры:
-
Запретим POST-запросы для приложения myapp. Отныне, так как для приложения появилась политика, согласно алгоритму выше будут запрещены только POST-запросы к приложению.
1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: deny-post-requests 5 namespace: foo 6spec: 7 selector: 8 matchLabels: 9 app: myapp 10 action: DENY 11 rules: 12 - to: 13 - operation: 14 methods: ["POST"]
-
Здесь для приложения создана политика ALLOW. При ней будут разрешены только запросы из NS
bar
, остальные запрещены.1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: deny-all 5 namespace: foo 6spec: 7 selector: 8 matchLabels: 9 app: myapp 10 action: ALLOW # default, можно не указывать. 11 rules: 12 - from: 13 - source: 14 namespaces: ["bar"]
-
Здесь для приложения создана политика ALLOW. При этом она не имеет ни одного правила, и поэтому ни один запрос под нее не попадет, но она таки есть. Поэтому, согласно алгоритму, раз что-то разрешено, то все остальное запрещено. В данном случае все остальное — это вообще все запросы.
1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: deny-all 5 namespace: foo 6spec: 7 selector: 8 matchLabels: 9 app: myapp 10 action: ALLOW # default, можно не указывать. 11 rules: []
-
Здесь для приложения созданы политика ALLOW (это default) и одно пустое правило. Под это правило попадает любой запрос и автоматически получает добро.
1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: allow-all 5 namespace: foo 6spec: 7 selector: 8 matchLabels: 9 app: myapp 10 rules: 11 - {}
Запретить все действия в рамках пространства имён foo
Два способа:
-
Запретить явно. Здесь мы создаем политику DENY с единственным универсальным фильтром
{}
, под который попадают все запросы:1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: deny-all 5 namespace: foo 6spec: 7 action: DENY 8 rules: 9 - {}
-
Неявно. Здесь мы создаем политику ALLOW (по умолчанию), но не создаем ни одного фильтра, так что ни один запрос под нее не попадет и будет автоматически запрещен.
1apiVersion: security.istio.io/v1beta1 2kind: AuthorizationPolicy 3metadata: 4 name: deny-all 5 namespace: foo 6spec: {}
Запретить доступ только из пространства имён foo
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: deny-from-ns-foo
5 namespace: myns
6spec:
7 action: DENY
8 rules:
9 - from:
10 - source:
11 namespaces: ["foo"]
Разрешить запросы только в рамках нашего пространства имён foo
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-intra-namespace-only
5 namespace: foo
6spec:
7 action: ALLOW
8 rules:
9 - from:
10 - source:
11 namespaces: ["foo"]
Разрешить из любого места в нашем кластере
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-all-from-my-cluster
5 namespace: myns
6spec:
7 action: ALLOW
8 rules:
9 - from:
10 - source:
11 principals: ["mycluster.local/*"]
Разрешить любые запросы только кластеров foo или bar
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-all-from-foo-or-bar-clusters-to-ns-baz
5 namespace: baz
6spec:
7 action: ALLOW
8 rules:
9 - from:
10 - source:
11 principals: ["foo.local/*", "bar.local/*"]
Разрешить любые запросы только кластеров foo или bar, при этом из пространства имён baz
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-all-from-foo-or-bar-clusters-to-ns-baz
5 namespace: baz
6spec:
7 action: ALLOW
8 rules:
9 - from:
10 - source: # Правила ниже логически перемножаются.
11 namespaces: ["baz"]
12 principals: ["foo.local/*", "bar.local/*"]
Разрешить из любого кластера (по mTLS)
Важно! Если есть запрещающие правила, у них будет приоритет. Смотри алгоритм.
Пример:
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-all-from-any-cluster-with-mtls
5 namespace: myns
6spec:
7 action: ALLOW
8 rules:
9 - from:
10 - source:
11 principals: ["*"] # To set mTLS mandatory.
Разрешить вообще откуда угодно (в том числе без mTLS)
1apiVersion: security.istio.io/v1beta1
2kind: AuthorizationPolicy
3metadata:
4 name: allow-all-from-any
5 namespace: myns
6spec:
7 action: ALLOW
8 rules: [{}]
Устройство федерации из двух кластеров с помощью кастомного ресурса IstioFederation
Доступно в редакциях Enterprise Edition и Certified Security Edition Pro (1.67).
Cluster A:
1apiVersion: deckhouse.io/v1alpha1
2kind: IstioFederation
3metadata:
4 name: cluster-b
5spec:
6 metadataEndpoint: https://istio.k8s-b.example.com/metadata/
7 trustDomain: cluster-b.local
Cluster B:
1apiVersion: deckhouse.io/v1alpha1
2kind: IstioFederation
3metadata:
4 name: cluster-a
5spec:
6 metadataEndpoint: https://istio.k8s-a.example.com/metadata/
7 trustDomain: cluster-a.local
Устройство мультикластера из двух кластеров с помощью ресурса IstioMulticluster
Доступно только в редакции Enterprise Edition.
Cluster A:
1apiVersion: deckhouse.io/v1alpha1
2kind: IstioMulticluster
3metadata:
4 name: cluster-b
5spec:
6 metadataEndpoint: https://istio.k8s-b.example.com/metadata/
Cluster B:
1apiVersion: deckhouse.io/v1alpha1
2kind: IstioMulticluster
3metadata:
4 name: cluster-a
5spec:
6 metadataEndpoint: https://istio.k8s-a.example.com/metadata/
Управление поведением data plane
Предотвратить завершение работы istio-proxy до завершения соединений основного приложения
По умолчанию в процессе остановки пода все контейнеры, включая istio-proxy, получают сигнал SIGTERM одновременно. Но некоторым приложениям для правильного завершения работы необходимо время и иногда дополнительная сетевая активность. Это невозможно, если istio-proxy завершился раньше.
Решение — добавить в istio-proxy preStop-хук для оценки активности прикладных контейнеров, а единственный доступный метод — это выявление сетевых сокетов приложения, и если таковых нет, тогда можно останавливать контейнер.
Аннотация ниже добавляет описанный выше preStop-хук в контейнер istio-proxy прикладного пода:
1annotations:
2 inject.istio.io/templates: "sidecar,d8-hold-istio-proxy-termination-until-application-stops"
Ограничения режима перенаправления прикладного трафика CNIPlugin
В отличие от режима InitContainer
, настройка перенаправления осуществляется в момент создании пода, а не в момент срабатывания init-контейнера istio-init
. Это значит, что прикладные init-контейнеры не смогут взаимодействовать с остальными сервисами так как весь трафик будет перенаправлен на обработку в sidecar-контейнер istio-proxy
, который ещё не запущен. Обходные пути:
- Запустить прикладной init-контейнер от пользователя с uid
1337
. Запросы данного пользователя не перехватываются под управление Istio. - Исключить IP-адрес или порт сервиса из-под контроля Istio с помощью аннотаций
traffic.sidecar.istio.io/excludeOutboundIPRanges
илиtraffic.sidecar.istio.io/excludeOutboundPorts
.
Обновление Istio
Обновление control plane Istio
- Deckhouse позволяет инсталлировать несколько версий control plane одновременно:
- Одна глобальная, обслуживает пространства имён или поды без явного указания версии (лейбл у пространства имён
istio-injection: enabled
). Настраивается параметром globalVersion. - Остальные — дополнительные, обслуживают пространства имён или поды с явным указанием версии (лейбл у пространства имён или пода
istio.io/rev: v1x21
). Настраиваются параметром additionalVersions.
- Одна глобальная, обслуживает пространства имён или поды без явного указания версии (лейбл у пространства имён
- Istio заявляет обратную совместимость между data plane и control plane в диапазоне двух минорных версий:
- Алгоритм обновления (для примера, с версии
1.19
на версию1.21
):- Добавить желаемую версию в параметр модуля additionalVersions (
additionalVersions: ["1.21"]
). - Дождаться появления соответствующего пода
istiod-v1x21-xxx-yyy
в пространства имёнd8-istio
. - Для каждого прикладного пространства имён, где включен istio:
- поменять лейбл
istio-injection: enabled
наistio.io/rev: v1x21
; - по очереди пересоздать поды в пространстве имён, параллельно контролируя работоспособность приложения.
- поменять лейбл
- Поменять настройку
globalVersion
на1.21
и удалитьadditionalVersions
. - Убедиться, что старый под
istiod
удалился. - Поменять лейблы прикладных пространств имён на
istio-injection: enabled
.
- Добавить желаемую версию в параметр модуля additionalVersions (
Чтобы найти все поды под управлением старой ревизии Istio (в примере — версия 19), выполните команду:
1kubectl get pods -A -o json | jq --arg revision "v1x19" \
2 '.items[] | select(.metadata.annotations."sidecar.istio.io/status" // "{}" | fromjson |
3 .revision == $revision) | .metadata.namespace + "/" + .metadata.name'
Автоматическое обновление data plane Istio
Доступно в редакциях Enterprise Edition и Certified Security Edition Pro (1.67).
Для автоматизации обновления istio-sidecar’ов установите лейбл istio.deckhouse.io/auto-upgrade="true"
на Namespace
либо на отдельный ресурс — Deployment
, DaemonSet
или StatefulSet
.