当前位置: 首页 > 工具软件 > Istio > 使用案例 >

Istio服务网格

卢承弼
2023-12-01

【为什么用Istio】

微服务对于每个功能的开发细化了,但是对于系统的管理负载度增强了,尤其是网络流量的管理。这样很多功能例如黑名单,导流,加密,访问控制,流量监控,熔断,限速,收费功能,数据流节点延迟,就不需要在应用代码中更改了。

【Istio的关键功能】

HTTP/1.1,HTTP/2,gRPC和TCP流量的自动区域感知负载均衡和故障切换。

通过丰富的路由规则,容错和故障注入,对流行为的粒度控制。

支持访问控制,速率限制和配额的可插拔策略层和配置API。

集群内所有流量的自动度量,日志和跟踪,包括集群入口和出口。

安全的服务到服务身份验证,在集群中的服务之间具有强大的身份标识。

【微服务的两面性】

虽然微服务对开发进行了简化,但通过将复杂系统切分为若干个微服务来分解和降低复杂度,使这些微服务被小型开发团队所理解和维护。但是复杂度并为消失。

微服务拆分后,单个微服务复杂度大幅降低,但是由于系统被一个单体拆分为十几个甚至更多微服务,带来了另一个复杂度:微服务的连接,管理和监控。

【Sidecar模式】

Sidecar是容器应用模式的一种,service meash(服务网格)架构的一种实现方式,使用Sidecar部署服务网格时,无需再节点上运行代理(不需要基础结构的协作),但是集群当中将运行多个sidecar副本,从另一个角度看:在sidecar部署方式当中,你会为每个应用容器部署一个伴生容器。Sidecar接管进出应用容器的所有流量。在kubernetes的pod中,在原有应用旁启动一个sidecar容器,可以理解为两个容器共享存储,网络等资源,可以理解为将sidecar容器注入到pod当中,两个容器共享资源。

【istio注入和伴生容器】

通过上面可以了解istio会通过在一个pod中多创建一个伴生容器,使这个伴生容器管理这个pod所有的进出流量,istio注入就是将这个伴生容器注入原本的pod中。下面是一个例子:

[root@localhost ~]# [root@localhost ~]# kubectl apply -f nginx.yaml
pod/test created
[root@localhost ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          2s
[root@localhost ~]# cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
#此处是一个正常启动的pod,可以看到没有伴生容器
#接下来在这个nginx.yaml的基础上,再手动注入一个伴生容器
#这里只需要命令注入,yaml会自动写好。
[root@localhost ~]# istioctl kube-inject -f nginx.yaml > nginx-istio.yaml
[root@localhost ~]# cat nginx-istio.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/default-container: test-container
    kubectl.kubernetes.io/default-logs-container: test-container
    prometheus.io/path: /stats/prometheus
    prometheus.io/port: "15020"
    prometheus.io/scrape: "true"
    sidecar.istio.io/status: '{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}'
  creationTimestamp: null
  labels:
    security.istio.io/tlsMode: istio
    service.istio.io/canonical-name: test
    service.istio.io/canonical-revision: latest
  name: test
spec:
  containers:
  - image: nginx:latest
    imagePullPolicy: IfNotPresent
    name: test-container
    resources: {}
  - args:
    - proxy
    - sidecar
    - --domain
    - $(POD_NAMESPACE).svc.cluster.local
    - --proxyLogLevel=warning
    - --proxyComponentLogLevel=misc:error
    - --log_output_level=default:info
    - --concurrency
    - "2"
    env:
    - name: JWT_POLICY
      value: third-party-jwt
    - name: PILOT_CERT_PROVIDER
      value: istiod
    - name: CA_ADDR
      value: istiod.istio-system.svc:15012
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: INSTANCE_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: SERVICE_ACCOUNT
      valueFrom:
        fieldRef:
          fieldPath: spec.serviceAccountName
    - name: HOST_IP
      valueFrom:
        fieldRef:
          fieldPath: status.hostIP
    - name: PROXY_CONFIG
      value: |
        {}
    - name: ISTIO_META_POD_PORTS
      value: |-
        [
        ]
    - name: ISTIO_META_APP_CONTAINERS
      value: test-container
    - name: ISTIO_META_CLUSTER_ID
      value: Kubernetes
    - name: ISTIO_META_INTERCEPTION_MODE
      value: REDIRECT
    - name: ISTIO_META_WORKLOAD_NAME
      value: test
    - name: ISTIO_META_OWNER
      value: kubernetes://apis/v1/namespaces/default/pods/test
    - name: ISTIO_META_MESH_ID
      value: cluster.local
    - name: TRUST_DOMAIN
      value: cluster.local
    image: docker.io/istio/proxyv2:1.12.0
    name: istio-proxy
    ports:
    - containerPort: 15090
      name: http-envoy-prom
      protocol: TCP
    readinessProbe:
      failureThreshold: 30
      httpGet:
        path: /healthz/ready
        port: 15021
      initialDelaySeconds: 1
      periodSeconds: 2
      timeoutSeconds: 3
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      privileged: false
      readOnlyRootFilesystem: true
      runAsGroup: 1337
      runAsNonRoot: true
      runAsUser: 1337
    volumeMounts:
    - mountPath: /var/run/secrets/istio
      name: istiod-ca-cert
    - mountPath: /var/lib/istio/data
      name: istio-data
    - mountPath: /etc/istio/proxy
      name: istio-envoy
    - mountPath: /var/run/secrets/tokens
      name: istio-token
    - mountPath: /etc/istio/pod
      name: istio-podinfo
  initContainers:
  - args:
    - istio-iptables
    - -p
    - "15001"
    - -z
    - "15006"
    - -u
    - "1337"
    - -m
    - REDIRECT
    - -i
    - '*'
    - -x
    - ""
    - -b
    - '*'
    - -d
    - 15090,15021,15020
    image: docker.io/istio/proxyv2:1.12.0
    name: istio-init
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
        drop:
        - ALL
      privileged: false
      readOnlyRootFilesystem: false
      runAsGroup: 0
      runAsNonRoot: false
      runAsUser: 0
  volumes:
  - emptyDir:
      medium: Memory
    name: istio-envoy
  - emptyDir: {}
    name: istio-data
  - downwardAPI:
      items:
      - fieldRef:
          fieldPath: metadata.labels
        path: labels
      - fieldRef:
          fieldPath: metadata.annotations
        path: annotations
    name: istio-podinfo
  - name: istio-token
    projected:
      sources:
      - serviceAccountToken:
          audience: istio-ca
          expirationSeconds: 43200
          path: istio-token
  - configMap:
      name: istio-ca-root-cert
    name: istiod-ca-cert
status: {}
---
#再次执行测试
kubectl a[root@localhost ~]# kubectl apply -f nginx-istio.yaml
pod/test created
[root@localhost ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   2/2     Running   0          4s
#现在pod中却启动了两个容器,其中一个则是新添加的伴生容器,进出流量就由这个容器接管。

完成istio注入的方式,有手动注入和自动注入。

手动注入就是想先前的例子一样,后面添加上kubectl apply -f - 即可

istioctl kube-inject -f nginx.yaml > nginx-istio.yaml | kubectl apply -f -

自动注入则是给命名空间打上特定标签,当拥有这个标签的命名空间内的pod都会自动添加伴生容器。下面是例子:

[root@localhost ~]# kubectl label ns default istio-injection=enabled
namespace/default labeled
[root@localhost ~]# cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test-container
    image: nginx:latest
    imagePullPolicy: IfNotPresent
[root@localhost ~]# kubectl apply -f nginx.yaml
pod/test created
[root@localhost ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   2/2     Running   0          5s
#可以看见当设置了标签后,即使没有手动注入,只要pod被部署于这个命名空间时,就会自动添加伴生容器。

【istio在k8s中怎么工作】

#这里使用命令获取一下控制器发现,istio自带暴露服务的控制器和ingress-nginx类似的工作方式
[root@localhost bookinfo]# kubectl get deploy -n istio-system
NAME                   READY   UP-TO-DATE   AVAILABLE   AGE
grafana                1/1     1            1           60m
istio-egressgateway    1/1     1            1           60m
istio-ingressgateway   1/1     1            1           60m
istiod                 1/1     1            1           60m
jaeger                 1/1     1            1           60m
kiali                  1/1     1            1           60m
prometheus             1/1     1            1           60m
#查看后发现istio-ingressgateway和istio-egressgateway的存在,gateway资源可以直接打上标签来使用这个service
[root@localhost bookinfo]# kubectl get service -n istio-system
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                                      AGE
grafana                NodePort       10.96.241.212   <none>        3000:33000/TCP                                                               59m
istio-egressgateway    ClusterIP      10.96.38.192    <none>        80/TCP,443/TCP                                                               60m
istio-ingressgateway   LoadBalancer   10.96.109.254   <pending>     15021:11906/TCP,80:38548/TCP,443:25679/TCP,31400:12156/TCP,15443:63397/TCP   60m
istiod                 ClusterIP      10.96.74.254    <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        60m
jaeger-collector       ClusterIP      10.96.122.5     <none>        14268/TCP,14250/TCP,9411/TCP                                                 59m
kiali                  NodePort       10.96.37.93     <none>        20001:20001/TCP,9090:9091/TCP                                                59m
prometheus             NodePort       10.96.246.113   <none>        9090:30090/TCP                                                               59m
tracing                NodePort       10.96.178.201   <none>        80:30686/TCP,16685:30685/TCP                                                 59m
zipkin                 ClusterIP      10.96.206.142   <none> 

这里的istio-ingressgateway和istio-egressgateway管理了istio所有进出流量。网关设置标签选择器可以设定指定控制器。

【istio资源】

实际操作:https://mp.csdn.net/mp_blog/creation/editor/130003775

此处gateway资源选择了ingressgateway控制器,实际流量会经过ingressgateway控制器,这个gateway将管理访问任意域名,80端口,http协议的流量。

[root@localhost istio]# cat gateway.yaml
apiVersion: networking.istio.io/v1alpha3   #这里network api注意版本。
kind: Gateway                              #创建网关类型
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway               #设置标签,给istio默认的控制器识别,istio有默认控制器。有egressgateway控制器和ingressgateway控制器
  servers:
  - port:
      number: 80                        #设置80端口
      protocol: HTTP                    #设置协议为HTTP
      name: http                        #设置名称http
    hosts:
    - "*"                               #设置允许访问的域名,这里是全部允许。

 这里设置虚拟服务,上面gateway筛选的流量会通过vs虚拟服务。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: booking
spec:
  hosts:
  - "*"                    #定义路由规则关联的一组主机。
  gateways:
  - bookinfo-gateway       #设置网关名,可以时多个网关
  http:
  - match:                                 #定义路由的匹配规则列表。
    - uri:
        prefix: /api/v1/booking              
    - uri: 
        exact: /login          #exact请求,prefix前缀                                
    route:                         #路由转发目的地列表。
    - destination:
        host: booking-service      #这里设置service服务名称
        port:
          number: 80               #设置service端口

match相当于设置条件,route指定流量的去处,这里设置了service服务名称,最后流量会被转发到这个service上。

当微服务有多个版本的时候,就需要用到destinationrule资源,通过vs,不同的规则将流量转发到不同的版本。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: dest-nginx
spec:
  host: ttt           #设置service名称
  subsets:
  - name: a
    labels:
      version: a      #设置pod标签
  - name: b
    labels:
      version: b      #设置pod标签

 类似资料: