サービスメッシュを実現するIstioをEKS上で動かす - その2 EKSでサンプルを動かしてみる
山崎 雅斗
前回は、Minikubeを使ってKubernetesクラスタを作成し、それを使ってIstio上にサンプルアプリケーションをデプロイするというところまでやってみました。
今回はその続きとして、AWSのKubernetesマネージドサービスであるEKS上でBookinfoアプリケーションを動かすところをやっていきたいと思います。
シリーズ一覧
- まずはMinikubeでサンプルアプリケーションを動かしてみる
- EKSでサンプルを動かしてみる 👈 この記事
- EKSでRDSなど外部サービスと接続してみる
- データの可視化について
- 実運用中のサービスをIstioにのせてみる
- Datadogと連携する
EKSクラスタの作成
今回は、eksctlを使ってEKSクラスタを作成していきます。
まずは、次のコマンドでeksctlをインストールします。
$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
$ sudo mv /tmp/eksctl /usr/local/bin
また、後ほど kubectl
コマンドでEKSクラスタとやり取りができるように、次のコマンドでaws-iam-authenticatorも合わせてインストールしておきます(実行にはGoのビルド環境が必要です)。
$ go get -u -v github.com/kubernetes-sigs/aws-iam-authenticator/cmd/aws-iam-authenticator
準備ができたら、 eksctl
コマンドでEKSクラスタを作成していきます。
今回は東京リージョンにクラスタを作成したいので、 --region
オプションには ap-northeast-1
を指定します。
$ eksctl --region ap-northeast-1 create cluster --name istio-test-cluster
完了までは少し時間がかかりますが、最後に EKS cluster ... is ready
と出力されれば作成は成功です。
クラスタが作成できたら、 kubectl
コマンドがうまく実行できるか確認しておきます。
なお、 ~/.kube/config
は自動的に更新されるため、特に手動で変更する必要はありません。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-7-162-203.ap-northeast-1.compute.internal Ready <none> 29d v1.11.5
ip-10-7-163-236.ap-northeast-1.compute.internal Ready <none> 29d v1.11.5
Istioのインストール
ここまででEKSクラスタの準備ができたので、次はIstioをインストールしていきます。
前回はデモ用の設定で簡単にインストールしましたが、プロダクション環境で使用する場合はKubernetes用パッケージマネージャのHelmを使ってインストールするのが推奨されています。
そのため、今回はHelmを使ってIstioをインストールしていきます。
また、Minikubeの時と同様、事前に必要なファイル群をダウンロードしておく必要があります。
$ curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.1.1 sh -
$ cd istio-1.1.1
事前に helm
コマンドをインストールしておく必要があります。 helm
コマンドは、Github Releasesからダウンロードできます。
まず、Helmを使うためにKubernetesクラスタへTillerをインストールします。
Tiller用のService Account作成、Tillerのインストール、という手順で進めていきます。
$ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml
$ helm init --service-account tiller
次に、Istioをインストールするnamespaceを作成します。
$ kubectl create namespace istio-system
最後に、 helm install
コマンドでIstioをインストールします。
$ helm install install/kubernetes/helm/istio --name istio --namespace istio-system
ここまででIstioのインストールは完了ですが、default namespaceにデプロイしたサービスにSidecar Proxyを自動で配置してくれるようにlabelをつけておきます。
$ kubectl label namespace default istio-injection=enabled
Bookinfoアプリケーションのデプロイ
アプリケーションのデプロイ手順は、基本的にMinikubeと同様の手順で行います。
$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
アプリケーションのデプロイができたら、うまくできているかどうかを確認するため実際にアクセスしてみます。
Minikubeと違い、EKSの場合はロードバランサが使えるので、ロードバランサに対してHTTPリクエストを発行する形となります。
ロードバランサはIstio用のnamespace(今回であれば istio-system
)にServiceリソースとして登録されているので、下記コマンドで確認することができます。
$ kubectl get service istio-ingressgateway --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.20.188.72 xxxxxx.ap-northeast-1.elb.amazonaws.com 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:31283/TCP,8060:31547/TCP,853:30670/TCP,15030:32670/TCP,15031:30958/TCP 7m
istio-ingressgateway
の EXTERNAL-IP に対してリクエストを送ることで、Gatewayリソースの設定に応じてサービスメッシュ内のアプリケーションにアクセスできます。
前回見たように、Bookinfoアプリケーション用に作成したGatewayリソースはあらゆるホスト名にマッチするような設定となっています。Bookinfoアプリケーションは /productpage
というパスでアクセスできるので、 xxxxx.ap-northeast-1.elb.amazonaws.com/productpage
というURLにアクセスすることでBookinfoアプリケーション画面が表示されます。
トラフィックルーティングの設定
IstioのTraffic Managementの機能の概要を理解するため、簡単な設定を入れてみたいと思います。
今回設定する内容は次のとおりです。
- デフォルトでは、reviewsサービスは3つのバージョンの内v2にルーティングされる
- roundrobinユーザでログインした場合、reviews-v1 10%, reviews-v2 30%, reviews-v3 60% にルーティングされる
- v1: 星はなく、文字だけで表示される
- v2: 黒い星が表示されるようになる
- v3: 赤い星が表示されるようになる
まず、reviewsサービスのそれぞれのバージョンへのルーティング設定ができるようにするため、DestinationRuleリソースを作成します。下記のmanifestを適用すると、reviewsサービスのバージョンが3つ(v1、v2、v3)定義されます。
# define service subsets to use in VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: 'reviews.default.svc.cluster.local'
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
DestinationRuleリソースの spec.subsets
で、サービスのバージョンを定義することができます。こういったバージョンのことを、Istioでは subset と呼びます。
例えば下の定義では、ホスト名が reviews.default.svc.cluster.local
のPodの中で、 version=v1
というlabelを持つものが、reviewsサービスのv1として定義されます。
host: 'reviews.default.svc.cluster.local'
subsets:
- name: v1
labels:
version: v1
ルーティングの設定を行う
トラフィックのルーティング設定は、VirtualServiceリソースを使って設定します。ルーティングの設定は、 spec.http
以下に記述していきます。
ルーティングの設定は複数記述でき、上から順番に評価されていきます。マッチするものが見つかればそこで評価は終了するので、記述する順番にも気をつける必要があります。
今回はroundrobinユーザでログインしたときのみ3バージョンへルーティングさせたいので、まずその設定を書いていきます。
Bookinfoアプリケーションでは、ユーザ名が end-user
というヘッダに格納されるような仕様となっています。なので、このヘッダを確認してroundrobinとマッチしたときにのみ適用されるような設定を書くことになります。
roundrobinユーザ用の設定は次のようなものになります。 match
で end-user
ヘッダの値が意図するものかどうかを確認し、マッチした場合は route
の設定が適用されます。 route
以下にある weight
が、各バージョンへルーティングを振り分ける重みとなっており、すべてを足して100になるように設定する必要があります。
http:
- match:
- headers:
end-user:
exact: roundrobin
route:
- destination:
host: reviews.default.svc.cluster.local
subset: v1
weight: 10
- destination:
host: reviews.default.svc.cluster.local
subset: v2
weight: 30
- destination:
host: reviews.default.svc.cluster.local
subset: v3
weight: 60
最後は、roundrobinユーザ以外に適用される設定を書いていきます。特にマッチさせる条件がない場合は、 match
を省くことでこれまでの条件に当てはまらなかったすべてのリクエストに適用させることができます。
roundrobinユーザ以外はreviews-v2にルーティングしたいので、つぎのような設定となります。
- route:
- destination:
host: reviews.default.svc.cluster.local
subset: v2
これらを合わせた最終的なVirtualServiceリソースの設定は次のようになります。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- 'reviews.default.svc.cluster.local'
gateways:
- mesh
http: # この http 以下に、ルーティングの設定を定義
# match の条件に合致する通信は、 route 以下の定義に従ってルーティングされる
- match:
- headers:
end-user:
exact: roundrobin
route:
- destination:
host: reviews.default.svc.cluster.local
subset: v1 # この subset は、 DestinationRule で定義しているもの
weight: 10
- destination:
host: reviews.default.svc.cluster.local
subset: v2
weight: 30
- destination:
host: reviews.default.svc.cluster.local
subset: v3
weight: 60
# match がないので、ここに到達したすべての通信にマッチする
- route:
- destination:
host: reviews.default.svc.cluster.local
subset: v2
このVirtualServiceリソースを適用すると、roundrobinユーザでログインした場合は指定した重みで複数のバージョンにルーティングされ、その他のユーザの場合はv2にしかアクセスされないことが確認できるようになります。
mTLSの有効化
HelmでインストールしたIstioは、特に何もオプションを与えない限り、mTLSが無効になっています。
ここでは、Istioのインストール後にmTLSを有効にし、アプリケーションを正常に動かすための設定について見ていきます。
サービスメッシュ全体でmTLSを有効化する
サービスメッシュ全体でmTLSを有効にするには、 MeshPolicy
リソースを作成します。
apiVersion: authentication.istio.io/v1alpha1
kind: MeshPolicy
metadata:
name: default
spec:
peers:
- mtls: {}
これを適用すると、mTLSなしでサービスへリクエストを投げた場合は 503
が返ってくるようになります。
なお、上のように MeshPolicy
リソースを使用するとサービスメッシュ全体でmTLSが有効になりますが、特定のnamespaceだけで有効にしたい場合は変わりに Policy
リソースを使用します。この場合、PolicyリソースがあるnamespaceのみでmTLSが有効となります。
例えば、default namespaceのみでmTLSを有効にするには次のようなmanifestを適用します。
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
メッシュ内のサービス間通信でmTLSを有効化する
次に、サービスごとにDestinationRule内でmTLSを有効にするための設定を作成する必要があります。
しかし、サービスごとに一つ一つ作成するのは面倒なので、ワイルドカードを使ってdefault namespaceの全サービスに適用させることにします。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: default
namespace: default
spec:
host: "*.local" # *.localにマッチするすべてのホスト(サービス)が対象となる
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
trafficPolicy.tls.mode
に ISTIO_MUTUAL
を設定すると、Istioが証明書や秘密鍵を勝手に管理してくれるようになります。これで、 特にサービスごとにDestionationRuleリソースを作成していない場合は このDestinationRuleリソースがデフォルトとして適用され、mTLSが有効になります。例えば、Bookinfoアプリケーションでは3つの異なるバージョンreviewsにルーティングさせるため、DestinationRuleリソースをすでに作成しています。そのため、今回作成したDestinationRuleリソースはreviewsサービスには適用されず、reviewsへのリクエストはmTLSが使われずに失敗してしまいます。
reviewsのように個別でDestinationRuleリソースを作成しているサービスは、そのDestinationRuleリソースにも上と同様 trafficPolicy.tls.mode
を ISTIO_MUTUAL
に設定する必要があります。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: 'reviews.default.svc.cluster.local'
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
# このように個別でmTLSの設定が必要となる
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
メッシュ外のサービスからメッシュ内のサービスに接続する
mTLSを有効にしたサービスメッシュでは、メッシュ外のサービスからメッシュ内のサービスへのリクエストは 失敗します 。
現状でこれを防ぐ手立てはなく、必要な部分だけmTLSをオフにする等、認証のレベルを下げる他に対応策はないようです。
メッシュ内のサービスからメッシュ外のサービスに接続する
mTLSを有効にしたサービスメッシュからメッシュ外のサービスに接続すると、デフォルトでは失敗します。
正常に接続を行うには、メッシュ外のサービスに対して個別にmTLSを無効にする設定が必要となります。
例として、kube-apiserverに接続する時に必要となる設定は次のようになります。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: "api-server"
spec:
host: "kubernetes.default.svc.cluster.local"
trafficPolicy:
tls:
mode: DISABLE
このように、 trafficPolicy.tls.mode
を DISABLE
にすることで、mTLSを無効にすることができます。
まとめ
今回は、EKS上にIstioをインストールし、Bookinfoアプリケーションをデプロイしました。Bookinfoアプリケーションを利用して、簡単なトラフィックルーティングの設定やmTLSの設定等を試してみました。
Istioのサービスメッシュ上にデプロイしたアプリケーションはメッシュ外とのサービスにももちろんアクセスできますが、デフォルトのままだとうまくいきません。次回はそのあたりを実際に試していきたいと思います。