Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、Istioの環境構築と実践ポイントを説明します。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。今回は、前回の「サービスメッシュ」や「Istio」の概要の紹介に続き、Istioの環境構築と実践ポイントを説明します。
Istioのインストールについては、Istio公式サイト(Getting Startedページ)でも書かれているので、興味がある方はご覧ください。
今回は、下記の環境でインストールしました。
対象 | 説明 | 動作確認で利用した環境 |
---|---|---|
Kubernetes | 「Azure Kubernetes Service」(AKS)や「Google Kubernetes Engine」(GKE)などのクラウドのマネージドサービス環境や「minikube」などのローカル環境おけるKubernetesクラスタ | AKS(v1.21) GKE(v1.21) minikube(v1.21) |
Istio | サービスメッシュソフトウェア | v1.11.3 |
Istioを利用するには、「istioctl」を用いる方法、連載第8回で紹介した「Operator」を利用する方法、CLIによりマニフェストファイルを生成する方法、連載第3回で紹介した「Helm」を利用する方法がありますが、ここではIstio公式サイト(Install with Istioctlページ)に沿ってistioctlを用いる方法を説明します。
最初にIstioの設定を管理するistioctlを下記コマンドでダウンロードします。
# 最新版を使用する場合 $ curl -L https://istio.io/downloadIstio | sh - # バージョン、プロセッサアーキテクチャを指定する場合 $ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.11.3 TARGET_ARCH=x86_64 sh -
ダウンロードしたIstioリリースパッケージは次のディレクトリで構成されています。
階層構造は下記のようになっています。
$ tree -L 2 istio-1.11.3 istio-1.11.3 ├── LICENSE ├── README.md ├── bin │ └── istioctl # istioctl ├── manifest.yaml ├── manifests # helmチャートやistioctlを使用したインストールの構成ファイルが含まれる │ ├── charts │ ├── examples │ └── profiles ├── samples # サンプルアプリケーションが含まれる │ ├── README.md │ ├── addons │ ├── bookinfo │ ├── certs │ ├── custom-bootstrap │ ├── extauthz │ ├── external │ ├── health-check │ ├── helloworld │ ├── httpbin │ ├── jwt-server │ ├── kubernetes-blog │ ├── multicluster │ ├── operator │ ├── ratelimit │ ├── security │ ├── sleep │ ├── tcp-echo │ └── websockets └── tools # istioctlのbash-completionが含まれる ├── _istioctl ├── certs └── istioctl.bash
istioctlを実行してコマンドが機能することを確認します。
# 事前にコマンドのパスを通しておく $ cd ./istio-1.11.3 $ export PATH=$PWD/bin:$PATH $ istioctl version no running Istio pods in "istio-system" 1.11.3
Kubernetesクラスタで前提条件(バージョンなど)が満たされていることを確認します。下記コマンドで確認できます。
$ istioctl x precheck レ No issues found when checking the cluster. Istio is safe to install or upgrade! To get started, check out https://istio.io/latest/docs/setup/getting-started/
問題がなければ、istioctlで使用するインストールオプションを確認します。今回は、Istioで事前に準備されているチュートリアル実行用のConfiguration Profileを利用します。
Configuration Profileは、istioctlから呼び出して使用できるインストールオプションです。「manifests/profiles」配下に設定ファイルが格納されており、自身でカスタマイズすることもできます。事前に用意されているファイルは下記コマンドで確認できます。
$ istioctl profile list Istio configuration profiles: default demo empty external minimal openshift preview remote
事前に準備されたConfiguration Profileを用いて導入できる主要なコンポーネントは下表の通りです。
Profile | default | demo | empty | minimal |
---|---|---|---|---|
istio-egressgateway | - | ○ | - | - |
istio-ingressgateway | ○ | ○ | - | - |
istiod | ○ | ○ | - | ○ |
grafana | - | - | - | - |
istio-tracing | - | - | - | - |
kiali | - | - | - | - |
prometheus | - | - | - | - |
なお、事前に準備されたConfiguration ProfileはIstioのバージョンによって内容が異なる場合があるので、Istio公式サイト(Installation Configuration Profilesページ)で確認することをお勧めします。v1.6までのIstioのConfiguration Profileには、「Prometheus」などのObservabilityに関連したアドオンが含まれていましたが、現在のバージョンでは個別にインストールする必要があります。
これらのObservabilityに関するアドオンについては、後述します。
最初にConfiguration Profileに基づいてインストールする方法を解説します。設定をカスタマイズする方法については、次節で解説します。
ここでは、チュートリアル実行用のConfiguration Profileである「demo」を使用して、「egressgateway」「ingressgateway」「istiod」をインストールします。
# istioctlを利用したインストールコマンド $ istioctl install --set profile=demo -y レ Istio core installed レ Istiod installed レ Egress gateways installed レ Ingress gateways installed レ Installation complete Thank you for installing Istio 1.11.Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/kWULBRjUv7hHci7T6
「Installation complete」が表示されれば完了です。Istioのリソースがデプロイされているかどうかを確認します。
$ kubectl get namespace NAME STATUS AGE default Active 84m istio-system Active 9m2s kube-node-lease Active 84m kube-public Active 84m kube-system Active 84m $ kubectl get all -n istio-system NAME READY STATUS RESTARTS AGE pod/istio-egressgateway-7d4f75956-fbcdd 1/1 Running 0 9m44s pod/istio-ingressgateway-5d57955454-bsghf 1/1 Running 0 9m44s pod/istiod-6f6c6bbbbd-rjw7b 1/1 Running 0 10m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/istio-egressgateway ClusterIP 10.0.28.8 <none> 80/TCP,443/TCP 9m44s service/istio-ingressgateway LoadBalancer 10.0.176.115 20.191.174.190 15021:31626/TCP,80:31349/TCP,443:31180/TCP,31400:31562/TCP,15443:31901/TCP 9m44s service/istiod ClusterIP 10.0.52.158 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 10m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/istio-egressgateway 1/1 1 1 9m44s deployment.apps/istio-ingressgateway 1/1 1 1 9m44s deployment.apps/istiod 1/1 1 1 10m NAME DESIRED CURRENT READY AGE replicaset.apps/istio-egressgateway-7d4f75956 1 1 1 9m44s replicaset.apps/istio-ingressgateway-5d57955454 1 1 1 9m44s replicaset.apps/istiod-6f6c6bbbbd 1 1 1 10m
上記からegressGateway、ingressgateway、istiodがデプロイされていることが確認できます。
続いて、インストールしたIstioの正常性を確認します。「istioctl verify-install」コマンドを使うことで、インストール時に指定した設定ファイルと比較できます。
$ istioctl verify-install 1 Istio control planes detected, checking --revision "default" only <中略> レ Istio is installed and verified successfully
「Istio is installed and verified successfully」が確認できれば、インストールは完了です。
先ほどの手順では、事前に用意されたdemo用のConfiguration Profileをそのままインストールしました。しかし環境によっては、用意された値ではなく、構成のカスタマイズが必要なケースも出てきます。例えば、Ingressgatewayコンポーネントでは、「Service」の「LoadBalancer」を利用しますが、パブリッククラウドで提供されるマネージドKubernetes環境ではなく、自前でKubernetesを構築した場合、Service:LoadBalancerは環境によっては利用できないので、NodePortを利用する必要があります。
今回は、構成をカスタマイズする一例として、IngressgatewayをNodePortで起動する方法を紹介します。
なお、この手順は必須ではないので、まずはdemo用のConfiguration Profileのまま試したい方は、サンプルアプリケーションのデプロイから手順を進めてください。
簡単なカスタマイズ方法として、istioctlコマンドに「--set」オプションを与えることで設定を追加できます。
# --set引数を使用して、ワンライナーでNodePortに変更 $ istioctl install --set profile=demo --set values.gateways.istio-ingressgateway.type=NodePort -y
この方法は、少しの変更には適していますが、設定の変更履歴を管理したり、設定を変更した部分の差分を確認したりすることには適していません。
公式ドキュメントではマニフェストファイルを事前に作成する方法を推奨しているので、それらの方法を確認します。
商用環境で構成を管理する場合には、「IstioOperatorAPI」を使用したマニフェストファイルの適用をお勧めします。
Istio Operatorは、Istioの構成管理を行うKubernetesのカスタムリソースです。「base」「pilot」「ingressGateways」「egressGateways」「cni」「istiodRemote」というIstioのコンポーネントの構成を管理します。istioctlコマンドでは、コマンドラインオプションやマニフェストファイルを渡すことでIstioOperatorの全APIを使用できるので、マニフェスト形式でIstioコンポーネントに対して有効化の設定やKubernetes設定(レプリカ数など)をカスタマイズすることが可能です。
変更可能なKubernetesリソースに関しては、Istio公式サイト(Customize Kubernetes settingsページ)をご覧ください。
・設定ファイルの編集
「manifests/profiles」配下のファイルとIstio公式サイト(IstioOperator Optionsページ)を参考にYAMLを編集します。「ingressgateway」は、デフォルトでは、「type: LoadBalancer」として起動するので、明示的に設定を変更する必要があります。
apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: components: ingressGateways: - name: istio-ingressgateway enabled: true # istio-ingressgatewayを有効にする k8s: # k8s配下でKubernetesリソースに関する設定を変更する service: type: NodePort # ServiceリソースをNodePortに変更する ports: - name: status-port port: 15021 targetPort: 15021 - name: http2 port: 80 targetPort: 8080 - name: https port: 443 targetPort: 8443 - name: tcp port: 31400 targetPort: 31400 - name: tls port: 15443 targetPort: 15443
先ほどのインストール手順でも使用したdemo用のConfiguration Profileをベースに作成したマニフェストファイルで上書きする形で構成を反映できます。
・設定の差分確認
下記のようなケースで、Istioの設定の差分を確認したいことがあります。
「istioctl manifest generate」を利用すると、Istioのデプロイ内容が、kubectlコマンドでデプロイ可能なKubernetesのマニフェスト形式として出力されます。通常のKubernetesのマニフェストになるので、IstioOperatorのYAMLと比べて「何がデプロイされるのか」「何が変更されるのか」を確認するのも容易になります。
差分を確認します。コマンド自体はistioctl installに似た形式で、参照するProfileを指定すると、そのProfileでデプロイされるリソースがマニフェスト形式で出力されます。
# samdemo-LB.yamlにKubernetesのマニフェスト形式で出力する(設定変更前) $ istioctl manifest generate --set profile=demo > ./demo-LB.yaml
こちらのマニフェストを「kubectl apply」コマンドで適用することも可能ですが、Istioのリリースではテストされていないので、注意が必要です。詳細については、Istio公式サイト(Generate a manifest before installationページ)を参照してください。
先ほど作成した「ingressgateway_NodePort.yaml」をdemo用のConfiguration Profileに上書きする形でKubernetesのマ二フェストを生成し、先ほど出力した設定変更前のマニフェストと比較しましょう。
# demo_nodePort.yamlにKubernetesのマニフェスト形式で出力する(設定変更後) $ istioctl manifest generate --set profile=demo -f ./ingressgateway_NodePort.yaml > ./demo_nodePort.yaml # 設定内容の比較 $ istioctl manifest diff ./demo-LB.yaml ./demo_nodePort.yaml Differences in manifests are: Object Service:istio-system:istio-ingressgateway has diffs: spec: type: LoadBalancer -> NodePort # NodePortに変更されたことを確認
このようにKubernetesのマ二フェスト形式で設定ファイルを作成しておくことで、設定変更の際の差分を取得できるので便利です。
・マニフェストファイルを使用したインストール
変更前後の差分を含めた設定の確認ができたので、インストールします。先ほどのマニフェスト作成時と同様、demo用のConfiguration Profileに上書きする形でインストールすることが可能です。
$ istioctl install --set profile=demo -f ./ingressgateway_NodePort.yaml -y
Ingress-gatewayがNodePortで起動していることを確認できます。
$ kubectl get service -n istio-system NNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-egressgateway ClusterIP 10.103.226.217 <none> 80/TCP,443/TCP 14m istio-ingressgateway NodePort 10.99.169.3 <none> 15021:30546/TCP,80:30793/TCP,443:32307/TCP,15443:30778/TCP 14m istiod ClusterIP 10.99.185.134 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 14m
「service/istio-ingressgateway」が「type: NodePort」で起動していることが確認できました。必要な構成に限定してカスタマイズ可能であり、設定をyamlファイルで保持できるので、最も適用しやすい方法といえるでしょう。
Istioは稼働するコンポーネントも多く運用が難しい点もありますが、このようにさまざまな方法でカスタマイズしてインストールすることも可能なので、ぜひ試してみてください。
サンプルアプリケーションをデプロイします。今回は、samples配下に用意されているBookinfoアプリケーションを使用します。
Istioに導入する前の構成を確認します。
Bookinfoアプリケーションは、4つのマイクロサービスから構成されています。「productpage」サービスが一番外側でリクエストを受け付け、2つのサービス「reviews」「details」と連携し、reviewsは「ratings」サービスとも連携するという構成です。reviewsサービスは異なる3つのバージョンが存在します。
Bookinfoアプリケーションは、trace-idをheaderに伝搬する処理も実装されているので、Istioを使用した監視、トレーシングを検証したい方にお薦めのアプリケーションです。
アプリケーションをデプロイします。
# 上記でistio-ingressgatewayをLoadBalancerに戻しておきます(手順上、LoadBlancerで実行するので) istioctl install --set profile=demo -y # namespace:defaultにBookinfoアプリケーションをデプロイ $ kubectl apply -f ./samples/bookinfo/platform/kube/bookinfo.yaml
インストール後のアプリケーションの状態は下記のようになります。ここでは、まだサイドカープロキシを挿入していないので、READY欄の数が1であることを確認してください。
$ kubectl get pod NAME READY STATUS RESTARTS AGE details-v1-79f774bdb9-c6q5h 1/1 Running 0 2m6s productpage-v1-6b746f74dc-hz6g9 1/1 Running 0 2m6s ratings-v1-b6994bb9-bg6pd 1/1 Running 0 2m6s reviews-v1-545db77b95-g76dp 1/1 Running 0 2m6s reviews-v2-7bf8c9648f-kx6rg 1/1 Running 0 2m6s reviews-v3-84779c7bbc-j8kvm 1/1 Running 0 2m6s $ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE details ClusterIP 10.0.183.197 <none> 9080/TCP 3m38s kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 113m productpage ClusterIP 10.0.41.43 <none> 9080/TCP 3m38s ratings ClusterIP 10.0.167.111 <none> 9080/TCP 3m38s reviews ClusterIP 10.0.5.210 <none> 9080/TCP 3m38s # ラベル(app=ratings)を付与されたPodからproductpageに対してHTTPリクエストを送信し、タイトルページを表示 $ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title> # 出力結果
このようにページのタイトルが表示できれば、デプロイ完了です。
kubectlコマンドは、JSONPathのテンプレートをサポートしているので、結果を取得するときにはJSONPathを使って特定の内容を抽出できます。
BookinfoアプリケーションにHTTPリクエストを送信した際のコマンドを例に確認してみましょう。「kubectl get pods」のように複数オブジェクトを対象とした操作をした場合、下記のようなデータ構造になっています。
# ラベル(app=ratings)を付与されたPod情報をYAML形式で出力 $ kubectl get pod -l app=ratings -o yaml # もちろん、同様にjson形式でも確認できる $ kubectl get pod -l app=ratings -o json
JSONでもYAML形式でもどちらでもデータ構造が確認可能ですが、今回はYAML形式で確認します。
# YAML形式でのPod情報 apiVersion: v1 items: - apiVersion: v1 kind: Pod metadata: annotations: kubectl.kubernetes.io/default-container: ratings kubectl.kubernetes.io/default-logs-container: ratings <中略> name: ratings-v1-b6994bb9-bg6pd # ここの情報を抽出
items配下でPod単位に配列になっていることを確認できます。この配列からPod名のみを抽出したい場合、構造を基に「'{.items[*].metadata.name}'」と記述すると、items配下の全配列からmetadata内のname情報を指定できます。
今回は、ラベル(app=ratings)を付与されたPodが1つしかないので、最初の配列から抽出するように指定します。
# ラベル(app=ratings)を付与されたPodのうち、最初の配列にあるPod名を抽出 $ kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}' ratings-v1-b6994bb9-bg6pd # もちろんjqでも同様に抽出できる $ kubectl get pod -l app=ratings -o json | jq -r '.items[0].metadata.name' ratings-v1-b6994bb9-bg6pd
このようにJSONPathを使うことで、ちょっとしたコマンド数の削減ができます。
JSONPathのサポート、kubectlチートシートを参考に使いこなしてください。
準備が完了したので、ここからはIstioの機能を有効化します。
サンプルアプリケーションをデプロイしましたが、現時点では各PodにはIstioのサイドカープロキシ(Envoy)は含まれていません。Istioのサイドカープロキシを挿入するには、「istioctl kube-inject」コマンドを使います。
次のように実行することで、サイドカープロキシの情報を付与したマニフェストファイルを適用できます。
$ istioctl kube-inject -f ./samples/bookinfo/platform/kube/bookinfo.yaml | kubectl apply -f -
正常にデプロイが完了したら、サイドカープロキシが挿入できたかどうかを確認します。「kubectl get pod」コマンドでREADY欄が2になっていることを確認してください。先ほどは、Pod内にはBookInfoアプリケーションのみが存在していました(READY欄は1でした)が、サイドカープロキシを含んだ2つのコンテナが稼働しています(READY欄が2になりました)。
# READY欄が2になり、サイドカープロキシの起動を確認できる $ kubectl get pod NAME READY STATUS RESTARTS AGE details-v1-6b76c6bdbc-7rk7k 2/2 Running 0 90s productpage-v1-5f7776bcd-mfcqj 2/2 Running 0 90s ratings-v1-5bd6b8fb6c-ln54r 2/2 Running 0 90s reviews-v1-b859999c7-bj8hq 2/2 Running 0 90s reviews-v2-944fb57c4-xvcsv 2/2 Running 0 90s reviews-v3-649947b5b7-f9zph 2/2 Running 0 90s
しかし、アプリケーションをデプロイするたびに「istioctl kube-inject」コマンドを実行するのは手間がかかります。自動でサイドカープロキシを挿入する設定を入れます。自動挿入の対象としたいnamespaceに対して「istio-injection=enabled」というラベルを付与することで、Istioが検知し、サイドカープロキシが自動で挿入されるようになります。
新しく作成したnamespaceでサイドカープロキシの自動導入を有効化し、アプリケーションをデプロイします。
# 新規でnamespace:sample-appを作成 $ kubectl create namespace sample-app namespace/sample-app created # istio-injection=enabled ラベルを付与 $ kubectl label namespace sample-app istio-injection=enabled namespace/sample-app labeled # istio-injection=enabled ラベルが付与されていることを確認 $ kubectl get ns sample-app --show-labels NAME STATUS AGE LABELS sample-app Active 2m36s istio-injection=enabled,kubernetes.io/metadata.name=sample-app $ kubectl apply -f ./samples/bookinfo/platform/kube/bookinfo.yaml -n sample-app <省略> # READY欄が2になり、サイドカープロキシの起動を確認できる $ kubectl get pod -n sample-app NAME READY STATUS RESTARTS AGE details-v1-79f774bdb9-6v2h2 2/2 Running 0 60s productpage-v1-6b746f74dc-795kd 2/2 Running 0 60s ratings-v1-b6994bb9-95l82 2/2 Running 0 60s reviews-v1-545db77b95-lc9g9 2/2 Running 0 60s reviews-v2-7bf8c9648f-kz7fl 2/2 Running 0 60s reviews-v3-84779c7bbc-9rfrp 2/2 Running 0 60s
こちらの方法でもPod内で起動するコンテナ数が2つになり、サイドカープロキシが挿入できたことを確認できました。再度、Bookinfoアプリケーションにアクセスできることを確認します。
# namespace:sample-appで、ラベル(app=ratings)を付与されたPodからproductpageに対してリクエストを発行 $ kubectl exec "$(kubectl get pod -n sample-app -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -n sample-app -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title>
サイドカープロキシが挿入されると、各通信は下図のようにサイドカープロキシのEnvoyを経由することになります。
サイドカープロキシを経由するので、通信ログもサイドカープロキシのログから確認できます。先ほどアクセスした「productpage」のサイドカーのログを見てみましょう。アクセスログは、「istio-proxy」を指定することで表示可能です。なお、アクセスログに関しては下記で設定可能です。
# ラベル(app=productpage)を付与されたPodのサイドカー(istio-proxy)のログを表示 $ kubectl logs -n sample-app "$(kubectl get pod -n sample-app -l app=productpage -o jsonpath={.items..metadata.name})" -c istio-proxy | tail -5 2021-10-03T09:31:12.250080Z info Initialization took 1.999170456s 2021-10-03T09:31:12.250628Z info Envoy proxy is ready [2021-10-03T09:31:58.532Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 33 33 "-" "curl/7.52.1" "535a16d8-1a7b-9f4f-8d25-810ac82988f6" "details:9080" "172.16.4.47:9080" outbound|9080||details.sample-app.svc.cluster.local 172.16.4.14:52976 10.0.216.153:9080 172.16.4.14:47910 - default [2021-10-03T09:31:58.590Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 375 820 819 "-" "curl/7.52.1" "535a16d8-1a7b-9f4f-8d25-810ac82988f6" "reviews:9080" "172.16.4.36:9080" outbound|9080||reviews.sample-app.svc.cluster.local 172.16.4.14:59142 10.0.212.252:9080 172.16.4.14:46188 - default [2021-10-03T09:31:58.526Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 5179 933 933 "-" "curl/7.52.1" "535a16d8-1a7b-9f4f-8d25-810ac82988f6" "productpage:9080" "172.16.4.14:9080" inbound|9080|| 127.0.0.6:53507 172.16.4.14:9080 172.16.4.64:39534 outbound_.9080_._.productpage.sample-app.svc.cluster.local default
アクセスログから、確かにサイドカープロキシであるEnvoyを経由して各アプリケーションに通信していることが確認できました。アクセスログの詳細については、Istio公式サイト(Getting Envoy's Access Logsページ)を参照してください。
本記事で紹介する手順は汎用(はんよう)的に使用できるものですが、環境に応じて追加の手順が必要となる場合があります。本コラムでは、代表としてGKEを限定公開クラスタで構成する環境にIstioインストールする場合の注意点を取り上げます。
その他の環境にインストールする場合の注意点は、Istio公式サイト(Platform Setupページ)を参照ください。
なお、GKEクラスタにインストールする場合の手順の詳細についてもIstio公式サイト(Google Kubernetes Engineページ)を参照してください。
限定公開クラスタ作成時に自動で適用されるファイアウォールルールでは、ノードの15017ポートへの通信を許可していません。サイドカーインジェクションは、APIサーバがWebhookのデプロイメント(istiod)に接続することで動作するので、15017ポートを明示的に許可する必要があります。
ファイアウォールルールを変更しない場合の動作を確認します。15017ポートを許可しない場合、アプリケーションをデプロイした場合でもPodが起動してこない様子を確認できます。
# namespace:sample-appにBookInfoアプリケーションをデプロイ $ kubectl apply -f ./samples/bookinfo/platform/kube/bookinfo.yaml -n sample-app <省略> $ kubectl get pod -n sample-app No resources found in sample-app namespace. # Podが作成されない $ kubectl get deployment -n sample-app NAME READY UP-TO-DATE AVAILABLE AGE # deploymentの進行で止まる details-v1 0/1 0 0 12m productpage-v1 0/1 0 0 12m ratings-v1 0/1 0 0 12m reviews-v1 0/1 0 0 12m reviews-v2 0/1 0 0 12m reviews-v3 0/1 0 0 12m
繰り返しますが、15017ポートへの通信が許可されていないので、サイドカーインジェクションに失敗し、タイムアウトしていることが原因でPodが作成されてきません。下記のように、コマンドを発行することでAPIサーバがPodにアクセスできるかどうかを確認することもできます。
$ kubectl get --raw /api/v1/namespaces/istio-system/services/https:istiod:https-webhook/proxy/inject -v4 I0922 02:37:56.880874 2366 helpers.go:217] server response object: [{ "metadata": {}, "status": "Failure", "message": "error trying to reach service: dial tcp 10.76.1.30:15017: i/o timeout", # 15017に通信していることを確認できる "reason": "ServiceUnavailable", "code": 503 }] Error from server (ServiceUnavailable): error trying to reach service: dial tcp 10.76.1.30:15017: i/o timeout
原因が明確になったので、許可設定を追加します。gcloudコマンドで、ルールの追加が可能です。
# 既存のルールの確認 $ gcloud compute firewall-rules list --filter="name~gke-[0-9a-z]*-master" NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED gke-testcluster-40f78762-master default INGRESS 1000 tcp:10250,tcp:443 False # 変数に対象のルール4829設定 $ export firewallRule=`gcloud compute firewall-rules list --filter="name~gke-[0-9a-z]*-master"| grep gke | awk '{print $1}'` # 15017ポートの許可を追加 $ gcloud compute firewall-rules update ${firewallRule} --allow tcp:10250,tcp:443,tcp:15017 # 許可後の確認 $ kubectl get pod -n sample-app NAME READY STATUS RESTARTS AGE details-v1-79f774bdb9-qnq5n 2/2 Running 0 5m27s productpage-v1-6b746f74dc-ckz44 2/2 Running 0 5m22s ratings-v1-b6994bb9-j7sqp 2/2 Running 0 5m32s reviews-v1-545db77b95-gqq6z 2/2 Running 0 5m20s reviews-v2-7bf8c9648f-fsp5l 2/2 Running 0 5m17s reviews-v3-84779c7bbc-p864h 2/2 Running 0 5m27s
このように環境に応じて、設定を追加する必要がある場合があります。もし本記事の手順を実施する中で、うまく進まないことがあれば、Istio公式ページ(Platform Setup)を参照しながら環境特有の設定も確認してください。
BookInfoアプリケーションに外部からアクセスできるようにします。Istioの機能を使用して、外部からアクセスできるようにするには、「Istio Ingress Gateway」を使用します。Istio-ingressgatewayが外部からのリクエストの受け口となります。
まずは、リソースを確認します。「istio=ingressgateway」というlabelが付与されており、Gatewayリソースではこれを指定します。
# istio=ingressgatewayというlabelを確認(この後マニフェストで使用) kubectl get deployments.apps istio-ingressgateway -n istio-system -L istio NAME READY UP-TO-DATE AVAILABLE AGE ISTIO istio-ingressgateway 1/1 1 1 2d14h ingressgateway
Istio Ingress Gatewayは、GatewayリソースとVirualServiceリソースを基に、Istio Ingress Gatewayへのアクセスをアプリケーションにルーティングすることで、外部からアプリケーションにアクセスできるようにします。例えば、下図のようになります。
「samples/bookinfo/networking」配下の「bookinfo-gateway.yaml」を例に設定の詳細を見ていきます。
Gatewayを登録します。istio-ingessgatewayを設定するリソースです。下記は80番ポートでHTTPリクエストを待ち受けるように設定しています。Gatewayリソースはトラフィックを受ける設定をするだけで、どの宛先にトラフィックを流すかはVirtualServiceリソースで定義します。
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: ingressgateway # 先ほど確認したlabelと一致させる servers: - port: number: 80 # リクエストを受け付けるポートを指定 name: http protocol: HTTP hosts: # Host Headerを見て、何を対象とするのかを指定できる - "*" # 今回は、「*」で全てのリクエストを受け付けるように設定する
また、servers内のhostsにはHost Headerを見てどれを対象とするかを定義できます。今回は、「*」で全てを受け入れるように設定していますが、例えば下記のように設定すると、dev.sample.comやprod.sample.comを持つVirtualServiceが対象となります。
hosts: - "*.sample.com"
istio-ingressgatewayで受けたトラフィックをどの宛先に流すかを設定します。
後述のDestinationRuleリソースで定義するsubsetsに合わせることでトラフィック分割も可能になります。「spec.gateways」で上記のGatewayリソースとひも付けします。
今回の設定では「bookinfo-gateway」が受け取ったトラフィックのうち、URIが「/productpage」「/login」「/logout」の場合と「/api/v1/products」「static」から始まる場合は、productpageサービスにルーティングするように設定しています。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: bookinfo spec: hosts: - "*" gateways: - bookinfo-gateway # 上記のGatewayリソースとのひも付け http: - match: # bookinfo-gatewayが受け取ったリソースのうち、 - uri: # どのURIに一致した場合に、後続のサービスにルーティングするかを設定 exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: exact: /logout - uri: prefix: /api/v1/products route: - destination: # 後続のproductpageサービスにルーティング host: productpage port: number: 9080
前置きが長くなりましたが、デプロイしていきましょう。先ほど解説した2つのカスタムリソースを確認できます。
# gateway、virtualserviceリソースのデプロイ $ kubectl apply -f ./samples/bookinfo/networking/bookinfo-gateway.yaml -n sample-app # リソースの確認 $ kubectl get gateway -n sample-app NAME AGE bookinfo-gateway 12s $ kubectl get virtualservice -n sample-app NAME GATEWAYS HOSTS AGE bookinfo ["bookinfo-gateway"] ["*"] 24s
次に、Kubernetesクラスタ外からのアクセスが可能かどうかを確認します。下記コマンドで対象のIPアドレスとポートを設定し、コマンドラインでページにアクセスしてみましょう。今回は、「type: LoadBalancer」を使用していますが、NodePortや「minikube」を使う場合は、Istio公式サイト(Determining the ingress IP and portsページ)を参考に設定してください。
# type: LoadBalancerを使用する場合は以下の環境変数を設定 $ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}') # クラスタの外部からBookInfoアプリケーションにアクセス $ curl -s "http://${INGRESS_HOST}:${INGRESS_PORT}/productpage" | grep -o "<title>.*</title>" # ブラウザからアクセスするためにURLを表示 $ echo http://${INGRESS_HOST}:${INGRESS_PORT}/productpage
Webブラウザから上記URLにアクセスすると、Bookinfoアプリケーションのページにアクセスできます。「istio-proxy」のログを確認することで、クライアントからのアクセスも確認できます。
$ kubectl logs -n sample-app "$(kubectl get pod -n sample-app -l app=productpage -o jsonpath={.items..metadata.name})" -c istio-proxy | tail -3 [2021-06-27T06:41:43.317Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 4 4 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" "36fa5e55-27ad-930f-8069-c867aa0a10ac" "details:9080" "172.16.4.47:9080" outbound|9080||details.sample-app.svc.cluster.local 172.16.4.14:52976 10.0.216.153:9080 172.16.4.14:36648 - default [2021-06-27T06:41:43.327Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 379 25 24 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" "36fa5e55-27ad-930f-8069-c867aa0a10ac" "reviews:9080" "172.16.4.15:9080" outbound|9080||reviews.sample-app.svc.cluster.local 172.16.4.14:59988 10.0.212.252:9080 172.16.4.14:34924 - default [2021-06-27T06:41:43.308Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 5183 55 55 "172.16.4.4" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" "36fa5e55-27ad-930f-8069-c867aa0a10ac" "20.191.174.190" "172.16.4.14:9080" inbound|9080|| 127.0.0.6:40819 172.16.4.14:9080 172.16.4.4:0 outbound_.9080_._.productpage.sample-app.svc.cluster.local default
アプリケーションを外部に公開するのにVirtualServiceを使いましたが、他にもさまざまなリソースがあります。
Istioのサービスメッシュ内では、VirtualService、DestinationRuleなどのCustom Resource Definitionを利用することで、柔軟にルーティングします。メッシュ内のマイクロサービスにアクセスする場合の基本的な考え方は、Ingressを用いる場合と類似しており、定義したルールを基に、サイドカープロキシのEnvoyが転送する仕組みです。この転送するルールを定義するのが、VirtualService、DestinationRuleです。次回以降で詳しく解説しますが、トラフィック制御機能はIstioのコア機能の一つで、これらのリソースを理解することがIstioを活用する第一歩です。
VirtualServiceとDestinationRuleの概要とそれぞれのリソースの関係を確認しておきます。
DestinationRuleは、特定のサービスへのトラフィックに適応されるポリシーを定義するリソースです。PodのLabelを用いたまとまり(サブセット)の作成や負荷分散ルールの構成、接続数の設定などを行えます。下記では、reviewsという名前のServiceに2つのバージョンが存在し、それぞれ「v1」「v2」というLabelで識別可能とするようなポリシーを作成します。
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: reviews-destination spec: host: reviews.prod.svc.cluster.local # reviewsサービスへのトラフィックに関してポリシーを定義 subsets: - name: v1 # サブセットの名称 labels: version: v1 # Podのラベル情報 - name: v2 labels: version: v2
VirtualServiceは、サービスにリクエストをルーティングする方法を構成するリソースです。特定のサービスへのリクエストが発生した際に、HTTPヘッダやパスなどを条件化することでルーティング先を定義したり、DestinationRuleと組み合わせることでサブセット単位にルーティングのルールを設定したりすることができます。具体的には、下記のように条件に応じて、バージョンの違うサービスにルーティングするような設定が可能です。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews-route spec: hosts: # ひも付けるサービスを指定 - reviews.prod.svc.cluster.local # ここでは、reviewサービスを指定 http: - name: "reviews-v2-routes" match: - uri: prefix: "/wpcatalog" route: - destination: host: reviews.prod.svc.cluster.local # 通信先のサービスを設定 subset: v2 # /wpcatalogの場合、v2サブセットに対して通信する - name: "reviews-v1-route" route: - destination: host: reviews.prod.svc.cluster.local subset: v1 # パスを指定しない場合は、v1サブセットに対して通信する
これらのリソースを使用して、複数バージョンが存在するサービスへのルーティングを制御できるので、ブルーグリーンデプロイメントや、リクエストの重み付けを加えることによるカナリアリリースなども可能となります。
以上を簡潔にまとめると、下図のようになります。
上記を踏まえると、VirtualServiceは、振り分け先の宛先Serviceを決定するリソースで、DestinationRuleはPodにリクエストを振り分けるポリシーを定義するリソースといえます。Envoyはこれらのリソースを監視して、そのルールに基づき転送します。
VirtualServiceとDestinationRuleのイメージを持つことができたでしょうか? 次回以降のトラフィック制御機能を実行する際には、併せて見直すとより理解が深まると思います。
各データプレーンに設定が反映されていることを確認します。IstioのデータプレーンであるEnvoyは、istiodの構成要素「Pilot」から設定を伝搬されることで動的に構成されます。設定変更した際にデータプレーンへの反映状況を確認するにはどうすればいいのでしょうか。istioctlコマンドは、そのようなニーズにも対応しており、下記のように伝搬状況を確認できます。
$ istioctl proxy-status NAME CDS LDS EDS RDS ISTIOD VERSION details-v1-79f774bdb9-cjsls.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 istio-egressgateway-7d4f75956-nnlz5.istio-system SYNCED SYNCED SYNCED NOT SENT istiod-6f6c6bbbbd-nhk6d 1.11.3 istio-ingressgateway-5d57955454-bzxxn.istio-system SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 productpage-v1-6b746f74dc-kg82c.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 ratings-v1-b6994bb9-z222n.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 reviews-v1-545db77b95-4qnjk.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 reviews-v2-7bf8c9648f-7gx2t.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3 reviews-v3-84779c7bbc-ztlqj.sample-app SYNCED SYNCED SYNCED SYNCED istiod-6f6c6bbbbd-nhk6d 1.11.3
このように全部「Sync」状態になっていれば、設定が反映されています(今回のデプロイしたアプリケーションの構成では、egressgatewayを設定していないのでistio-egressgatewayのRDSが「NOT SENT」になります)。
xDSはEnvoyをコントロールするために必要なDiscovery Serviceのことです。Istioの場合、Cluster、Listener、Endpoint、RouteのDiscovery Serviceを設定できます。
例えば、先ほどのVirtualServiceの設定反映を見る場合には、以下を確認するといいでしょう。
# コマンド例 $ istioctl proxy-config route [PODNAME].[NAMESPACE] -o json # productpageのPod内のIstio-proxyに対して実行する場合 $ istioctl proxy-config route "$(kubectl get pod -n sample-app -l app=productpage -o jsonpath='{.items[0].metadata.name}')" -n sample-app -o json
さらに設定を細かく見たい場合は、下記コマンドを用いてデータプレーンの設定を全て出力するといいでしょう。
$ kubectl exec [PODNAME] -c istio-proxy -n [NAMESPACE] -- curl localhost:15000/config_dump # productpageのPod内のIstio-proxyに対して実行する場合 $ kubectl exec "$(kubectl get pod -n sample-app -l app=productpage -o jsonpath='{.items[0].metadata.name}')" -c istio-proxy -n sample-app -- curl localhost:15000/config_dump
今回は詳細に触れませんが、Istioにおける設定方法とデータプレーンのEnvoyにおける設定箇所までを理解することで、問題発生時にも対応できるようになるでしょう。詳細については、Istio公式サイト(Debugging Envoy and Istiodページ)を参照してください。
「インストールオプションの確認」の項でも触れましたが、Istioは「Kiali」「Jeager」といったプロダクトのダッシュボードと統合されています。
ダッシュボードからサービスを参照することで、サービスメッシュの構造やリソース状態を可視化できます。用意されているサンプルを使用して「どのようにサービスを可視化できるか」を確認します。
# アドオンは個別でデプロイが可能 $ ls -l ./samples/addons total 560 -rw-r--r-- 1 sample sample 5194 9 22 02:38 README.md drwxr-xr-x 6 sample sample 192 9 22 02:38 extras -rw-r--r-- 1 sample sample 245502 9 22 02:38 grafana.yaml -rw-r--r-- 1 sample sample 2533 9 22 02:38 jaeger.yaml -rw-r--r-- 1 sample sample 11008 9 22 02:38 kiali.yaml -rw-r--r-- 1 sample sample 13633 9 22 02:38 prometheus.yaml # 今回は一括でデプロイします $ kubectl apply -f ./samples/addons # デプロイ後の状態 $ kubectl get pod -n istio-system NAME READY STATUS RESTARTS AGE grafana-68cc7d6d78-dd5vv 1/1 Running 0 2m19s istio-egressgateway-7d4f75956-fbcdd 1/1 Running 0 16m istio-ingressgateway-5d57955454-bsghf 1/1 Running 0 16m istiod-6f6c6bbbbd-rjw7b 1/1 Running 0 16m jaeger-5d44bc5c5d-fhlzh 1/1 Running 0 2m18s kiali-fd9f88575-jcmkk 1/1 Running 0 2m18s prometheus-77b49cb997-j6rgz 2/2 Running 0 2m18s
今回は、Kialiのダッシュボードを例にメッシュ内のサービス状況を確認します。istioctlコマンドには「istioctl dashboard」というオプションがあり、これを実行することで「kubectl port-forward」を実行したときのように、Kialiのダッシュボードにアクセスできるようになります。
PrometheusやGrafana、Jaegerも同様に「istioctl dashboard」コマンドでダッシュボードにアクセス可能です。詳細については、Istio公式ページ(Integrations)を参照してください。
# kialiのダッシュボードを表示 $ istioctl dashboard kiali http://localhost:20001/kiali
コマンド実行後、上記のURLにアクセスするとダッシュボードにアクセスできます。
上記画面には、NamespaceごとのアプリケーションPodの個数、Istio Configの設定有無などの状況が表示されています。
次に画面左の「Graph」を選択し、Pod間の接続状況を表示します。上記画面のGraphをクリックするとアプリケーションの状況が図示されます。「Empty Graph」と表示される場合は、ブラウザもしくはコマンド経由で複数回BookInfoアプリケーションにアクセスしましょう。
# クラスタの外部からBookInfoアプリケーションにアクセス $ curl -s "http://${INGRESS_HOST}:${INGRESS_PORT}/productpage" | grep -o "<title>.*</title>" # ブラウザからアクセスするためにURLを表示 $ echo http://${INGRESS_HOST}:${INGRESS_PORT}/productpage
すると、下図のようにサービスの相関を表示できます。画面中の三角形はService、丸四角形はappを表しており、namespace:istio-systemにはistio-ingressgatewayの存在も確認できます(※下図の表示例では、「Display」欄のNamespaceBoxとServiceBoxにチェックを入れた状態にしています)。
Kialiでは、アクセス量やサービス間の通信発生箇所をリアルタイムで表示したり、先ほど発生させたBookInfoアプリケーションへの通信がistio-ingressgatewayを経由していることも確認したりすることができます(緑色矢印箇所)。その他にも通信の割合を可視化することやIstioのConfigの確認なども可能です。詳細について確認したい方は、Kiali公式ページを参照してください。
使用した環境のアンインストールをする方法も記載します。こちらは必要に応じて、参照してください。
Bookinfoアプリケーションにはアンインストールツールが用意されているので、そちらを使用するといいでしょう。対象のnamespaceが対話式で問われるので、指定するだけです。
$ samples/bookinfo/platform/kube/cleanup.sh namespace ? [default] sample-app using NAMESPACE=sample-app virtualservice.networking.istio.io "bookinfo" deleted gateway.networking.istio.io "bookinfo-gateway" deleted Application cleanup may take up to one minute service "details" deleted serviceaccount "bookinfo-details" deleted deployment.apps "details-v1" deleted service "ratings" deleted serviceaccount "bookinfo-ratings" deleted deployment.apps "ratings-v1" deleted service "reviews" deleted serviceaccount "bookinfo-reviews" deleted deployment.apps "reviews-v1" deleted deployment.apps "reviews-v2" deleted deployment.apps "reviews-v3" deleted service "productpage" deleted serviceaccount "bookinfo-productpage" deleted deployment.apps "productpage-v1" deleted Application cleanup successful $ kubectl delete namespace sample-app
「Application cleanup successful」と表示されれば、完了です。
IstioのアンインストールもConfiguration Profileを指定して実行します。
$ istioctl manifest generate --set profile=demo | kubectl delete --ignore-not-found=true -f - $ kubectl get all -n istio-system $ kubectl delete namespace istio-system
今回はIstioをインストールし、クラスタの外部にアプリケーションを公開する手順を紹介しました。また、DestinationRuleでトラフィックに適応されるポリシーを定義し、VirtualServiceでルーティングするといったIstioの主要なリソースについても触れました。
紹介した内容はまだまだIstioの入り口にすぎません。Istioの本領は、これらをはじめとしたリソースを用いて、トラフィックを制御し、セキュリティと可観測性を向上させる点にあります。
次回は主要機能のトラフィック制御機能に着目し、サービスメッシュを用いた航走をより加速させます。
Copyright © ITmedia, Inc. All Rights Reserved.