Istio入门指南

50 阅读6分钟

解锁更多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"

至此结束,如果觉得文章有用,麻烦给个关注,谢谢。