Kekeの日記

エンジニア、読書なんでも

IstioでKubernetesのサービスメッシュを構築してみる

f:id:bobchan1915:20181006003856p:plain

本記事

どうやらKubernetesクラスタへのHTTPリクエストのレスポンスタイムがスパイクするということで引き続き原因を探っています。

https://cdn-ak.f.st-hatena.com/images/fotolife/b/bobchan1915/20180927/20180927220444.png

以前の記事で同じくサービスメッシュを構築できるLinkerdというものを検証してみました。

その記事が以下のものとなります。

www.1915keke.com

しかしながら、いま勢いがあるのはIstioです。今回はLinkerdの良し悪しも評価することを含めてIstioを導入しようと思います。

Istioについて

Istioとは

アーキテクチャ

以下のようなアーキテクチャになっています。

https://istio.io/docs/concepts/what-is-istio/arch.svg

大まかな機能を説明します。

  • Pilot: サービスディスカバリと高度なトラフィックマネジメント(A/Bテスト、カナリアデプロイなど)を提供する。
  • Proxy: Envoy Proxyを使ってSidecarとしてデプロイをしている。
  • Mixer: プラットフォームに依存するもの。アクセスコントロールやサービスメッシュに渡る制御をしたり、それぞれのEnvoyやサービスからテレメトリーを収集する。
  • Citadal: サービス間とエンドユーザー認証を行う。
  • Galley: Control Planeを代表してユーザー認証されたIstio APIを提供する。

Helmによるインストール方法について

0. カスタムリソース宣言をデプロイ

まず、リポジトリをクローンします。

git clone git@github.com:istio/istio.git
cd istio

IstioはCustomResoucreを使いまくっているので以下のコマンドでカスタムリソース宣言をデプロイします。

kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml

customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/serviceentries.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/gateways.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/clusterrbacconfigs.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/policies.authentication.istio.io created
customresourcedefinition.apiextensions.k8s.io/meshpolicies.authentication.istio.io created
customresourcedefinition.apiextensions.k8s.io/httpapispecbindings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/httpapispecs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/quotaspecbindings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/quotaspecs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/rules.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/attributemanifests.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/bypasses.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/circonuses.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/deniers.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/fluentds.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/kubernetesenvs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/listcheckers.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/memquotas.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/noops.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/opas.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/prometheuses.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/rbacs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/redisquotas.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/servicecontrols.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/signalfxs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/solarwindses.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/stackdrivers.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/statsds.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/stdios.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/apikeys.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/authorizations.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/checknothings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/kuberneteses.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/listentries.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/logentries.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/edges.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/metrics.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/quotas.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/reportnothings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/servicecontrolreports.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/tracespans.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/rbacconfigs.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/serviceroles.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/servicerolebindings.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/adapters.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/instances.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/templates.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/handlers.config.istio.io created

1. インストールする

今回はhelmのTemplateを使ってControl Planeをデプロイしていきます。

以下のようにデプロイします。

helm template install/kubernetes/helm/istio --name istio --namespace istio-system > $HOME/istio.yaml

kubectl create namespace istio-system
kubectl apply -f $HOME/istio.yaml

GrafanaでIstio自体を監視したい人は以下のオプションをつけてください。

--set grafana.enabled=true --set grafana.persist=true --set grafana.storageClassName=standard

確認すると正しくデプロイができています。

NAME                                        READY     STATUS      RESTARTS   AGE
istio-citadel-86c9878bd9-4ss2j              1/1       Running     0          55s
istio-cleanup-secrets-78tjv                 0/1       Completed   0          58s
istio-egressgateway-6c7949d598-2rq95        1/1       Running     0          55s
istio-galley-656946f9d-sb6sw                1/1       Running     0          55s
istio-ingressgateway-699794bf9c-kfh6m       1/1       Running     0          55s
istio-pilot-5f757f67d8-plp44                1/2       Running     0          55s
istio-policy-6978f6fff4-9brxk               2/2       Running     0          55s
istio-sidecar-injector-58996b77bd-vxnwh     0/1       Running     0          55s
istio-statsd-prom-bridge-55965ff9c8-tfgrk   1/1       Running     0          56s
istio-telemetry-bb6b55b67-5mrld             2/2       Running     0          55s
prometheus-7456f56c96-wq4x6                 1/1       Running     0          55s
grafana-59bdd9c89c-9zfl7                    1/1       Running       0          55s

2. SidecarのInjection

Data Planeを作るには、以下のようにSidecarをデプロイしていきます。

istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -

ここでsamples...は例です。

また、特定のnamespaceにできるPodにEnvoyを自動的に挿入することも可能です。

その場合は以下のラベルを名前空間につけます。

kubectl label namespace default istio-injection=enabled

普段のkubectl applyをするマニフェストファイルにこれを入れるだけで十分です。

確認すると以下のようにContainer数が2になっていました。

NAME                                                       READY     STATUS    RESTARTS   AGE
test-1-6cf9fc7dd-w7mzk                                     2/2       Running   0          14s

以上でインストールは終わりになります。

Task

Traffic管理

ここはA/Bテストやカナリアデプロイなど、トラフィックに関することを行う。

項目が多いため、別途使うときになれば記事にしようと思います。

セキュリティ

私はセキュリティには詳しくないため割愛します。

Policies

これはポリシーという制限をかけるものである。

Rate Limits

どのくらいのトラフィックがくるかを制御できるものである。

ブラック・ホワイトリスト

NginxやSELinuxを使った人がある人ならわかるかもしれません。

ブラックリストとは全アクセスを許容する中で特定のIPアドレスは例外で受け付けない様にするIPのリストです。

Telemetrics

分散トレーシング

CNCFプロジェクトであるJaegerを使っています。これは--set tracing.enabled=trueを指定することで設定できます。

記事の内容からそれるので、Jaegerそのものについては説明はしません。

マイクロサービスは複数のサービスで構成されているのでサービスを跨いで(分散して)処理したリクエストもトレースできるのが分散トレース。

https://jaeger.readthedocs.io/en/stable/images/spans-traces.png

以下のようになります。

www.jaegertracing.io

以下のようにしてポート転送をします。

kubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 16686:16686 &

すると以下の様な画面が出ます。

f:id:bobchan1915:20181006033924p:plain

GrafanaでIstioの監視

Grafanaを開くと一部だか、以下のようなダッシュボードがある。

Pilot Dashboard

f:id:bobchan1915:20181006022502p:plain

Wordload Dashboard

f:id:bobchan1915:20181006022526p:plain

以上のようなものがありIstio自体の監視をすることができます。

それ以外にもGrafanaはIstio本体だけではなくて、サービスメッシュも確認することができます。

f:id:bobchan1915:20181006022715p:plain

なぜかServiceMeshが出ていません、解決次第、修正します。

これはLinkerdのOverviewとよく似ています。

https://cdn-ak.f.st-hatena.com/images/fotolife/b/bobchan1915/20180930/20180930011557.png

サービスグラフによる可視化

これによってIstioメッシュのサービスのグラフを作成することができる。

以下のようにしてポート転送をします。

kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=servicegraph -o jsonpath='{.items[0].metadata.name}') 8088:8088 &

ここでhttp://localhost:8088/force/forcegraph.htmlにアクセスしてください。

f:id:bobchan1915:20181006041605p:plain

このようにサービス間と元のデプロイメントにpolicytelemetryが接続されていることがわかります。

クリーンアップ

Istioのアンインストール

以下のようにするとistioをアンインストールすることができます。

helm delete --purge istio

addons

先ほどもgrafanaを追加したように、デフォルトではインストールされないものがあります。

これはこのリストから選ぶことができます。

dependencies:
  - name: sidecarInjectorWebhook
    version: 1.0.1
    condition: sidecarInjectorWebhook.enabled
  - name: security
    version: 1.0.1
    condition: security.enabled
  - name: ingress
    version: 1.0.1
    condition: ingress.enabled
  - name: gateways
    version: 1.0.1
    condition: gateways.enabled
  - name: mixer
    version: 1.0.1
    condition: mixer.enabled
  - name: pilot
    version: 1.0.1
    condition: pilot.enabled
  - name: grafana
    version: 1.0.1
    condition: grafana.enabled
  - name: prometheus
    version: 1.0.1
    condition: prometheus.enabled
  - name: servicegraph
    version: 1.0.1
    condition: servicegraph.enabled
  - name: tracing
    version: 1.0.1
    condition: tracing.enabled
  - name: galley
    version: 1.0.1
    condition: galley.enabled
  - name: kiali
    version: 1.0.1
    condition: kiali.enabled
  - name: certmanager
    version: 1.0.1
    condition: certmanager.enabled

これを

-set [CONDITON]=[BOOL]

で渡すことによって有効化や無効化ができます。

まとめ

Istioは圧倒的にできることが多いので、学習コストが高いように感じた。

特にレイテンシなどを調査したいときに使うべきはLinkerdだなと感じた。