從docker到istio之四 - istio分流應用

前言

容器化,雲原生越演越烈,新概念很是之多。信息爆炸的同時,帶來層層迷霧。我嘗試從擴容出發理解其脈路,通過實踐探索,整理造成一個入門教程,包括下面四篇文章。linux

這是第四篇,istio分流應用。nginx

istio

服務網格(Service Mesh)這個術語一般用於描述構成這些應用程序的微服務網絡以及應用之間的交互。隨着規模和複雜性的增加,服務網格愈來愈難以理解和管理。它的需求包括服務發現、負載均衡、故障恢復、指標收集和監控以及一般更加複雜的運維需求,例如 A/B 測試、金絲雀發佈、限流、訪問控制和端到端認證等。git

Istio 提供了一個完整的解決方案,經過爲整個服務網格提供行爲洞察和操做控制來知足微服務應用程序的多樣化需求。github

安裝istio

istio1.1支持kubernetes1.11,1.12,1.13,Docker for mac的stable版本過低,須要切換Docker for mac 到 edge版本,kubernetes會升級到1.13。使用 kubectl version 確認kubernetes版本:redis

Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.0", GitCommit:"ddf47ac13c1a9483ea035a79cd7c10005ff21a6d", GitTreeState:"clean", BuildDate:"2018-12-03T21:04:45Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.0", GitCommit:"ddf47ac13c1a9483ea035a79cd7c10005ff21a6d", GitTreeState:"clean", BuildDate:"2018-12-03T20:56:12Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"linux/amd64"}
複製代碼

按照安裝指南安裝istio到k8s。 kubectl get svc -n istio-system 查看isto服務(svc是service的速記別名)docker

NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
grafana                  ClusterIP      10.96.238.84     <none>        3000/TCP                                                                                                                                     19s
istio-citadel            ClusterIP      10.110.233.235   <none>        8060/TCP,15014/TCP                                                                                                                           19s
istio-egressgateway      ClusterIP      10.107.81.184    <none>        80/TCP,443/TCP,15443/TCP                                                                                                                     20s
istio-galley             ClusterIP      10.108.48.185    <none>        443/TCP,15014/TCP,9901/TCP                                                                                                                   20s
istio-ingressgateway     LoadBalancer   10.99.64.197     localhost     15020:31681/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32145/TCP,15030:31376/TCP,15031:30092/TCP,15032:31491/TCP,15443:32689/TCP   19s
istio-pilot              ClusterIP      10.101.105.130   <none>        15010/TCP,15011/TCP,8080/TCP,15014/TCP                                                                                                       19s
istio-policy             ClusterIP      10.107.208.244   <none>        9091/TCP,15004/TCP,15014/TCP                                                                                                                 19s
istio-sidecar-injector   ClusterIP      10.104.152.19    <none>        443/TCP                                                                                                                                      19s
istio-telemetry          ClusterIP      10.102.233.77    <none>        9091/TCP,15004/TCP,15014/TCP,42422/TCP                                                                                                       19s
jaeger-agent             ClusterIP      None             <none>        5775/UDP,6831/UDP,6832/UDP                                                                                                                   18s
jaeger-collector         ClusterIP      10.100.208.250   <none>        14267/TCP,14268/TCP                                                                                                                          18s
jaeger-query             ClusterIP      10.104.246.180   <none>        16686/TCP                                                                                                                                    18s
kiali                    ClusterIP      10.100.34.9      <none>        20001/TCP                                                                                                                                    19s
prometheus               ClusterIP      10.103.238.247   <none>        9090/TCP                                                                                                                                     19s
tracing                  ClusterIP      10.103.49.38     <none>        80/TCP                                                                                                                                       18s
zipkin                   ClusterIP      10.105.126.70    <none>        9411/TCP
複製代碼

查看isto的pod是否所有正常啓動:flask

➜  kubectl get pods -n istio-system
NAME                                      READY   STATUS      RESTARTS   AGE
grafana-749c78bcc5-jczt2                  1/1     Running     1          20m
istio-citadel-899dfb67c-r6cmx             1/1     Running     0          20m
istio-cleanup-secrets-1.1.3-d42jx         0/1     Completed   0          20m
istio-egressgateway-748d5fd794-zkcjs      1/1     Running     1          20m
istio-galley-555dd7c7d7-t9fhz             1/1     Running     0          20m
istio-grafana-post-install-1.1.3-2qzg5    0/1     Completed   0          20m
istio-ingressgateway-55dd86767f-n5v7m     1/1     Running     1          20m
istio-pilot-7979d58649-lg6vq              2/2     Running     0          20m
istio-policy-f89c945dc-8d6mn              2/2     Running     0          55s
istio-security-post-install-1.1.3-4ggpf   0/1     Completed   0          20m
istio-sidecar-injector-998dd6cbb-fbdgw    1/1     Running     0          20m
istio-telemetry-7d9d866c65-2pngr          2/2     Running     0          16s
istio-tracing-595796cf54-mp6tp            1/1     Running     1          20m
kiali-5df77dc9b6-jq26m                    1/1     Running     0          20m
prometheus-7f87866f5f-p2568               1/1     Running     0          20m
複製代碼

部署應用

調整pods符合istio規範

部署引用前,須要按照Istio對Pod和服務的要求,進行微調。api

微調後的istio\flaskapp.yaml以下:bash

apiVersion: v1
kind: Service
metadata:
  name: flaskapp
spec:
  ports:
    - port: 5000
      name: http
  selector:
    app: business
---
apiVersion: extensions/v1beta1 
kind: Deployment
metadata:
  name: flaskapp
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: business
        version: v1
    spec:
      containers:
      - image: flaskapp:0.0.2
        name: flaskapp
        ports:
        - containerPort: 5000
複製代碼

微調後的istio\redis.yaml以下:網絡

apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  ports:
    - port: 6379
      name: redis
  selector:
    app: redis
---
apiVersion: extensions/v1beta1 
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: redis
        version: v1
    spec:
      containers:
      - image: redis:4-alpine3.8
        name: redisdb
        ports:
        - containerPort: 6379
複製代碼

由於istio附帶ingress,因此咱們取消了前置的nginx負載,直接使用ingress。

啓動istio的sidecar自動注入

istio經過在pod中輸入sidecar,用來管理流量,設置default名稱空間下默認注入:

➜  docker2istio kubectl label namespace default istio-injection=enabled
namespace/default labeled
複製代碼

啓動服務

啓動服務方式和k8s沒有區別

➜  docker2istio kubectl apply -f k8s/redis.yaml -f k8s/flaskapp.yaml
service/redis created
deployment.extensions/redis created
service/flaskapp created
deployment.extensions/flaskapp created
複製代碼

使用kubectl describe pod/flaskapp-757cd47df4-zkzv2 確認istio正常管理app:

Name:               flaskapp-757cd47df4-zkzv2
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               docker-desktop/192.168.65.3
Start Time:         Wed, 24 Apr 2019 18:43:16 +0800
Labels:             app=business
                    pod-template-hash=757cd47df4
                    version=v1
Annotations:        sidecar.istio.io/status:
                      {"version":"3420543c87a5049f8ec099530c3992a5c1f06bf54fa56d7a3877e7ffc658ea8d","initContainers":["istio-init"],"containers":["istio-proxy"]...
Status:             Running
IP:                 10.1.0.45
Controlled By:      ReplicaSet/flaskapp-757cd47df4
Init Containers:
  istio-init:
    Container ID:  docker://0bac5e70832c287a1c446d38034c75ebe5b8e66b9e2fb6d5a1fc3bcb8a9f644c
    Image:         docker.io/istio/proxy_init:1.1.3
    Image ID:      docker-pullable://istio/proxy_init@sha256:000d022d27c198faa6cc9b03d806482d08071e146423d6e9f81aa135499c4ed3
    Port:          <none>
    Host Port:     <none>
    Args:
      
      ...
      
Containers:
  flaskapp:
    Container ID:   docker://9cdf76e12c710f1d50c2b3a2ac349909f481975f220af5b31e1b76717bcabd95
    Image:          flaskapp:0.0.2
    Image ID:       docker://sha256:d52877069956696bb9009c0af43a0d339d2d253e67f5fb09c9f1f052a35528de
    Port:           5000/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 24 Apr 2019 18:43:19 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-ndv6q (ro)
  istio-proxy:
    Container ID:  docker://84eecd89d7c203b7b97749d2a02c63cb8b4c57cfda96f0c7585547a8918344c1
    Image:         docker.io/istio/proxyv2:1.1.3
    Image ID:      docker-pullable://istio/proxyv2@sha256:b682918f2f8fcca14b3a61bbd58f4118311eebc20799f24b72ceddc5cd749306
    Port:          15090/TCP
    Host Port:     0/TCP
    Args:
    
      ...
    
    State:          Running
      Started:      Wed, 24 Apr 2019 18:43:19 +0800
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     2
      memory:  128Mi
    Requests:
      cpu:      10m
      memory:   40Mi
    Readiness:  http-get http://:15020/healthz/ready delay=1s timeout=1s period=2s #success=1 #failure=30
    Environment:
      POD_NAME:                      flaskapp-757cd47df4-zkzv2 (v1:metadata.name)
      POD_NAMESPACE:                 default (v1:metadata.namespace)
      INSTANCE_IP:                    (v1:status.podIP)
      ISTIO_META_POD_NAME:           flaskapp-757cd47df4-zkzv2 (v1:metadata.name)
      ISTIO_META_CONFIG_NAMESPACE:   default (v1:metadata.namespace)
      ISTIO_META_INTERCEPTION_MODE:  REDIRECT
      ISTIO_METAJSON_LABELS:         {"app":"business","pod-template-hash":"757cd47df4","version":"v1"}

    Mounts:
      /etc/certs/ from istio-certs (ro)
      /etc/istio/proxy from istio-envoy (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-ndv6q (ro)

...

複製代碼

!!!注意 這裏的pod,會被自動注入名爲istio-init的initContainer和名爲**istio-proxy的container。具備這2個container,標誌pod接受istio流量管理。

確認服務正常啓動

➜  docker2istio kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
flaskapp     ClusterIP   10.107.67.44     <none>        5000/TCP       4m31s
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        36m
redis        ClusterIP   10.100.210.72    <none>        6379/TCP       4m31s
複製代碼

確認pod正常啓動

➜  docker2istio kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
flaskapp-77ddb9698c-xb2gm   1/1     Running   0          4m2s
redis-c5dd6fcfc-8tqwm       1/1     Running   0          4m2s
複製代碼

部署istio的gateway

由於取消了前置的nginx負載,須要設置gateway,集羣外部纔可以訪問服務。istio\gateway.yaml:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: flaskapp-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: flaskapp
spec:
  hosts:
  - "*"
  gateways:
  - flaskapp-gateway
  http:
  - match:
    - uri:
        exact: /
    route:
    - destination:
        host: flaskapp
        port:
          number: 5000
複製代碼

kubectl apply -f istio/gateway.yaml提交後,查看gameway的端口:

➜  docker2istio kubectl get svc istio-ingressgateway -n istio-system

NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
istio-ingressgateway   LoadBalancer   10.99.64.197   localhost     15020:31681/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32145/TCP,15030:31376/TCP,15031:30092/TCP,15032:31491/TCP,15443:32689/TCP   179m
複製代碼

這裏的服務類型爲LoadBalancer,能夠直接使用80端口訪問服務:

➜  docker2istio curl http://localhost
Hello World by 10.1.0.40 from 10.1.0.30 ! 該頁面已被訪問 1 次。
複製代碼

金絲雀發佈

istio的流量管理提供了很是便捷的金絲雀發佈功能。

首先,咱們調整app/flaskapp.py,將域名獲取調整成爲主機名稱:

#-*- coding:utf-8 -*-
import socket
from flask import Flask
from redis import Redis


app = Flask(__name__)
redis = Redis(host='redis', port=6379)

def get_host_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    except:
        ip = '127.0.0.1'
    finally:
        s.close()
    return ip

def get_hostname():
    return socket.gethostname()

@app.route('/')
def hello():
    app.logger.debug('hello in')
    from flask import request
    count = redis.incr('hits')
    # host_ip = get_host_ip()
    host_id = get_hostname()
    client_ip= request.headers['X-Real-Ip'] if 'X-Real-Ip' in request.headers else request.remote_addr 
    app.logger.debug("Hello out {} {} {}:".format(host_id,client_ip,count))
    return 'Hello World by {} from {} ! 該頁面已被訪問 {} 次。\n'.format(host_id,client_ip,count)


if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
複製代碼

使用 docker build -f app/Dockerfile -t flaskapp:0.0.3 app 編譯新的鏡像。

製做新的deployment,使其使用新的鏡像:

apiVersion: extensions/v1beta1 
kind: Deployment
metadata:
  name: flaskapp-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: business
        version: v2
    spec:
      containers:
      - image: flaskapp:0.0.3
        name: flaskapp
        ports:
        - containerPort: 5000
複製代碼

建立並確認新的部署生效:

➜  docker2istio kubectl apply -f istio/flaskappv2.yaml
deployment.extensions/flaskapp-v2 created
➜  docker2istio kubectl get deployment
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
flaskapp      3/3     3            3           72m
flaskapp-v2   1/1     1            1           7s
redis         1/1     1            1           129m
複製代碼

調整VirtualService,控制流量分發策略:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: flaskapp
spec:
  hosts:
  - "*"
  gateways:
  - flaskapp-gateway
  http:
  - match:
    - uri:
        exact: /
    route:
    - destination:
        host: flaskapp
        port:
          number: 5000
  - route:
    - destination:
        host: flaskapp
        subset: v1
      weight: 80
    - destination:
        host: flaskapp
        subset: v2
      weight: 20
複製代碼

這裏重點是指定規則,按照8:2,將flaskapp的訪問分配到deployment v1 和 deployment v2 上。

kubectl apply -f istio/gateway2.yaml 應用新的流量分配策略:

訪問觀察服務:

➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 7 次。
➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 8 次。
➜  docker2istio curl http://localhost
Hello World by flaskapp-v2-ff9f8cfdb-vh788 from 127.0.0.1 ! 該頁面已被訪問 9 次。
➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 10 次。
➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 11 次。
➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 12 次。
➜  docker2istio curl http://localhost
Hello World by 10.1.0.45 from 127.0.0.1 ! 該頁面已被訪問 13 次。
➜  docker2istio curl http://localhost
Hello World by flaskapp-v2-ff9f8cfdb-vh788 from 127.0.0.1 ! 該頁面已被訪問 14 次。
複製代碼

能夠看到,訪問被按比例分配到v1和v2兩個版本上。

總結

從上面實踐過程空可見,istio完善了k8s提供的編排功能,在縱向擴容的基礎上能夠實現橫向擴展。

相關文章
相關標籤/搜索