Istio 基础概念学习整理
流量管理
为了在网格中导流,Istio 需要知道所有的 endpoint 在哪以及它们属于哪些服务。 为了定位到 service registry(服务注册中心), Istio 会连接到一个服务发现系统(Istio不提供服务发现系统)。例如,如果您在 Kubernetes 集群上安装了 Istio, 那么它将自动检测该集群中的服务和 endpoint。
虚拟服务(Virtual Service) 和目标规则(Destination Rule) 是 Istio 流量路由功能的核心构建模块。每个虚拟服务包含一组按顺序评估的路由规则,通过这些规则,Istio 将每个到虚拟服务的给定请求匹配到特定的、真实的目标地址。
使用 Istio实现金丝雀发布
Kubernetes中使用istio流量路由和副本部署是两个完全独立的功能,可以轻松实现细粒度控制流量百分比(例如路由 1% 的流量而不需要 100 个 Pod)。
定义svc,Istio是基于svc来实现服务注册的
yaml
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
spec:
selector:
app: helloworld
...
添加 2 个 Deployment,包含相同的标签app=helloworld
,版本分别为 v1 和 v2。
yaml
kind: Deployment
metadata:
name: helloworld-v1
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v1
spec:
containers:
- image: helloworld-v1
...
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: helloworld-v2
spec:
replicas: 1
template:
metadata:
labels:
app: helloworld
version: v2
spec:
containers:
- image: helloworld-v2
...
使用普通 Kubernetes 进行金丝雀部署需要调整每个 Deployment 的副本数目。例如,将 10% 的流量发送到金丝雀版本(v2),v1 和 v2 的副本可以分别设置为 9 和 1。
使用istio我们可以通过设置路由规则来控制流量分配:
yaml
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld
http:
- route:
- destination:
host: helloworld
subset: v1
weight: 90 # 90%的流量给v1
- destination:
host: helloworld
subset: v2
weight: 10
timeout: 10s # 默认15秒
retries:
attempts: 3 # 默认重试2次
perTryTimeout: 2s # 每次重试都有 2 秒的超时
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
EOF
我们基于流量来控制后,我们就可以放心的使用hpa了
shell
$ kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10
$ kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10
我们还可以通过匹配headers来实现将特定用户的流量引入到金丝雀版本中
yaml
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld
http:
- match:
- headers:
cookie:
regex: "^(.*?;)?(email=[^;]*@some-company-name.com)(;.*)?$"
route:
- destination:
host: helloworld
subset: v1
weight: 50
- destination:
host: helloworld
subset: v2
weight: 50
- route:
- destination:
host: helloworld
subset: v1
EOF
Istio网关
Istio 的网关资源可以来管理网格的入站和出站流量,可以配置 4-6 层的负载均衡属性,如对外暴露的端口、TLS 设置等。网关主要用于管理进入的流量。
示例:让 HTTPS 流量从 ext-host.example.com
通过 443 端口流入网格
yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: ext-host-gwy
spec:
selector:
app: my-gateway-controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- ext-host.example.com
tls:
mode: SIMPLE
credentialName: ext-host-cert
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: virtual-svc
spec:
hosts:
- ext-host.example.com
gateways:
- ext-host-gwy
服务入口
配置服务入口允许您管理运行在网格外的服务的流量
示例:添加一个外部dns到服务中心
yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: svc-entry
spec:
hosts:
- ext-svc.example.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
---
# 接下来就可以把其添加为DestinationRule了
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: ext-res-dr
spec:
host: ext-svc.example.com
trafficPolicy:
connectionPool:
tcp:
connectTimeout: 1s
Sidecar
默认情况下,Istio 让每个 Envoy 代理都可以访问来自和它关联的工作负载的所有端口的请求,在大集群中会因此占用大量内存,所以sidecar支持特定namespace的访问
yaml
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default
namespace: bookinfo
spec:
egress:
- hosts:
- "./*" # 当前ns的服务
- "istio-system/*" # istio-system ns下的服务
故障注入
故障注入是一种将错误引入系统以确保系统能够承受并从错误条件中恢复的测试方法。
示例:千分之一的访问 5 秒延迟
yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percentage:
value: 0.1
fixedDelay: 5s
route:
- destination:
host: ratings
subset: v1
Kubernetes Gateway API
Kubernetes Gateway API负责南北流量,集群对外访问的流量。Istio关注的是服务之间的流量,包括集群内的东西向流量和南北向流量。
与 Ingress 不同,Kubernetes Gateway 不包含对目标服务的任何引用。使用 Gateway API 后,服务路由被定义在单独的配置资源中, 这些配置资源会附加到 Gateway 中,用于将流量子集定向到特定服务,例如我们示例中的 helloworld。这种分离允许我们在不同的命名空间中定义 Gateway 和路由, 并可以由不同的团队进行管理。
定义helloworld测试服务
shell
$ kubectl create ns sample
$ kubectl apply -f samples/helloworld/helloworld.yaml -n sample
定义网关资源
shell
$ kubectl create namespace sample-ingress
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: sample-gateway
namespace: sample-ingress
spec:
gatewayClassName: istio # 名为 istio 的gw
listeners:
- name: http
hostname: "*.sample.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All # 所有ns
EOF
上面我们作为集群管理人员,在 sample-ingress
命名空间中应用了 Gateway,因为 Gateway 资源的所有权归于集群操作员,它可以很好地用于为多个团队的服务提供入口。
接下来,我们将代表开发人员为 sample-ingress/sample-gateway
添加路由。
shell
kubectl apply -n sample -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: helloworld
spec:
parentRefs: # 将 HTTPRoute 附加到 sample-gateway
- name: sample-gateway
namespace: sample-ingress
hostnames: ["helloworld.sample.com"] # 子域名
rules:
- matches:
- path:
type: Exact
value: /hello # 路径
backendRefs:
- name: helloworld # svc/helloworld
port: 5000
EOF
基于权重的路由选择,创建v1、v2的svc
shell
$ kubectl apply -n sample -f samples/helloworld/gateway-api/helloworld-versions.yaml
将流量 90% 转到 v1
,10% 到 v2
shell
$ kubectl apply -n sample -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: helloworld
spec:
parentRefs:
- name: sample-gateway
namespace: sample-ingress
hostnames: ["helloworld.sample.com"]
rules:
- matches:
- path:
type: Exact
value: /hello
backendRefs:
- name: helloworld-v1
port: 5000
weight: 90
- name: helloworld-v2
port: 5000
weight: 10
EOF