解锁更多k8s相关内容可以关注我的微信公众号“运维日常手记”。
介绍
istio是一个开源的服务网格,它可以提供:
- 双向 TLS 加密、基于身份的强身份验证和授权实现安全的服务到服务通信
- HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡
- 通过丰富的路由规则、重试、故障转移和故障注入对流量行为进行精细控制
- 支持访问控制、速率限制和配额的可插拔策略层和配置 API
- 集群内入口和出口的所有流量的metrics、logs和traces的自动监控
两种模式
Istio提供两种模式,一种是Ambient模式,还有一种是Sidecar模式,Sidecar模式需要在每个pod中注入Envoy代理,开销较大,Ambient模式是新的改进的模型,旨在解决 sidecar 模式的缺点。在Ambient模式下,每个节点上都安装了一个安全隧道,可以使用您安装的代理(通常)按命名空间选择加入完整功能集,但相对于Sidecar模式,Ambient模式有一些特性还不支持,比如多集群安装,多网络支持等。
Ambient模式安装
安装istioctl工具
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.26.1
export PATH=$PWD/bin:$PATH
安装数据面应用,此处hub指定国内镜像仓库
istioctl install --set profile=ambient --set hub=crpi-u3f530xi0zgtvmy0.cn-beijing.personal.cr.aliyuncs.com/image-infra --skip-confirmation
安装gateway CRD
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
部署示例应用
示例应用架构如下图,部署过程中镜像可能会下载失败,可更改镜像前缀为上一步hub指定的国内镜像仓库。
编辑
执行以下命令部署示例应用
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/platform/kube/bookinfo-versions.yaml
简单查看下bookinfo.yaml的部分内容,可以看到这是其中一个Details服务的yaml文件,它创建了一个Service,一个ServiceAccount和一个Deployment,其中Deployment中引用了ServiceAccount。
---
# Details service
apiVersion: v1
kind: Service
metadata:
name: details
labels:
app: details
service: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-details
labels:
account: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: details-v1
labels:
app: details
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: details
version: v1
template:
metadata:
labels:
app: details
version: v1
spec:
serviceAccountName: bookinfo-details
containers:
- name: details
image: docker.io/istio/examples-bookinfo-details-v1:1.20.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
部署和配置gateway网关
# 部署和配置gateway
kubectl apply -f samples/bookinfo/gateway-api/bookinfo-gateway.yaml
# 将服务类型更改为ClusterIP
kubectl annotate gateway bookinfo-gateway networking.istio.io/service-type=ClusterIP --namespace=default
分析一下bookinfo-gateway.yaml的内容,如下
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
gatewayClassName: istio # 指定使用 Istio 作为网关实现
listeners:
- name: http
port: 80 # 监听 80 端口
protocol: HTTP # 协议是 HTTP
allowedRoutes:
namespaces:
from: Same # 只允许同命名空间的 HTTPRoute 绑定此 Gateway
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: bookinfo
spec:
parentRefs:
- name: bookinfo-gateway # 绑定到上述 Gateway
rules:
- matches: # 定义匹配规则
- path:
type: Exact # 精确匹配路径
value: /productpage
- path:
type: PathPrefix # 前缀匹配路径
value: /static
- path:
type: Exact
value: /login
- path:
type: Exact
value: /logout
- path:
type: PathPrefix
value: /api/v1/products
backendRefs: # 定义后端服务
- name: productpage # 指向名为 productpage 的 Service
port: 9080 # 服务端口 9080
部署完成后将看到一个gateway pod,它就是网关。
编辑
测试,浏览器访问http://localhost:8080/productpage(localhost改为节点ip)
kubectl port-forward --address 0.0.0.0 svc/bookinfo-gateway-istio 8080:80
输出如下,刷新界面将看到Reviews的变化
编辑
将应用添加到服务网格中,执行如下命令后,pod中的服务间调用将启用mTLS加密。
kubectl label namespace default istio.io/dataplane-mode=ambient
可视化应用程序和指标
kubectl apply -f samples/addons/prometheus.yaml
kubectl apply -f samples/addons/kiali.yaml
测试,浏览器访问http://localhost:20001(localhost改为节点ip)
kubectl port-forward --address 0.0.0.0 svc/kiali 20001:20001 -n istio-system
调用一下productpage服务,然后刷新一下界面就能看到服务间调用链路和metrics指标监控。
编辑
授权策略
四层授权策略,设置productpage 服务只允许gateway网关的请求通过。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-ztunnel
namespace: default
spec:
selector:
matchLabels:
app: productpage # 目标:带有标签 app=productpage 的 Pod
action: ALLOW # 动作:允许访问(默认是 DENY,需显式声明 ALLOW)
rules:
- from:
- source:
principals:
# 仅允许来自此身份(Istio为每个服务分配的身份,UI界面上可以查看到)的请求
- cluster.local/ns/default/sa/bookinfo-gateway-istio
EOF
测试,运行一个带有curl命令的pod,在pod里面访问productpage应用,将无法访问
kubectl apply -f samples/curl/curl.yaml
kubectl exec deploy/curl -- curl -s "http://productpage:9080/productpage"
提示无法访问
upstream connect error or disconnect/reset before headers. reset reason: connection termination
七层授权策略
# 部署一个waypoint代理
istioctl waypoint apply --enroll-namespace --wait
kubectl get gtw waypoint
创建策略,使productpage服务仅接受curl服务发起的GET请求。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-waypoint
namespace: default
spec:
targetRefs:
- kind: Service # 明确指定目标资源类型(Service)
group: ""
name: productpage # 目标服务名称
action: ALLOW # 允许符合条件的请求
rules:
- from:
- source:
principals:
- cluster.local/ns/default/sa/curl # 仅允许来自此身份的请求
to:
- operation:
methods: ["GET"] # 仅允许GET请求
EOF
测试之前productpage服务还需要允许waypoint代理访问。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-ztunnel
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/default/sa/bookinfo-gateway-istio
- cluster.local/ns/default/sa/waypoint
EOF
测试
$ # This fails with an RBAC error because you're not using a GET operation
$ kubectl exec deploy/curl -- curl -s "http://productpage:9080/productpage" -X DELETE
RBAC: access denied
$ # This fails with an RBAC error because the identity of the reviews-v1 service is not allowed
$ kubectl exec deploy/reviews-v1 -- curl -s http://productpage:9080/productpage
RBAC: access denied
$ # This works as you're explicitly allowing GET requests from the curl pod
$ kubectl exec deploy/curl -- curl -s http://productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
流量拆分
创建HTTPRoute
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: reviews
spec:
parentRefs:
- group: ""
kind: Service # 绑定到Service资源(而非Gateway)
name: reviews # 目标Service名称,访问该服务的流量将会被拆分
port: 9080 # Service端口
rules:
- backendRefs:
- name: reviews-v1
port: 9080
weight: 90 # reviews-v1服务接收90%流量
- name: reviews-v2
port: 9080
weight: 10 # reviews-v2服务接收10%流量
EOF
测试,将会看到到v1和v2的流量大概是9:1
kubectl exec deploy/curl -- sh -c "for i in $(seq 1 100); do curl -s http://productpage:9080/productpage | grep reviews-v.-; done"
至此结束,如果觉得文章有用,麻烦给个关注,谢谢。