LoginSignup
4
2

More than 5 years have passed since last update.

IstioのKubernetes上におけるTraffic Managementの仕組みを理解する

Last updated at Posted at 2019-04-28

Istioを本番システムで利用する場合は、Istioの機能がどのように実現されているかを理解していないと、いざという時トラブルシュートができません。そこで、Istioを勉強するにあたって、IstioのTraffic ManagementがKubernetes上でどのように実現されているかをドキュメントを見たり、kubectlでリバースエンジニアリングしながら調べてみました。

  • 想定読者

    • IstioがTraffic ManagementをKubernetes上でどのように実現するか理解したい人
    • Kubernetesの基礎は理解している
      • Service、Podなどの基本的なリソースの説明はしません
  • 前提

    • 外部からmesh内サービスへのアクセスまでを対象とし、mesh内から外部への通信については触れない
      • ServiceEntryについては触れません、いつかもっと理解したら載せるかもです
    • IstioのサンプルアプリIstio / Bookinfo Applicationを題材とする
      • image.png

IstioのTraffic Managementを実現するリソースの理解

参考:Istio / Traffic Management

本記事ではIstioのTraffic にManagementを実現する以下3つのCRD(Custom Resource Definition)について説明をする。

  • VirtualService
  • DestinationRule
  • Gateway

各リソースを用いてBookinfoにおけるIstioのリクエストフローを表現すると、以下のようになる。Kubernetes上で具体的にどのように実現されているかは後述する。あくまでも、リソースを理解するうえでのイメージ図であることに注意。

スクリーンショット 2019-04-28 17.48.41.png

Gateway

  • Istio / Gateway
  • mesh外からのリクエスト受付窓口
  • exposeするポート、プロトコル、SNIの設定情報を記載する
  • GatewayとVirtualServiceの紐付けはVirtualServiceで行う

VirtualService

  • Istio / Virtual Service
  • mesh上のリクエストのルーティング設定を行う
    • DestinationRule(後述)でより細かいルーティング設定ができる
  • bookinfoではまずbookinfo VirtualServiceでGatewayへのアクセスをproductpage VirtualServiceへルーティングしている
    • 次にproductpage VirtualServiceの設定によりproductpage Podにリクエストがルーティングされる
bookinfo-virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
  namespace: ""
spec:
  gateways:
  - bookinfo-gateway
  hosts:
  - '*'
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage # <= 上記でmatchしたリクエストをproductpageにルーティングする
        port:
          number: 9080
productpage-viertualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
  namespace: ""
  resourceVersion: ""
spec:
  hosts:
  - productpage   <= productpageへのリクエストを受けるVirtualService
  http:
  - route:
    - destination:
        host: productpage    <= productpageに
        subset: v1           <= subset: v1というDestinationRuleでルーティングを行う

DestinationRule

  • Istio / Destination Rule
  • VirtualServiceがPodにリクエストをルーティングする際の細かいポリシーなどを設定する
  • バージョンごとのルーティングや、負荷分散のポリシーなどを設定できる
productpage-destinatnionrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productpage
  namespace: default
spec:
  host: productpage      <= productpageへ来たリクエストに対する細かいルールを設定
  subsets:
  - labels:
      version: v1
    name: v1             <= version: v1のラベルへルーティングするsubsetをv1という名前で定義している

上記productpageは単一バージョンしかないが、reviewsは複数バージョンがあるため、複数のsubsetが定義されている。

reviews-destinationrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
  namespace: default
spec:
  host: reviews
  subsets:
  - labels:
      version: v1
    name: v1
  - labels:
      version: v2
    name: v2
  - labels:
      version: v3
    name: v3

Kubernetes上での実現方法を理解する

IstioのTraffic ManagementがKubernetesでどのように実現されるかを説明する。
(参考:Istio / Traffic Management

スクリーンショット 2019-04-29 8.21.38.png

mesh外からのリクエストルーティング

  • istio-ingressgateway ServiceからProxyコンテナに入ってきたリクエストは、各Pod内にsidecarとして起動しているProxyコンテナを介してリクエストのやりとりを行う
  • ProxyコンテナはIstioのPilotコンポーネントが作成したルーティングルールにしたがってリクエストをルーティングする

istio-ingressgateway Service

  • Istio install時にデフォルトでinstallされている
  • KubernetesのServiceリソース(type LoadBalancer)で作成されている
    • EKSなどで作成すると、ELBが自動的に作成される
    • 外部からのリクエストを受け付ける窓口となる
      • Gatewayリソース作成時に紐付けをする
  • 宛先にはProxyコンテナが指定されている
    • 外部からのアクセスはこの仕組みにより最初のProxyコンテナにルーティングされ、ルーティング設定にしたがってmesh上の各Podにルーティングされていく

IstioのCRDどこいった?

お気づきかと思うが、上記の説明ではGatewayやVirtualService、DestinationRuleがでてこない。これらのリソースはPilotが作成するProxyコンテナのルーティングルールの作成に利用されている。それぞれの設定はPilotによりルーティングルールとして全Proxyコンテナに設定される。

Serviceリソースをどこに使ってるんだ?

通信は全てProxyコンテナ間で行われ、各ProxyコンテナはPilotによって作成されたルーティングルールに沿って通信を行う。つまりProxyコンテナは直接はKubernetesのServiceリソースによる名前解決を利用していない。ではどこで利用しているかというと、Pilotがルーティングルールを作成する際に利用している。(参考:Istio / Traffic Management

実際にServiceの定義を見てみるとselectorには app: reviews しか指定されていない。

reviews-service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: reviews
    service: reviews
  name: reviews
spec:
  ports:
  - name: http
    port: 9080
    protocol: TCP
    targetPort: 9080
  selector:
    app: reviews
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

以下のようにDeploymentを確認すると、reviewsの全てのバージョン(V1~V3)に app: reviews ラベルが貼られている。つまり、reviews Serviceで名前解決をすると全てのバージョン(V1~V3)の宛先が返ってくるはずである。

$ k get deploy -o wide                                                                                                                                                       
NAME             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS    IMAGES                                          SELECTOR
details-v1       1         1         1            1           5h        details       istio/examples-bookinfo-details-v1:1.10.1       app=details,version=v1
productpage-v1   1         1         1            1           5h        productpage   istio/examples-bookinfo-productpage-v1:1.10.1   app=productpage,version=v1
ratings-v1       1         1         1            1           5h        ratings       istio/examples-bookinfo-ratings-v1:1.10.1       app=ratings,version=v1
reviews-v1       1         1         1            1           5h        reviews       istio/examples-bookinfo-reviews-v1:1.10.1       app=reviews,version=v1
reviews-v2       1         1         1            1           5h        reviews       istio/examples-bookinfo-reviews-v2:1.10.1       app=reviews,version=v2
reviews-v3       1         1         1            1           5h        reviews       istio/examples-bookinfo-reviews-v3:1.10.1       app=reviews,version=v3

上記のようなServiceの設定を見てもわかるように、Proxyコンテナ自体はServiceリソースを直接は用いておらず、Pilotがルーティングルールを作成するために利用していることがわかる。

(参考)Pod上のAPコードの変更なしでリクエストがProxyを通るようにする仕組み

内容

IstioではAPの変更なしで、PodがProxyコンテナを通すようにすることができる。PodからのリクエストをどのようにProxyコンテナを通すようにするか気になったので少し調べてみた。結論は以下。

  • PodからのリクエストはよしなにProxyコンテナを仲介するように設定される
    • たぶん自動injectionをtrueにすれば勝手にやってくれる

Podのyamlを見てみるとProxyコンテナがリクエストを奪い取るっぽい設定がされたいる。

以下にproductpageの元のDeploymentのyamlと実際にデプロイされていたpodのyamlを記載する。

productpage-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: productpage-v1
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      containers:
      - name: productpage
        image: istio/examples-bookinfo-productpage-v1:1.10.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
product-pod.yaml
$ k get po productpage-v1-5cb458d74f-wnlf8 -o yaml                                                                                                                           [~/SDropbox/Dropbox/k8s/istio]
apiVersion: v1
kind: Pod
metadata:
  annotations:
    sidecar.istio.io/status: '{"version":"db2f6e5a0d19dde20f8dc886fe87dbb029dd3d2c3f77bfc11196d156ca5f8069","initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-certs"],"imagePullSecrets":null}'
  creationTimestamp: 2019-04-28T00:50:50Z
  generateName: productpage-v1-5cb458d74f-
  labels:
    app: productpage
    pod-template-hash: "1760148309"
    version: v1
  name: productpage-v1-5cb458d74f-wnlf8
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: productpage-v1-5cb458d74f
    uid: aaf0a34b-694f-11e9-89ac-067d8b9d0d08
  resourceVersion: "4680"
  selfLink: /api/v1/namespaces/default/pods/productpage-v1-5cb458d74f-wnlf8
  uid: aaf1f726-694f-11e9-89ac-067d8b9d0d08
spec:
  containers:
  - image: istio/examples-bookinfo-productpage-v1:1.10.1
    imagePullPolicy: IfNotPresent
    name: productpage
    ports:
    - containerPort: 9080
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-c5qk5
      readOnly: true
  - args:
    - proxy
    - sidecar
    - --domain
    - $(POD_NAMESPACE).svc.cluster.local
    - --configPath
    - /etc/istio/proxy
    - --binaryPath
    - /usr/local/bin/envoy
    - --serviceCluster
    - productpage.$(POD_NAMESPACE)
    - --drainDuration
    - 45s
    - --parentShutdownDuration
    - 1m0s
    - --discoveryAddress
    - istio-pilot.istio-system:15010
    - --zipkinAddress
    - zipkin.istio-system:9411
    - --connectTimeout
    - 10s
    - --proxyAdminPort
    - "15000"
    - --concurrency
    - "2"
    - --controlPlaneAuthPolicy
    - NONE
    - --statusPort
    - "15020"
    - --applicationPorts
    - "9080"
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.namespace
    - name: INSTANCE_IP
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: status.podIP
    - name: ISTIO_META_POD_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.name
    - name: ISTIO_META_CONFIG_NAMESPACE
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.namespace
    - name: ISTIO_META_INTERCEPTION_MODE
      value: REDIRECT
    - name: ISTIO_METAJSON_LABELS
      value: |
        {"app":"productpage","pod-template-hash":"1760148309","version":"v1"}
    image: gcr.io/istio-release/proxyv2:release-1.1-latest-daily
    imagePullPolicy: IfNotPresent
    name: istio-proxy
    ports:
    - containerPort: 15090
      name: http-envoy-prom
      protocol: TCP
    readinessProbe:
      failureThreshold: 30
      httpGet:
        path: /healthz/ready
        port: 15020
        scheme: HTTP
      initialDelaySeconds: 1
      periodSeconds: 2
      successThreshold: 1
      timeoutSeconds: 1
    resources:
      limits:
        cpu: "2"
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi
    securityContext:
      readOnlyRootFilesystem: true
      runAsUser: 1337
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /etc/istio/proxy
      name: istio-envoy
    - mountPath: /etc/certs/
      name: istio-certs
      readOnly: true
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-c5qk5
      readOnly: true
  dnsPolicy: ClusterFirst
  initContainers:
  - args:
    - -p
    - "15001"
    - -u
    - "1337"
    - -m
    - REDIRECT
    - -i
    - '*'
    - -x
    - ""
    - -b
    - "9080"
    - -d
    - "15020"
    image: gcr.io/istio-release/proxy_init:release-1.1-latest-daily
    imagePullPolicy: IfNotPresent
    name: istio-init
    resources:
      limits:
        cpu: 100m
        memory: 50Mi
      requests:
        cpu: 10m
        memory: 10Mi
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
      runAsNonRoot: false
      runAsUser: 0
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
  nodeName: ip-192-168-20-207.us-west-2.compute.internal
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: default-token-c5qk5
    secret:
      defaultMode: 420
      secretName: default-token-c5qk5
  - emptyDir:
      medium: Memory
    name: istio-envoy
  - name: istio-certs
    secret:
      defaultMode: 420
      optional: true
      secretName: istio.default
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2019-04-28T00:50:53Z
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: 2019-04-28T00:51:03Z
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: null
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: 2019-04-28T00:50:50Z
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: docker://ff9bcd670cfdf0ebb511e2a354f275eccdfd87adb0e08a62c3b4ea7634271519
    image: gcr.io/istio-release/proxyv2:release-1.1-latest-daily
    imageID: docker-pullable://gcr.io/istio-release/proxyv2@sha256:01d50d0390058d52197727499dcad3f0ccc6f65e0cf6a82ddf85bd0083341dfe
    lastState: {}
    name: istio-proxy
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2019-04-28T00:51:01Z
  - containerID: docker://5786b8460526512f321dba0f5317c6a474f319b8c63c2d22ed5e582840af3197
    image: istio/examples-bookinfo-productpage-v1:1.10.1
    imageID: docker-pullable://istio/examples-bookinfo-productpage-v1@sha256:a427e10277a814b27c066d9ea5f2605b656fc1948714ed09e55c97342c5a721d
    lastState: {}
    name: productpage
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2019-04-28T00:51:00Z
  hostIP: 192.168.20.207
  initContainerStatuses:
  - containerID: docker://49956b55bed3950f0a4a3c35207994c4ad1925ea82e304a870533db82073825f
    image: gcr.io/istio-release/proxy_init:release-1.1-latest-daily
    imageID: docker-pullable://gcr.io/istio-release/proxy_init@sha256:30e629a68500f45b73dd7258cf86c6c1c20920bdd5d92eb6a26aacb6d1c54739
    lastState: {}
    name: istio-init
    ready: true
    restartCount: 0
    state:
      terminated:
        containerID: docker://49956b55bed3950f0a4a3c35207994c4ad1925ea82e304a870533db82073825f
        exitCode: 0
        finishedAt: 2019-04-28T00:50:53Z
        reason: Completed
        startedAt: 2019-04-28T00:50:52Z
  phase: Running
  podIP: 192.168.3.132
  qosClass: Burstable
  startTime: 2019-04-28T00:50:50Z

istio-proxyとistio-initが追記されていることがわかりますね。
こいつらがよしなにやってくれているのだろう。

まとめ

IstioのTrafficがどのようにKubernetes上で実現されるかを説明しました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2