OpenShift Origin 3.7でIstioを動かす

このエントリは Kubernetes Advent Calendar 2017 - Qiita の12/8分です。(ちょっとハマってしまって公開が遅くなってすみません。)

2017/11/30にOpenShift3.7がGAになりました。OpenShift3.7はKubernetes1.7ベースなのでようやくIstioが普通に動かせるようになりましたが、デフォルトのセキュリティ設定が厳し目になっていることもあり、適切な権限設定をしてやらないと動きません。そこで、こちらの情報を参考に、minishiftから起動したOpenShift Origin 3.7上でIstioのbookinfoサンプルを動かす手順を紹介します。
blog.openshift.com

注意) OpenShift3.7はまだIstioを正式にサポートしていませんが、将来のバージョンでサポートする予定になっています。現時点ではRed Hatにお問い合わせいただいてもサポートできかねますのでご了承ください。

なお、以下手順はすべてmacOS Sierra(10.12.6)で動作確認しています。

minishiftインストール手順 for macOS

homebrewで入れますので、入っていなければ事前にインストールしておいてください。

xhyve driverインストール

minishiftから起動するVMをxhyveにするために入れておきます。

$ brew install docker-machine-driver-xhyve
$ sudo chown root:wheel $(brew --prefix)/opt/docker-machine-driver-xhyve/bin/docker-machine-driver-xhyve
$ sudo chmod u+s $(brew --prefix)/opt/docker-machine-driver-xhyve/bin/docker-machine-driver-xhyve

minishiftインストール

minishiftの本体です。ローカルマシン上でOpenShift Originを起動するのに使います。

$ brew cask install minishift

詳細: Installing Minishift - Getting Started | Minishift | OpenShift Origin Latest

ocコマンドインストール

OpenShiftのCLIです。(Kubernetesでのkubectl相当)

$ brew install openshift-cli

minishiftの基本的なオペレーション

minishift起動

$ minishift start

minishift VMのIP確認

$ minishift ip

Webコンソールアクセス

$ minishift console 
$ minishift console —url  #url表示のみ

CLIログイン

$ oc login -u developer -p developer  #一般ユーザー
$ oc login -u admin -p admin  #管理ユーザー(cluster-admin)

Istio環境構築

OpenShift Origin 3.7起動 on minishift

$ minishift start --openshift-version v3.7.0 --iso-url centos --cpus 4 --memory 8GB --disk-size 40GB

CentOS7のVM上にOpenShift Origin 3.7を起動します。
CPU/MEM/DISKは環境に合わせて適宜調整してください。MEMはなるべく多めに確保しておいたほうがうよいです。

Istio稼働用環境設定

Istioをデプロイするためのプロジェクトを作成し、必要な権限を設定しておきます。(ほぼザル設定。。。)

$ oc login -u admin -p admin
$ oc new-project istio-system 
$ oc project istio-system 
$ oc adm policy add-scc-to-user anyuid -z istio-ingress-service-account 
$ oc adm policy add-scc-to-user privileged -z istio-ingress-service-account 
$ oc adm policy add-scc-to-user anyuid -z istio-egress-service-account 
$ oc adm policy add-scc-to-user privileged -z istio-egress-service-account 
$ oc adm policy add-scc-to-user anyuid -z istio-pilot-service-account 
$ oc adm policy add-scc-to-user privileged -z istio-pilot-service-account 
$ oc adm policy add-scc-to-user anyuid -z default 
$ oc adm policy add-scc-to-user privileged -z default 
$ oc adm policy add-cluster-role-to-user cluster-admin -z default

Istioインストール

istioctlコマンドおよびサンプルコードをインストールしておきます。

$ curl -L https://git.io/getLatestIstio | sh - 
$ ISTIO_HOME=$(pwd)/$(ls | grep istio) 
$ export PATH="$PATH:$ISTIO_HOME/bin" 
$ cd $ISTIO_HOME 
$ oc apply -f install/kubernetes/istio.yaml

関連プロダクトのデプロイ

PrometheusやGrafanaなど、モニタリングに利用するプロダクトをデプロイします。

$ oc create -f install/kubernetes/addons/prometheus.yaml 
$ oc create -f install/kubernetes/addons/grafana.yaml 
$ oc create -f install/kubernetes/addons/servicegraph.yaml 
$ oc create -f install/kubernetes/addons/zipkin.yaml 
$ oc expose svc grafana 
$ oc expose svc servicegraph 
$ oc expose svc zipkin

また、この後の作業用に、各プロダクトのURLを環境変数を設定しておきます。

$ SERVICEGRAPH=$(oc get route servicegraph -o jsonpath='{.spec.host}{"\n"}')/dotviz
$ GRAFANA=$(oc get route grafana -o jsonpath='{.spec.host}{"\n"}')
$ ZIPKIN=$(oc get route zipkin -o jsonpath='{.spec.host}{"\n"}')

bookinfoサンプルアプリケーションのデプロイ

サンプルアプリケーションは $ISTIO_HOME/samples/bookinfo 以下にあります。このエントリでは触れませんが、他にもサンプルがあるので試してみてください。

インストール

$ cd $ISTIO_HOME
$ oc apply -f <(istioctl kube-inject -f samples/bookinfo/kube/bookinfo.yaml) 
$ oc expose svc productpage

本当はプロジェクトを分けたいところですが、ちと面倒なのでまずはistio-systemプロジェクト内にデプロイしてしまいます。
デプロイ完了まで少し時間がかかるので、以下コマンドを実行して放置しておきましょう。

$ PRODUCTPAGE=$(oc get route productpage -o jsonpath='{.spec.host}{"\n"}') 
$ watch -n 1 curl -o /dev/null -s -w %{http_code} $PRODUCTPAGE/productpage

200が返ってくるようになったら起動完了です。

起動確認

念のため、すべてのPodがRunning状態になっているか確認します。

$ oc get po
NAME                              READY     STATUS    RESTARTS   AGE
details-v1-2818760093-rfsvf       2/2       Running   0          8m
grafana-2460282047-df7kt          1/1       Running   0          17m
istio-ca-293181461-bkvqw          1/1       Running   0          22m
istio-egress-2098918753-xwrzp     1/1       Running   0          22m
istio-ingress-3288103321-fnwcd    1/1       Running   0          23m
istio-mixer-4195966866-ssbr4      2/2       Running   0          23m
istio-pilot-1168925427-c5qq8      1/1       Running   3          23m
productpage-v1-1172091313-99m8f   2/2       Running   0          8m
prometheus-4086688911-7ztkb       1/1       Running   0          17m
ratings-v1-3016823457-cdhn9       2/2       Running   0          8m
reviews-v1-3334602649-msgkb       2/2       Running   0          8m
reviews-v2-2474208031-t8rfj       2/2       Running   0          8m
reviews-v3-471783377-ms9k7        2/2       Running   0          8m
servicegraph-4072321759-h7ccm     1/1       Running   0          17m
zipkin-3660596538-kmlsd           1/1       Running   0          17m

起動に失敗しているPodがあったら、ログやイベントで原因を確認しましょう。

bookinfoアプリケーションでIstioの機能を確認

単純ルーティング

$ open http://$PRODUCTPAGE

"Normal user"をクリックすると一般ユーザー向けの画面が表示されます。適当にリロードすると、赤星(v3)/黒星(v2)/星無し(v1)の3種類の画面がランダムに表示され、バックエンドのReviewサービスの各バージョンにランダムにルーティングされていることが確認できます。
f:id:nobusue:20171211053151p:plain
f:id:nobusue:20171211053224p:plain

サービスグラフ

$ open http://$SERVICEGRAPH

サービスの呼び出し経路と、レスポンスタイムなどの統計情報が確認できます。
f:id:nobusue:20171211053257p:plain

メトリクスモニタリング

$ open http://$GRAFANA

ダッシュボード"Istio"を選択すると、サービスに関する各種メトリクスを可視化することができます。便利。
f:id:nobusue:20171211053345p:plain

分散トレース

$ open http://$ZIPKIN

検索条件を指定して"find trace"を実行すると、サービス呼び出しの履歴やコールツリーを確認できます。
f:id:nobusue:20171211053410p:plain

インテリジェントルーティング

細かい条件を指定してルーティングを制御できます。ここではratingsサービスに対して、デフォルトではv1へ、ユーザー"jason"のみv2へルーティングしてみます。

$ oc create -f samples/bookinfo/kube/route-rule-all-v1.yaml 
$ oc create -f samples/bookinfo/kube/route-rule-reviews-test-v2.yaml
$ oc get routerule -o yaml

ログインしていない状態では星なし(v1)のページしか見えなくなりますが、jasonでログインすると黒星(v2)が見えます。

ディレイ

httpFaultを利用して意図的な遅延を挿入することができます。障害時の動作をエミュレートするときなどに有用です。
ここではratingsにjasonユーザーのみ7secのdelayを挿入しています。

oc create -f samples/bookinfo/kube/route-rule-ratings-test-delay.yaml

アクセスしてみると、jason以外のユーザーには影響がないことが確認できます。

タイムアウト

httpReqTimeoutを指定することで、サービス呼び出しのタイムアウトを設定することができます。

重み付きバージョンルーティング

サービスのバージョン毎に重みを指定してリクエストを分散できます。
ここでは、reviewsサービスに対するデフォルトのルーティングルールをv1:v3=50:50に変更しています。

$ cat samples/bookinfo/kube/route-rule-reviews-50-v3.yaml 
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1
    weight: 50
  - labels:
      version: v3
    weight: 50

$ oc replace -f samples/bookinfo/kube/route-rule-reviews-50-v3.yaml

クォータ

サービス呼び出しのrate limitを設定できます。memquotaオブジェクトで設定値を指定し、quataオブジェクトでカウント方法を指定、ruleオブジェクトでmemquotaとquataを結びつけます。

$ cat samples/bookinfo/kube/mixer-rule-ratings-ratelimit.yaml 
apiVersion: "config.istio.io/v1alpha2"
kind: memquota
metadata:
  name: handler
  namespace: istio-system
spec:
  quotas:
  - name: requestcount.quota.istio-system
    maxAmount: 5000
    validDuration: 1s
    # The first matching override is applied.
    # A requestcount instance is checked against override dimensions.
    overrides:
    # The following override applies to 'ratings' when
    # the source is 'reviews'.
    - dimensions:
        destination: ratings
        source: reviews
      maxAmount: 1
      validDuration: 1s
    # The following override applies to 'ratings' regardless
    # of the source.
    - dimensions:
        destination: ratings
      maxAmount: 100
      validDuration: 1s

---
apiVersion: "config.istio.io/v1alpha2"
kind: quota
metadata:
  name: requestcount
  namespace: istio-system
spec:
  dimensions:
    source: source.labels["app"] | source.service | "unknown"
    sourceVersion: source.labels["version"] | "unknown"
    destination: destination.labels["app"] | destination.service | "unknown"
    destinationVersion: destination.labels["version"] | "unknown"

---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
  name: quota
  namespace: istio-system
spec:
  actions:
  - handler: handler.memquota
    instances:
    - requestcount.quota

$ oc create -f samples/bookinfo/kube/mixer-rule-ratings-ratelimit.yaml

Egressルーティング

Istio proxyをインジェクトしたサービス(Istio-enabledなサービス)は、デフォルトではクラスタ外のURLにアクセスできません。外部アクセスが必要な場合は、EgressRuleを設定します。EgressRuleで定義したRouteに対して、RouteRuleのhttp_req_timeoutを指定することも可能。
外向けトラフィックのsource IPをegress routerで指定することや、-includeIPRangesフラグを指定することで istioctl kubectl-inject で注入するenvoy sidecarコンテナのCIDRを指定することもできます。

アクセスコントロール

ルールによる明示的なアクセス拒否や、ホワイトリスト方式によるアクセス拒否ができます。

まとめ

マイクロサービスをプロダクション運用する場合、従来であればNetflix OSSなどがよく使われていましたが、「Javaに限定される」「アプリケーションコードに非機能要件が入り込む」という課題がありました。
Istioのようなサービスメッシュ層を設けることで、実装言語によらずに、マイクロサービスの運用や問題判別に必要な機能を外付けすることができるようになります。特にKubernetesのPodとの相性が良いので、今後はIstio+Kubernetesの組み合わせでマイクロサービスをデプロイすることが多くなりそうです。