Впровадження та переваги Istio Ambient Mesh. Оптимізація ресурсів та підвищення безпеки у мікросервісних середовищах
Привіт! Мене звати Нікіта, я DevOps-інженер у команді професіоналів на платформі FinOps Uniskai від Profisea Labs. Нещодавно наша команда зіткнулася з викликом захисту та додаткового контролю над трафіком мікросервісів. Для цього вирішили впровадити Istio Ambient Mesh.
Istio виділяється як платформа з відкритим кодом, призначена для оптимізації та зміцнення зв’язку між мікросервісами. Вона спрощує складність керування трафіком у Kubernetes в багатьох хмарних середовищах, пропонуючи рішення для масштабованості та безпеки.
За своєю суттю Istio складається з двох ключових елементів:
Data plane. Охоплює мережу proxy-серверів Envoy, які обслуговують зв’язок між мікросервісами. Envoy діє як легкий proxy-сервер. Розгорнутий разом із кожною службою, він перехоплює та регулює потік трафіку. Надає основні функції: виявлення служб, покращення безпеки, mTLS, інструменти для стійкості мережі та її спостережуваності.
Control plane. Виконуючи функцію оркестратора, площина керування централізує завдання керування та налаштування для proxy-серверів у площині даних. Раніше він складався з кількох компонентів, тепер його спрощено в один ресурс під назвою Istiod. Istiod займається виявленням служб, конфігурацією та керуванням сертифікатами, перетворюючи правила маршрутизації високого рівня в конкретні конфігурації для Envoy.
Service Mesh діє як проміжний рівень у кластерній мережі. Він захищає канали зв’язку між призначеними контейнерами, працюючи поруч із основними контейнерами застосунків, як-от sidecar-контейнер. Це налаштування забезпечує підключення до мережі через proxy-сервер із бездоганною інтеграцією між ним та основною програмою через локальну мережу.
Але у версії Istio 1.19.0 зʼявився Ambient mode. Ambient mesh створено для спрощення Service mesh, з особливим акцентом на гнучкість архітектури, безпеку та продуктивність. В нашій команді вирішили спробувати Istio й майже одразу ми стикнулись з проблемою: Istio не додавав init-container в mesh й тому вони не могли закінчити свою роботу. У ході розгляду цієї проблеми було відкрито issue на GitHub де розробники розібралися в проблемі й вирішили її. Хочу скористатися можливістю та виразити подяку за це.
Переваги Istio Ambient Mesh
Зменшення ресурсів і накладних витрат
- Ambient Mesh має модульну архітектуру, де можливості L4 і L7 розподілені між двома компонентами, що знижує потребу у ресурсах порівняно з sidecar-proxy.
- Відсутність sidecar-proxy дозволяє уникнути зайвого використання ресурсів, спрощує роботу команд DevOps та покращує загальну ефективність кластерів.
- Ztunnels, які обробляють функції з zero trust/mTLS і L4 на рівні вузлів, є легкими та менш ресурсомісткими. Waypoint proxy автоматично масштабуються відповідно реального трафіку, що економить ресурси й кошти.
Zero trust і краща безпека мережі
- Відсутність sidecar-proxy, інтегрованих із застосунками, забезпечує кращу ізоляцію між ними та компонентами мережі, що підвищує загальну безпеку.
- Ztunnels і waypoint proxy можуть застосовувати політики authn/z.
- Керування життєвим циклом ztunnels і proxy здійснюється без перезапуску робочих навантажень, що забезпечує нульовий час простою.
Підвищення продуктивності та ефективності роботи
- Менша кількість компонентів для керування спрощує роботу команд DevOps, зменшує затримку та підвищує загальну продуктивність мережі.
- Гнучкість архітектури дозволяє поступово впроваджувати Istio. Починаючи з базових функцій, як-от mTLS і L4, і поступово додаючи розширені функції L7.
Режим Ambient у Istio відкриває нові можливості для оптимізації роботи мікросервісів, знижуючи складність та витрати, забезпечуючи при цьому високий рівень безпеки та продуктивності.
Розгортання Istio Ambient з використанням Terraform & Helm
Перш за все раджу зпулити й розташувати імейджі в вашому приватному репозиторії. На прикладі AWS це буде ECR. Оскільки при перших спробах розгортання ресурсів Istio їхня конфігурація зазнавала змін і в списку ресурсів є не тільки deployment, а й daemonset, ми вкрай швидко зіткнулись з проблемою обмеження кількості завантажень з DockerHub. Це блокувало роботу всього кластеру.
Щоб запобігти проблемі, вирішили використовувати внутрішній репозиторій. А ще тому, що в наших кластерах використовуються node з різними архітектурами x86 й arm. Більше про це у статті «Як оптимізувати хмарну інфраструктуру: шлях DevOps-інженера від процесорів x86 до ARM (Graviton) архітектури».
Щоб мати docker manifest, котрий посилається на імейджі під різні архітектури, необхідно спочатку отримати доступ до власного репозиторію, зпулити імейджі з DockerHub й запушити їх до нього з різними тагами. Після створити docker manifest зі списком цих імейджів й також запушити його в репозиторій. Такі дії необхідно повторити для всіх імейджів Istio, котрі ви будете використовувати.
aws ecr get-login-password --region <aws_region> | docker login --username AWS --password-stdin <account_id>.dkr.ecr.<aws_region>.amazonaws.com
docker pull istio/pilot:1.22.0 --platform linux/amd64
docker tag istio/pilot:1.22.0 <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-amd64
docker push <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-amd64
docker pull istio/pilot:1.22.0 --platform linux/arm64
docker tag istio/pilot:1.22.0 <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-arm64
docker push <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-arm64
docker manifest create <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0 <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-arm64 <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0-amd64
docker manifest push <account_id>.dkr.ecr.<aws_region>.amazonaws.com/istio:pilot-1.22.0
Для деплою Istio в кластер з використанням Terraform кращим рішенням буде створити окремий модуль. Щоб в ньому описати все, що стосується конфігурації Istio. Стандартний deployment Istio дає змогу лише керувати трафіком всередині кластеру, тому до Istio Base & Istiod helm chart необхідно додати й сконфігурувати Istio Gateway, завдяки якому ми зможемо керувати й направляти трафік ззовні.
resource "helm_release" "istio_base" {
name = "istio-base"
namespace = "istio-system"
chart = "base"
repository = "https://istio-release.storage.googleapis.com/charts"
create_namespace = true
version = "1.22.0"
}
resource "helm_release" "istiod" {
name = "istiod"
namespace = "istio-system"
chart = "istiod"
repository = "https://istio-release.storage.googleapis.com/charts"
create_namespace = true
version = "1.22.0"
wait = true
values = [file("values/istiod.yaml")]
depends_on = [helm_release.istio_base]
}
resource "helm_release" "istio_gateway" {
name = "istio-gateway"
namespace = "istio-system"
chart = "gateway"
repository = "https://istio-release.storage.googleapis.com/charts"
create_namespace = true
version = "1.22.0"
values = [file("values/istio-gateway.yaml")]
depends_on = [helm_release.istiod]
}
Коли ресурси в Terrafrom створені, необхідно додати модифіковані values.yaml файли для кожного helm chart, оскільки необхідно вказати місце зберігання імейджів (власного репозиторію), проставити ресурси й увімкнути Ambient mode. В нашому випадку фронтенд-сервіси додатково використовують протокол HTTP/1.1, тому в змінних Istiod треба прописати наступне значення. Протестуйте у своєму середовищі: якщо використовується остання версія протоколу, ці зміни не потрібні.
pilot:
hub: "<account_id>.dkr.ecr.<aws_region>.amazonaws.com"
tag: "pilot-1.22.0"
image: "istio"
traceSampling: 100.0
env:
PILOT_HTTP10: "1"
PILOT_ENABLE_AMBIENT: true
resources:
requests:
cpu: 300m
memory: 700Mi
limits:
cpu: 300m
memory: 700Mi
istio_cni:
enabled: true
chained: true
Своєю чергою конфігурація Istio Gateway є більш комплексною, оскільки Helm chart, котрий називається «istio-gateway» створює тільки pod й service в кластері. Окрім цього, chart має два типи gateway для керування вхідним трафіком.
Перший — стандартний Istio Gateway, котрий є частиною CRD networking.istio.io й розгортається завдяки helm chart. Він розглядається в цьому прикладі. Інший — Gateway API. Належить до CRD gateway.networking.k8s.io, котрий розгортається завдяки Kubernetes manifest. Розберемо розбіжності цих рішень у наступному пункті, а поки зосередимось на Istio gateway.
podAnnotations:
karpenter.sh/do-not-disrupt: "true"
autoscaling:
enabled: true
minReplicas: 2
resources:
requests:
cpu: 100m
memory: 150Mi
limits:
cpu: 100m
memory: 150Mi
service:
ports:
- name: status-port
port: 15021
protocol: TCP
targetPort: 15021
- name: http2
port: 80
protocol: TCP
targetPort: 80
- name: https
port: 443
protocol: TCP
targetPort: 443
annotations:
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "30"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "10"
В цьому файлі описується масштабування цього deployment. Рекомендую ставити від двох реплік, щоб у разі відмови одного pod трафік до ваших сервісів йшов через інший. Стандартно цей сервіс створює Network LoadBalancer, який конфігурується завдяки анотаціям.
Якщо ви використовуєте Application LoadBalancer в інфраструктурі, можете зіткнутись з перешкодами. Наприклад, з унеможливленням використовування WAF з NLB. Щоб розвʼязати проблему, можна скористатися AWS Application Load Balancer (ALB), який посилається на service Istio Gateway. Для досягнення цієї мети ми використовуємо аналогічний до минулого прикладу підхід, але з деякими модифікаціями:
podAnnotations:
karpenter.sh/do-not-disrupt: "true"
autoscaling:
enabled: true
minReplicas: 2
resources:
requests:
cpu: 100m
memory: 150Mi
limits:
cpu: 100m
memory: 150Mi
service:
type: NodePort
ports:
- name: status-port
protocol: TCP
port: 15021
targetPort: 15021
nodePort: 30586
- name: http2
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /healthz/ready
alb.ingress.kubernetes.io/healthcheck-port: "30586"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "30"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "10"
В цьому файлі ми змінили тип service з Load Balancer на Node Port. Далі постає питання — як виконувати health checks на AWS Application LoadBalancer? Адже в Istio Gateway використовуються різні порти — 80 для вхідного трафіку та 15021 для перевірки статусу. Якщо в Ingress вказати анотацію «alb.ingress.kubernetes.io/healthcheck-port», то ALB Ingress Controller не реагує на це налаштування, й Ingress не створюється для AWS LoadBalancer.
Рішення полягає в тому, щоб перемістити анотації, пов’язані з health check, в service самого Istio Gateway. Для цього редагуємо service Istio Gateway. Щоб анотації, пов’язані з health check, були застосовані до цього service.
Також може виникнути проблема з health check. Якщо таке сталось — збільшіть інтервали й таймаути. В нашому випадку вистачило виставити інтервали в 30 секунд й таймаут в 10. В різних середовищах й випадках поведінка може відрізнятись, тому треба підібрати ці значення.
У варіанті з використанням Gateway API необхідно додати CRD в кластер. Дістати їх можна в офіційному репозиторії по шляху «config/crd/standard». Для зручності чотири завантажених файли можна обʼєднати в один файл, розділивши маніфести «---». Коли створили спільний файл, що містить опис всіх ресурсів, зберігаємо у зручному місці й створюємо gateway.
Щоб трафік був захищений через цей gateway, використаємо cert-manager. Є можливість встановити CRDʼs, використовуючи Helm Chart й переписавши у значеннях «installCRDs: true». Або таким чином, як з Gateway API — встановити з репозиторію й обʼєднати маніфести. В цьому прикладі показано конфігурацію ClusterIssuer для використання Amazon Route53 для отримання DNS01 ACME (детальніше описано в документації).
//Cert-manager module
data "kubectl_file_documents" "cert_manager_crd" {
content = file("files/manifests/cert-manager.crds.yaml")
}
resource "kubectl_manifest" "cert_manager_manifest" {
for_each = data.kubectl_file_documents.cert_manager_crd.manifests
yaml_body = each.value
}
data "aws_iam_policy_document" "cert_manager_webidentity" {
statement {
effect = "Allow"
actions = [
"sts:AssumeRoleWithWebIdentity"
]
condition {
test = "StringEquals"
variable = "${replace(module.eks.cluster_oidc_issuer_url, "https://", "")}:aud"
values = [
"sts.amazonaws.com"
]
}
condition {
test = "StringEquals"
variable = "${replace(module.eks.cluster_oidc_issuer_url, "https://", "")}:sub"
values = [
"system:serviceaccount:cert-manager:cert-manager"
]
}
principals {
type = "Federated"
identifiers = [
module.eks.oidc_provider_arn
]
}
}
}
resource "aws_iam_role" "cert_manager_role" {
name = "cert-manager"
assume_role_policy = data.aws_iam_policy_document.cert_manager_webidentity.json
}
resource "aws_iam_policy" "cert_manager_policy" {
name = "cert-manager-policy"
description = "Policy for cert-manager IAM role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": "${var.cert_manager_route53_role}",
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "cert_manager_attachment" {
role = aws_iam_role.cert_manager_role.name
policy_arn = aws_iam_policy.cert_manager_policy.arn
}
resource "kubernetes_manifest" "route53_cluster_issuer" {
manifest = {
apiVersion = "cert-manager.io/v1"
kind = "ClusterIssuer"
metadata = {
name = "route53-cluster-issuer"
}
spec = {
acme = {
server = "https://acme-v02.api.letsencrypt.org/directory"
privateKeySecretRef = {
name = "route53-cluster-issuer"
}
solvers = [
{
selector = {
dnsZones = ["${var.site}"]
}
dns01 = {
route53 = {
region = "us-east-1"
role = "${var.cert_manager_route53_role}"
}
}
}
]
}
}
}
depends_on = [kubectl_manifest.cert_manager_manifest]
}
//Istio module
data "kubectl_file_documents" "gateway_api_crd" {
content = file("files/manifests/gateway-api.crds.yaml")
}
resource "kubectl_manifest" "gateway_api_manifest" {
for_each = data.kubectl_file_documents.gateway_api_crd.manifests
yaml_body = each.value
}
//Istio Gateway (CRD resource)
resource "kubernetes_manifest" "istio_ingress_gateway" {
manifest = {
apiVersion = "networking.istio.io/v1beta1"
kind = "Gateway"
metadata = {
name = "ingress-gateway"
namespace = "istio-system"
}
spec = {
selector = {
app = "istio-gateway"
}
servers = [
{
port = {
number = 80
name = "http"
protocol = "HTTP"
}
tls = {
httpsRedirect = true
}
hosts = ["*.test.com"]
},
{
port = {
number = 443
name = "https"
protocol = "HTTPS"
}
tls = {
mode = "SIMPLE"
credentialName = "ingress-gateway-cert"
}
hosts = ["*.test.com"]
}
]
}
}
depends_on = [kubernetes_manifest.route53_cluster_issuer]
}
//Gateway API "Gateway" (CRD resource)
resource "kubernetes_manifest" "ingress_gateway" {
manifest = {
apiVersion = "gateway.networking.k8s.io/v1beta1"
kind = "Gateway"
metadata = {
name = "ingress-gateway"
namespace = "istio-system"
annotations = {
"cert-manager.io/cluster-issuer" = "route53-cluster-issuer"
"service.beta.kubernetes.io/aws-load-balancer-internal" = "true"
"service.beta.kubernetes.io/aws-load-balancer-nlb-target-type" = "ip"
}
labels = {
app = "ingress-gateway"
}
}
spec = {
gatewayClassName = "istio"
listeners = [
{
name = "http"
protocol = "HTTP"
port = 80
hostname = "*.test.com"
},
{
name = "https"
protocol = "HTTPS"
port = 443
hostname = "*.test.com"
tls = {
mode = "Terminate"
certificateRefs = [
{
kind = "Secret"
group = ""
name = "ingress-gateway-cert"
}
]
}
allowedRoutes = {
namespaces = {
from = "All"
}
}
}
]
}
}
depends_on = [kubernetes_manifest.route53_cluster_issuer]
}
Gateway API помітно схожий на API Istio. А саме у використанні ресурсів Gateway і VirtualService, які служать аналогічним цілям. Мета розробки нових Gateway API — уніфікувати інформацію, зібрану з різних вхідних реалізацій Kubernetes, включно з Istio, щоб сформулювати стандартизований API, позбавлений упередженості постачальника. Хоча ці API першочергово служать тим же цілям, що й Gateway та VirtualService від Istio, існують деякі характерні відмінності.
В API Istio Gateway складається з двох частин: helm chart й сам gateway, де Istio керує вже розгорнутими ресурсами. І навпаки, в рамках Gateway API ресурс налаштовує та розгортає gateway. Хоча у VirtualService від Istio всі протоколи налаштовані в одному ресурсі, Gateway API використовує інший підхід, згідно з яким кожен тип протоколу має свій окремий ресурс. Наприклад, HTTPRoute і TCPRoute.
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: example-vs
namespace: example
spec:
gateways:
- istio-system/ingress-gateway #here you should write namespace & gateway name (Istio CRD)
hosts:
- example.test.com
http:
- match:
- uri:
prefix: /
name: example-svc
route:
- destination:
host: example-svc
port:
number: 80
tcp:
- match:
- port: 27017
route:
- destination:
host: example.svc.cluster.local
port:
number: 5555
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-example-route
spec:
parentRefs:
- name: ingress-gateway #here you should write gateway name (Gateway API CRD)
hostnames:
- "example.test.com"
rules:
- backendRefs:
- name: example-svc
port: 80
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: tcp-example-route
spec:
parentRefs:
- name: ingress-gateway #here you should write gateway name (Gateway API CRD)
sectionName: foo
rules:
- backendRefs:
- name: example-svc
port: 5555
Попри те, що Gateway API пропонує низку складних функцій маршрутизації, Gateway API поки що не охоплює повного набору функцій Istio. Адже багато людей вважають Gateway API перспективним проєктом, але не можуть його використовувати через несумісність з ALB. Саме тому ми вирішили використовувати звичайний функціонал Istio.
У випадку використання Service Mesh після того, як основні ресурси Istio розгорнуті й налаштовані, треба додати мітку «istio-injection=enabled» в namespace, котрі повинні бути в Istio Service Mesh й перезавантажити pod, щоб sidecar proxy зʼявились у кожному екземплярі в namespace. Основний недолік Service Mesh — його копія є у кожному pod кожного namespace, котрий ви додали в Service Mesh, додавши label «istio-injection=enabled».
Стандартні значення sidecar-контейнеру — (requests cpu: 100m, memory: 128Mi & limits cpu: 2000m, memory: 1024Mi). На практиці у тестовому середовищі використання ресурсів було на рівні 150m й 240Мі, що є досить суттєвим. Оскільки в нашому Dev-кластері в основному namespace, котрий містить самі мікросервіси аплікації, налічується біля 40 pod (залежить від навантаження). Якщо підрахувати, на один namespace знадобляться додаткові 6000m (6vCPU) й 9600Mi (9,6Gb).
Важливо відзначити — в нашому кластері використовується Karpenter, тому значення requests & limits виставленні однаковими. Для того, щоб Karpenter підбирав оптимальні node.
Своєю чергою Istio Ambient Mesh для роботи потребує лише два daemonset — це Istio CNI й Ztunnel. Також кожен namespace, котрий ви хочете додати до mesh, повинен мати label «istio.io/dataplane-mode=ambient». Istio CNI використовується для налаштування перенаправлення трафіку для модулів у Istio mesh. Він працює як daemonset: на кожному вузлі, з підвищеними привілеями.
Агент вузла CNI використовується обома режимами даних Istio, Ztunnel (Zero trust tunnel). Це спеціально створений proxy для кожного вузла для навколишньої Istio mesh. Він відповідає за безпечне підключення та автентифікацію робочих навантажень в Istio mesh зовнішнього середовища.
На Dev-кластері ми маємо 24 node, з чого виходить, що розгорнуті по 24 pod для кожного демонсету. Підібрані значення виділених ресурсів для контейнеру Istio CNI — (requests/limits cpu: 100m, memory: 100Mi), Ztunnel — (requests/limits cpu: 150m, memory: 150Mi), що сумарно складає 6000m (6vCPU) й 6000Mi (6Gb). З однією вагомою різницею — це на весь кластер, у порівнянні з Service Mesh для одного namespace.
Як раніше було сказано, для Ambient mesh треба розгорнути daemonset Istio CNI й Ztunnel.
resource "helm_release" "istio_cni" {
name = "istio-cni"
namespace = "istio-system"
chart = "cni"
repository = "https://istio-release.storage.googleapis.com/charts"
create_namespace = true
version = "1.22.0"
values = [file("values/istio-cni.yaml")]
depends_on = [helm_release.istio_base]
}
resource "helm_release" "ztunnel" {
name = "ztunnel"
namespace = "istio-system"
chart = "ztunnel"
repository = "https://istio-release.storage.googleapis.com/charts"
create_namespace = true
version = "1.22.0"
values = [file("values/istio-ztunnel.yaml")]
depends_on = [helm_release.istio_base]
}
Де в values.yaml Istio CNI ми можемо вказати namespace, котрі ми не хочемо додавати в Ambient mesh з деяких причин: як обмеження Istio ми зобовʼязані внести в цей список «istio-system» й «kube-system», вибагливі вимоги до продуктивності. Istio, як додатковий компонент в системі, дещо уповільнює роботу. Два proxy додаються приблизно 0,182 мс і 0,248 мс до
Також можуть бути проблеми з окремими застосунками, на нашому прикладі це «kube-prometheus-stack», котрий при додаванні в mesh переводить node в стан «not ready» й викликає ланцюгову реакцію для всіх інших node в кластері. Для запобігання такого були додані в список namespace «monitoring», «karpenter».
cni:
hub: "<account_id>.dkr.ecr.<aws_region>.amazonaws.com"
tag: "cni-1.22.0"
image: "istio"
ambient:
enabled: true
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 100m
memory: 100Mi
privileged: true
excludeNamespaces:
- kube-public
- kube-system
- karpenter
- istio-system
- monitoring
В values.yaml файлі Ztunnel нам необхідно тільки вказати ресурси й репозиторій з імейджем.
defaults:
hub: "<account_id>.dkr.ecr.<aws_region>.amazonaws.com"
tag: "ztunnel-1.22.0"
image: "istio"
resources:
requests:
cpu: 150m
memory: 150Mi
limits:
cpu: 150m
memory: 150Mi
Коли всі ресурси сконфігуровані й розташовані в кластері, необхідно проставити label «istio.io/dataplane-mode=ambient», після чого перезапустити node, оскільки Istio CNI для роботи повинен ініціалізуватись при старті сервера. Впевнившись, що все працює як заплановано, необхідно перенаправити вхідний трафік до Istio.
resource "kubectl_manifest" "sentry_ingress" {
count = var.environment == "dev" ? 0 : 1
yaml_body = <<YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "${helm_release.sentry.name}"
namespace: "istio-system"
annotations:
alb.ingress.kubernetes.io/group.name: internal
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/ssl-redirect: '443'
alb.ingress.kubernetes.io/target-type: ip
kubernetes.io/ingress.class: alb
spec:
rules:
- ${var.environment == "prod" ? "host: \"sentry.${var.dns_domain}\"" : var.environment == "stage" ? "host: \"sentry-${var.dns_domain}\"" : "host: \"sentry-${var.environment}.${var.dns_domain}\""}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: "istio-internal-gateway"
port:
number: 80
YAML
depends_on = [helm_release.sentry]
}
resource "kubectl_manifest" "virtual_service_sentry" {
yaml_body = <<YAML
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: "${helm_release.sentry.name}"
namespace: "${kubernetes_namespace_v1.sentry.metadata.0.name}"
spec:
gateways:
- ${var.environment == "dev" ? "istio-system/ingress-gateway" : "istio-system/istio-internal-gateway"}
hosts:
- ${var.environment == "prod" ? "sentry.${var.dns_domain}" : var.environment == "stage" ? "sentry-${var.dns_domain}" : "sentry-${var.environment}.${var.dns_domain}"}
http:
- match:
- uri:
prefix: /api/0/
route:
- destination:
port:
number: 9000
host: sentry-web
- match:
- uri:
prefix: /api/
route:
- destination:
port:
number: 3000
host: sentry-relay
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 9000
host: sentry-web
name: sentry-web
YAML
depends_on = [helm_release.sentry]
}
resource "kubernetes_namespace_v1" "sentry" {
metadata {
name = "sentry"
labels = {
name = "sentry"
"istio.io/dataplane-mode" = "ambient"
}
}
}
resource "kubectl_manifest" "sentry_istio_waypoint" {
yaml_body = <<YAML
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: "${kubernetes_namespace_v1.sentry.metadata.0.name}-istio-waypoint"
namespace: "${kubernetes_namespace_v1.sentry.metadata.0.name}"
spec:
gatewayClassName: istio-waypoint
listeners:
- name: mesh
port: 15008
protocol: HBONE
YAML
depends_on = [kubernetes_namespace_v1.sentry]
}
Перенаправлення трафіку до Istio на прикладі Sentry полягає у створенні namespace замість використання вбудованого функціоналу Terrafrom провайдера Helm. Так як нам треба проставити мітки, за необхідності створити Istio waypoint для обробки L7 робочих навантажень. Створити ingress, котрий використовує наш ALB й перенаправляє трафік не прямо до сервісу Sentry, а до Istio Gateway в namespace «istio-system», розташування Virtual Service в namespace Sentry, котрий перенаправляє трафік з Istio Gateway до сервісу Sentry. Такі маніпуляції необхідно виконати з кожним застосунком, який ви хочете внести до Istio mesh.
Висновок
Впровадження Istio Ambient Mesh дозволило нашій команді ефективно розвʼязати питання захисту та контролю трафіку між мікросервісами. Використовуючи його, ми значно заощадили у витратах на обчислювальні ресурси, збільшили гнучкість архітектури, покращили безпеку та підвищили надійність наших сервісів (у порівнянні з Service mesh). А також змогли полегшити процеси керування мережею, забезпечивши ефективне управління трафіком з мінімальними накладними витратами.
10 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів