サービスメッシュを実現するIstioをEKS上で動かす - その1 まずはMinikubeでサンプルアプリケーションを動かしてみる

山崎 雅斗
103

Istioとは

Istioは、サービスメッシュを実現するために用いられるソフトウェアです。各マイクロサービスと一緒にSidecar Proxyと呼ばれるプロキシをデプロイし、Sidecar Proxy経由で他のマイクロサービスとの通信を行います。Istioでは、Sidecar ProxyとしてLyft社が作成したEnvoyを採用しています。

Istioは、アプリケーション側で特に修正を加えることなく使えるという特徴があります。例えばKubernetes環境の場合、サービスをデプロイすると、IstioによってPod内にSidecar Proxyが自動的に配置されます。Init Containersという機能を使い、Sidecar Proxyを経由するようにiptablesのルールが書き換えられます。こうすることで、アプリケーションの変更なしでSidecar Proxy経由でのマイクロサービス間通信を実現しています。

Istioが提供する機能の一例として、次のようなものがあります。

  • HTTPやgRPC通信の負荷分散
  • A/Bテストやカナリアリリース
  • RetryやCircuit Breaker
  • mTLSによるサービス認証・サービス間通信の暗号化
  • サービスメッシュの可視化

これはあくまで一例であり、他にも多くの機能が提供されています。

この記事では、まずMinikubeで作ったKubernetesクラスタにIstioをインストールし、その概要を掴んでいこうと思います。

シリーズ一覧

Kubernetesクラスタの準備

では、早速Istioを使うための準備をしていきます。
なお、Minikubeのバージョンは 0.28.1 より新しいものを使用してください。

$ minikube version
minikube version: v0.35.0

まずはKubernetesクラスタを作成していきます。通常のアプリケーションと合わせてIstioをインストールする場合、メモリ8192MB、CPU4つを割り当てることが推奨されています。

なお、この記事ではMinikubeで利用するVM driverをVirtualBoxとして進めていきます。

$ minikube start --memory=8192 --cpus=4 --kubernetes-version=v1.13.0

Istio / Minikube

Istioのインストール

Kubernetesクラスタの準備ができたら、次はIstioをインストールしていきます。

まず、必要なファイル群をダウンロードする必要があります。
次のコマンドを実行すると、必要なファイルを一式ダウンロードしてきてくれます。

$ curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.1.1 sh -

ダウンロードが完了したら istio-1.1.1 というディレクトリができていると思うので、そこに移動しておきます。

$ cd istio-1.1.1

それでは、実際にIstioのコンポーネントをインストールしていきます。
今回はテストが目的なので、検証用として手軽にインストールできる方法を使っていきます。

$ for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done
$ kubectl apply -f install/kubernetes/istio-demo.yaml

インストールできたら、念の為正しくできているか確認しておきます。
出力に多少違いはあるかもしれませんが、だいたい同じような感じでリソースが作られていればOKです。

$ kubectl get service --namespace istio-system
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
grafana                  ClusterIP      10.101.64.221    <none>        3000/TCP                                                                                                                                     41s
istio-citadel            ClusterIP      10.105.151.0     <none>        8060/TCP,15014/TCP                                                                                                                           41s
istio-egressgateway      ClusterIP      10.107.234.187   <none>        80/TCP,443/TCP,15443/TCP                                                                                                                     42s
istio-galley             ClusterIP      10.111.216.196   <none>        443/TCP,15014/TCP,9901/TCP                                                                                                                   42s
istio-ingressgateway     LoadBalancer   10.98.185.191    <pending>     80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32421/TCP,15030:32019/TCP,15031:30492/TCP,15032:31708/TCP,15443:31437/TCP,15020:31055/TCP   41s
istio-pilot              ClusterIP      10.109.64.14     <none>        15010/TCP,15011/TCP,8080/TCP,15014/TCP                                                                                                       41s
istio-policy             ClusterIP      10.105.193.134   <none>        9091/TCP,15004/TCP,15014/TCP                                                                                                                 41s
istio-sidecar-injector   ClusterIP      10.102.66.58     <none>        443/TCP                                                                                                                                      41s
istio-telemetry          ClusterIP      10.111.70.37     <none>        9091/TCP,15004/TCP,15014/TCP,42422/TCP                                                                                                       41s
jaeger-agent             ClusterIP      None             <none>        5775/UDP,6831/UDP,6832/UDP                                                                                                                   40s
jaeger-collector         ClusterIP      10.97.209.25     <none>        14267/TCP,14268/TCP                                                                                                                          40s
jaeger-query             ClusterIP      10.103.246.63    <none>        16686/TCP                                                                                                                                    40s
kiali                    ClusterIP      10.98.38.163     <none>        20001/TCP                                                                                                                                    41s
prometheus               ClusterIP      10.106.254.153   <none>        9090/TCP                                                                                                                                     41s
tracing                  ClusterIP      10.102.197.252   <none>        80/TCP                                                                                                                                       40s
zipkin                   ClusterIP      10.101.17.94     <none>        9411/TCP                                                                                                                                     40s

$ kubectl get pods --namespace istio-system
NAME                                      READY   STATUS      RESTARTS   AGE
grafana-57586c685b-6bkwh                  1/1     Running     0          8m30s
istio-citadel-5f886dc9b4-mdz4w            1/1     Running     0          8m29s
istio-cleanup-secrets-1.1.1-tffzx         0/1     Completed   0          8m31s
istio-egressgateway-6555655585-glxhl      1/1     Running     0          8m30s
istio-galley-689b548d98-nn8xs             1/1     Running     0          8m30s
istio-grafana-post-install-1.1.1-sqt7k    0/1     Completed   0          8m32s
istio-ingressgateway-74484b55f4-vl8g6     1/1     Running     0          8m30s
istio-pilot-6d9b655646-r9lmr              2/2     Running     0          8m29s
istio-policy-5bcc46677b-2vrtt             2/2     Running     6          8m30s
istio-security-post-install-1.1.1-jxhx9   0/1     Completed   0          8m31s
istio-sidecar-injector-74666b458c-wxmj5   1/1     Running     0          8m29s
istio-telemetry-5f796886b4-6dpcd          2/2     Running     6          8m30s
istio-tracing-656f9fc99c-hphpn            1/1     Running     0          8m29s
kiali-69d6978b45-5vmg9                    1/1     Running     0          8m30s
prometheus-66c9f5694-cs8jd                1/1     Running     0          8m29s

Istio / Downloading the Release
Istio / Quick Start Evaluation Install

サンプルのアプリケーションをインストールする

Istioのインストールまでできたら、次はサンプルアプリケーションをインストールしていきます。
ここでは、公式が提供している Bookinfo アプリケーションを使っていきます。

今回使用する Bookinfo アプリケーションは、次のような構成のマイクロサービスとなっています。

bookinfo-architecture

Istio / Bookinfo Application より引用

productpage サービスが一番外側でクライアントからのリクエストを受け、 reviews と details の2つのサービスと連携します。さらに、 reviews は ratings サービスと連携する、という構成となっています。
また、 reviews サービスは異なる3つのバージョンが存在し、それぞれ少しずつ機能が異なります。

アプリケーションをデプロイする前に、default namespaceに istio-injection=enabled というlabelをつけておきます。これをつけておくことで、default namespaceにデプロイされるサービスに対し、Istioが自動的に各サービスのコンテナへSidecar Proxyをデプロイしてくれるようになります。

$ kubectl label namespace default istio-injection=enabled

それでは、アプリケーションをデプロイしていきます。
前の手順でダウンロードしてきたIstioのディレクトリに移動し、次のコマンドを実行します。

$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

これで3つのマイクロサービスがデプロイされます。念の為、うまくいっていることを確認しておきます。

$ kubectl get services
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.101.71.205   <none>        9080/TCP   12s
kubernetes    ClusterIP   10.96.0.1       <none>        443/TCP    39m
productpage   ClusterIP   10.97.227.92    <none>        9080/TCP   10s
ratings       ClusterIP   10.96.33.37     <none>        9080/TCP   11s
reviews       ClusterIP   10.104.70.91    <none>        9080/TCP   10s

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-69658dcf78-t4wr5       2/2     Running   0          2m37s
productpage-v1-6b6798cb84-2txmv   2/2     Running   0          2m35s
ratings-v1-6f97d68b6-2cjzx        2/2     Running   0          2m37s
reviews-v1-7c98dcd6dc-qnd5d       2/2     Running   0          2m36s
reviews-v2-6677766d47-zqpb7       2/2     Running   0          2m36s
reviews-v3-79f9bcc54c-thzs8       2/2     Running   0          2m36s

次に、Kubernetesクラスタの外から Bookinfo アプリケーションにアクセスできるようにするため、 Gateway と呼ばれるリソースを作成します。このリソースの定義もサンプルに含まれているので、 kubectl コマンドを実行するだけで作成できます。

$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

Gatewayは、サービスメッシュのゲートウェイ(一番外側に位置するロードバランサとなる部分)を設定するためのリソースで、次のようなことを設定することができます。

  • Listenするポートとそのプロトコル
  • SNI(Server Name Indication)の設定
  • TLSの設定 など

Gatewayリソースを作成しただけでは、どのポートで外部からの通信を受け付けるかといったことを設定しただけで、サービスメッシュの内部でどのようにリクエストがルーティングされるかということは設定していません。これを設定するために、通常はGatewayと合わせてVirtualServiceリソースを作成します。VirtualServiceリソースを使用すると、URLのパスごとのリクエストルーティング等が可能になります。

では、適用した bookinfo-gateway.yaml の中身を見てみます。
この中では、GatewayとVirtualServiceがそれぞれ一つずつ定義されています。

先程説明したように、Gatewayリソースでは、サービスメッシュのゲートウェイでListenするポートやプロトコル等を設定します。
spec.selector では設定対象のロードバランサ(Pod)を指定します。
今回の場合、 istio=ingressgateway というlabelを持つPodが対象として指定されています。

spec:
  selector:
    istio: ingressgateway # use istio default controller

このlabelを持つPodは、次のコマンドで取得することができます。

$ kubectl get pods --selector istio=ingressgateway --all-namespaces
NAMESPACE      NAME                                    READY   STATUS    RESTARTS   AGE
istio-system   istio-ingressgateway-58c77897cc-lmb85   1/1     Running   0          28d

spec.hosts では、このGatewayリソースが受け付ける対象のホスト名を指定します。
ここに指定されたホスト名とマッチしたリクエストが、このGatewayリソースの設定が適用される対象となります。また、ホスト名にはワイルドカードを指定することもできます。今回作成したGatewayの spec.hosts は次のようになっているため、あらゆるリクエストが対象となります。

hosts:
- "*"

spec.servers 以下には、外部からの通信を受け付けるために必要な設定を記述していきます。
今回作成したものだと次のようになっています。設定を見ると何となく分かるかと思いますが、HTTP用に80番ポートをListenするような設定になります。

servers:
- port:
    number: 80
    name: http
    protocol: HTTP

ここまでできたら、実際に Bookinfo アプリケーションにアクセスしてみましょう。
Minikube環境の場合、次のようなコマンドでアクセス先のIPアドレスとポート番号を知ることができます。

$ minikube ip
192.168.99.116
$ kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
31380

Bookinfoアプリケーションは /productpage というパスでアクセスできるので、今回の場合は 192.168.99.116:31380/productpage がアクセス先のURLとなります。
アクセスして下のような画面が表示されればデプロイは成功しています。

bookinfo-application
Bookinfoアプリケーション

Istio / Bookinfo Application

まとめ

この記事では、Minikubeを使ってIstioをインストールし、その上でサンプルの Bookinfo アプリケーションを動かすところまでを行いました。
今後何回かの記事に渡って、最終的に実運用中のサービスをEKS上のIstioにのせるまでの過程を紹介していく予定です。