K8S-istio

  1. istio安装
  2. istio-nginx例子
  3. istio-nginx测试
  4. 原理
  5. kiali安装

istio安装

mkdir -r /k8s/istio && cd /k8s/istio
curl -L https://istio.io/downloadIstio | sh -
echo 'export PATH="$PATH:/k8s/istio/istio-1.28.0/bin"' >> ~/.bashrc && source ~/.bashrc
istioctl x precheck
cd istio-1.28.0
istioctl install

kubectl label namespace default istio-injection=enabled

kubectl set resources deployment/istiod -n istio-system --containers=discovery --requests=cpu=100m,memory=500Mi --limits=cpu=400m,memory=1Gi
kubectl set resources deployment/istio-ingressgateway -n istio-system --containers=istio-proxy --requests=cpu=100m,memory=256Mi --limits=cpu=500m,memory=512Mi

istio-nginx例子

istio要求调用方同样位于istio环境的容器中,nginx-master.yaml用于调用测试

# nginx-master.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-master
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-master
  template:
    metadata:
      labels:
        app: nginx-master
    spec:
      containers:
        - name: nginx-container-master
          image: nginx:latest
          ports:
            - containerPort: 80

nginx-online表示正式环境

# nginx-online.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      isCanary: 'false'
  template:
    metadata:
      labels:
        app: nginx
        isCanary: 'false'
    spec:
      containers:
        - name: nginx-container
          image: nginx:latest
          ports:
            - containerPort: 80
          lifecycle:
            postStart:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - sed -i "s/Welcome to nginx\!/Welcome to ${HOSTNAME}\!/g" /usr/share/nginx/html/index.html

nginx-canary-1表示金丝雀1

# nginx-canary-1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-canary-1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      isCanary: 'true'
      canaryId: '1'
  template:
    metadata:
      labels:
        app: nginx
        isCanary: 'true'
        canaryId: '1'
    spec:
      containers:
        - name: nginx-container-canary-1
          image: nginx:latest
          ports:
            - containerPort: 80
          lifecycle:
            postStart:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - sed -i "s/Welcome to nginx!/Welcome to ${HOSTNAME}!/g" /usr/share/nginx/html/index.html

nginx-canary-2表示金丝雀2

# nginx-canary-2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-canary-2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      isCanary: 'true'
      canaryId: '2'
  template:
    metadata:
      labels:
        app: nginx
        isCanary: 'true'
        canaryId: '2'
    spec:
      containers:
        - name: nginx-container-canary-2
          image: nginx:latest
          ports:
            - containerPort: 80
          lifecycle:
            postStart:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - sed -i "s/Welcome to nginx!/Welcome to ${HOSTNAME}!/g" /usr/share/nginx/html/index.html

nginx的Service,通配nginx匹配

# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - name: web
      protocol: TCP
      port: 5000
      targetPort: 80
  type: ClusterIP

istio配置

# nginx-vs.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: nginx
spec:
  hosts:
    - nginx.default.svc.cluster.local
  http:
    - match:
        - headers:
            canary_id:
              exact: '1'
      route:
        - destination:
            host: nginx.default.svc.cluster.local
            subset: canary-1
    - match:
        - headers:
            canary_id:
              exact: '2'
      route:
        - destination:
            host: nginx.default.svc.cluster.local
            subset: canary-2
    - route:
        - destination:
            host: nginx.default.svc.cluster.local
            subset: online

---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: nginx
spec:
  host: nginx.default.svc.cluster.local
  subsets:
    - name: online
      labels:
        isCanary: 'false'
    - name: canary-1
      labels:
        isCanary: 'true'
        canaryId: '1'
    - name: canary-2
      labels:
        isCanary: 'true'
        canaryId: '2'
  exportTo:
    - '*'

istio-nginx测试

kubectl exec -it nginx-deployment-master-d9dfb9976-x28s5  -- bash

curl -s nginx:5000 -H "canary_id: 1" | grep "Welcome to"
<title>Welcome to nginx-deployment-canary-1-d4d4f9577-9dlvp!</title>
<h1>Welcome to nginx-deployment-canary-1-d4d4f9577-9dlvp!</h1>

curl -s nginx:5000 -H "canary_id: 2" | grep "Welcome to"
<title>Welcome to nginx-deployment-canary-2-558b489475-d6ppx!</title>
<h1>Welcome to nginx-deployment-canary-2-558b489475-d6ppx!</h1>

curl -s nginx:5000 -H "canary_id: 3" | grep "Welcome to"
<title>Welcome to nginx-deployment-748c545c49-mnsnq!</title>
<h1>Welcome to nginx-deployment-748c545c49-mnsnq!</h1>

curl -s nginx:5000  | grep "Welcome to"
<title>Welcome to nginx-deployment-748c545c49-mnsnq!</title>
<h1>Welcome to nginx-deployment-748c545c49-mnsnq!</h1>

配置的1和2都前往了对应的分组,未配置的3和空则走了默认的分组。

原理

  1. 创建一个Service,得到一个域名nginx.default.svc.cluster.local
  2. POD客户端(这个客户端也必须被注入了Istio)访问这个域名
  3. 流量被转发到POD客户端的istio-proxy(Envoy),访问nginx.default.svc.cluster.local不再是直达经过标签选择的pod,而是被转发到Envoy
  4. Envoy查询VS,使用hosts比对得到上面的VS规则,按断http协议的请求是否存在canary_id这个header,都是则继续查找nginx.default.svc.cluster.local的canary这个subset
  5. Envoy查询DestinationRule,判断nginx.default.svc.cluster.local的canary这个subset的规则,得到规则为存在canaryId: ‘1’这个标签
  6. 最终转发到存在canaryId: ‘1’标签的nginx-deployment-canary-1

Istio+Envoy的组合只会拦截TCP和UDP流量,不会拦截ping的ICMP流量

注册和配置收集

  1. pod被注入istio-proxy后,Envoy进程会自动启动
  2. Envoy尝试连接Istio控制面,报告自己的身份
  3. Istio控制面收集VS,DR等配置,计算这个Envoy的相关配置
    1. 默认情况下本命名空间的服务都被认为相关
    2. 所有被注入了Envoy的服务
  4. Istio控制面根据身份信息推送对应的Envoy配置

kiali安装

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.28/samples/addons/kiali.yaml
kubectl -n istio-system get svc kiali
kubectl -n istio-system port-forward svc/kiali 20001:20001 --address="0.0.0.0"

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/prometheus.yaml
kubectl -n istio-system get pod,svc | grep -i prometheus
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml