KINTO Tech Blog
Development

非インフラエンジニアのためのIstio入門

Cover Image for 非インフラエンジニアのためのIstio入門

非インフラエンジニアのためのIstio入門

こんにちは。Woven Payment Solution開発グループの楢崎と申します。
我々は、Woven by ToyotaToyota Woven Cityで利用される決済基盤アプリケーションの開発に携わっており、バックエンドからWebフロントエンド / モバイルアプリケーションまで決済に関わる機能を横断的に開発しています。
その中で私は主にバックエンドアプリケーションの開発を担当しています。我々が開発している決済バックエンドはマイクロサービスを構成しており、City PlatformというKubernetesをベースにしたプラットフォーム上で動作しています。

今回は、IstioというKubernetes上でマイクロサービスのネットワークを構成する仕組みを、普段ビジネスロジック等のコードを書いているバックエンドアプリケーションエンジニアにもわかりやすくその目的や機能を解説したいと思います。
この記事でIstioを用いた設定の理解がより深まり、トラブルシュート時に原因の切り分けやインフラ・ネットワークエンジニアと円滑にコミュニケーションが出来るような一助になれば幸いです。

Istioって何?

Istio

マイクロサービスアーキテクチャを採用すると、処理は複数のサービスにまたがり、サービス間の通信が発生することになります。
アプリケーションエンジニアとしては、つながればどうでもいいと思ってしまいがちですが、インフラエンジニアは、そのネットワークレイヤーの制御を効果的に行いたいと考えています。

そこで、ネットワークの経路やセキュリティなどの各種設定をKubernetesのマニフェストと同様に宣言的に一元管理し、ネットワークの状態を統合的に運用監視できることを目指す目的でIstioは作られました。ネットワークが網目状になっていることから、これらの機能をまとめてサービスメッシュ(Service Mesh)と呼ぶこともあります。

Istioのアーキテクチャ: データプレーンとコントロールプレーン

まず、Istioのアーキテクチャを知っておく必要があります。IstioはKubernetesと同じく「コントロールプレーン」と「データプレーン」に分かれています。
KubernetesはKubectlなどからAPIのリクエストを受けて、Pod等のリソースをコントロールするコントロールプレーンと、実際にアプリケーションが動作するPodなどがデータプレーンとなります。

Envoy

IstioのデータプレーンではEnvoyというネットワークプロキシが採用されています。コントロールプレーンが必要に応じて、我々が書いたコードが動作するコンテナの横にサイドカーコンテナとしてEnvoyを注入します。

Envoy
コントロールプレーンとデータプレーン

なぜIstioが必要か

Envoyは単体でも動作可能なネットワークプロキシアプリケーションです。その設定項目は非常に多岐にわたり、1つのEnvoyインスタンスを意図した通りに設定するのも簡単なことではありません。(少なくとも非インフラエンジニアにとっては!)

複雑なマイクロサービスアーキテクチャではそのネットワークが網目のようにクラスタ内外を接続し、たくさんのEnvoy Proxyを設定する必要が出てきます。個別に設定して全てを思い通りに動作させていくことが如何に大変か想像に難くないでしょう。

Istioで設定可能なリソース

Istioを導入することによって、利用可能になる機能として以下のようなものが挙げられています。

  • トラフィック管理(サービスディスカバリ、負荷分散)
  • オブザーバビリティ(ロギング、分散トレーシング)
  • 認証・認可などセキュリティ

一方で、バックエンドアプリケーションエンジニアにとってみれば、それぞれがブラックボックスになっていて、実際に何が設定可能なのか、意図せぬ挙動に出くわした際にどの設定ファイルをみればいいのかわからないことが、今までの我々の経験上多々ありました。
Istioの設定可能なリソースがどのような意味を持つのか、いくつか具体的に見ていきましょう。

Gateway

IngressとEgressというKubernetesのネットワークに関するリソースがありますが、IstioはGatewayと呼ばれるEnvoy Proxyで通信をインターセプトします。文字通りIstioネットワークへの出入口になります。
以下のファイルで設定できます。このファイルそのものにアプリケーションエンジニアが知っておくべき細かな設定が出てくることはほとんどありませんが、他のファイルから gateways という形で参照されることが多いので、まず適切にGatewayが設定されているか確認しましょう。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: test-gateway
spec:
  selector:
    istio: ingressgateway # Istioをインストールするとデフォルトで使えるLoadBalancer Service
  servers:
  - port:
      number: 80 # Listenしているport
      name: http
      protocol: HTTP # 許可しているプロトコル
    hosts:
    - "*" # Host名

Virtual Service

Kubernetesには Service というDeploymentやStatefulSetをクラスタ内ネットワークからアクセスできるようにする仕組みがあります。
一方でIstioのVirtual ServiceはServiceまでどのような経路をとるかを定義します。

非常に多くの設定値が定義出来て強力な反面、他の設定と重複するところがないか注意が必要です。自分が使っているサービスに対してリクエストが届かない場合は何かしらのミスがVirtual Serviceの設定で起こっている場合があります。 istioctl analyze コマンドで設定ミスを教えてくれる場合もあるので見てみましょう。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: test-virtualservice
  namespace: test
spec:
  hosts:
  - "*" # 指定されたホスト名。このホスト名が指定されたときに、以下のルールが適用される、という意味。*だと任意のホスト名に対してルールが適用される
  gateways:
  - test-gateway # 前述のgatewayを指定。複数指定可能
  - mesh # Gatewayを介さないクラスタ内通信を許可する場合ここに'mesh'を定義
  http:
  - match: # リクエストをフィルタリングするためのルールが記述可能
    - uri:
        prefix: /service-a # URIのパターン。Regexなども選べる
    route:
    - destination:
        host: service-a # 宛先のサービス
        port:
          number: 80
  - match: # 複数のルーティングのルールや接続先を定義可能
    - uri:
        prefix: /service-b
    route:
    - destination:
        host: service-b
        port:
          number: 80
 exportTo:
  - . # このルールをどこに適用するか。Kubernetesのnamespace。.(ドット)の場合、このルールが設定されたnamespaceのみに限られる

Authorization Policy

特定のサービス間通信を制御する事ができます。具体的には、プロトコル、特定のパスへのルーティング、HTTPメソッドの指定など、事細かに修正できるので、アプリケーションエンジニア側でも設定する機会が多いかもしれません。
一方で、ルールの設定をミスする場合も多く、思わぬ落とし穴も多いので設定後は必ずテストを実行するようにしましょう。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: access-allow-policy
  namespace: test
spec:
  selector:
    matchLabels:
      app: some-application # Podについているラベル
  action: ALLOW # 許可ルール
  rules:
  - from: # リクエスト送信元の定義
    - source:
        principals:
          - cluster.local/ns/test/sa/authorized-service-account # Kubernetesのサービスアカウント
    to: # リクエスト受信側の定義
    - operation:
        methods: ["POST"] # 許可するHTTPメソッド
        paths:
          - "/some-important-request" # 許可するエンドポイント
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-policy
  namespace: test
spec:
  selector:
    matchLabels:
      app: some-application
  action: DENY # リクエストを拒否する例
  rules:
  - to:
    - operation:
        paths: ["/forbidden-path"]

その他の設定

などの設定ファイルがありますが、ここでの説明は割愛します。基本的に、Kubernetesのリソースと同じく、スキーマが定義してあり、それぞれ設定項目があります。もしチーム内で利用しているリソースがあれば、どんな項目が設定可能か、一度ドキュメントを確認しておくとよいでしょう。

よくあるデバッグ、トラブルシューティングの具体例

まず最初に、設定に不具合がないかを確かめましょう。istioctl analyze コマンドを実行すれば大体の設定ミスはエラーとして報告されます。本番環境などRBACが有効になっていて、Istio関連のリソースに対して制約がある場合、権限をもつインフラエンジニアに実行してもらいましょう。

設定に関して、エラーになるような設定ミスがない場合、リクエストがどこまで到達しているか確認します。Gatewayで通信が途切れているか、アプリケーションのPodまで来ているかを確認するために、アプリケーションもしくはサイドカーのログをみましょう。Gatewayを通過しているように見える場合は、 kubectl logs pod <pod-name> -c istio-proxy -n <namespace> のようなアクセスされるべきPodのnamespace上でサイドカーコンテナのログを確認するのが良いでしょう。

クラスタ内の通信であれば、curl をコンテナ上で実行すれば良いですが、最近のDockerのベースイメージはコンテナアプリケーション実行に不要なアプリケーションは含まれていない事が多いので、k debug <pod-name> -n <namespace> -it --image=curlimages/curl:latest -- /bin/sh のようなデバッグ用のコンテナをアタッチしてクラスタ内で名前解決できるか調べてみましょう。

通信が遮断されているような場合であれば、Virtual Serviceファイルを見る、認証周りが怪しければAuthorization Policyファイルをみることで、設定の不具合の場所までたどり着けると思います。ルーティングや認証周りはどうしても複数のレイヤーで設定された項目がコンフリクトし易い箇所になります。Podにどのような認証ルールが適用されているかはistioctl x authz check <pod-name>.<namespace>というコマンドで一覧に出すことができます。

また、一見ネットワークのエラーのように見えて、実装に問題がある場合も多々あります。並行して実装側もネットワークや認証認可の設定を見直してみると良いでしょう。

以下が私がネットワーク関連のエラーに出くわしたときに実施していることです。

  1. Istioの設定が間違っていないか、istioctl analyze コマンドを実行したり、ログをみて原因を切り分ける
  2. クラスタ内外から curlkubectl debug コマンド等を利用してネットワークの疎通確認を実施する
  3. デプロイしたアプリケーションが正しくインフラレイヤーで指定したportのリクエストをlistenしているか等、アプリケーションの設定を確認する
  4. クライアントアプリケーションが必要な認証認可の仕組みを実装しているか、リクエストを調べてみる

これらはKialiなどのオブザーバビリティスタックの設定が有効であれば、GUIで設定ミスや通信のステータスを確認することも可能です。

最後に

具体的に設定可能な項目とその意味を知ることによってブラックボックス化されていた機能の一端が垣間見えたかと思います。
また設定項目が意外とシンプル、と思われた方もいるのではないでしょうか?

一方でIstioの難しさはネットワークを構成することそのものというよりは、継続的に安定して運用する(バージョンアップのパッチを当てる、その度に動作を検証する)といった、本番運用フェーズだと思います。
バックエンドアプリケーションエンジニアとして実際の運用に向けて、Istioの挙動を理解するのはもちろん、アプリケーションの挙動をテストすることも検討したいですね。

Facebook

関連記事 | Related Posts

We are hiring!

【Woven City決済プラットフォーム構築 PoC担当バックエンドエンジニア(シニアクラス)】/Toyota Woven City Payment Solution開発G/東京

Toyota Woven City Payment Solution開発グループについて私たちのグループはトヨタグループが取り組むWoven Cityプロジェクトの一部として、街の中で利用される決済システムの構築を行います。Woven Cityは未来の生活を実験するためのテストコースとしての街です。

【Toyota Woven City決済プラットフォームフロントエンドエンジニア(Web/Mobile)】/Toyota Woven City Payment Solution開発G/東京

Toyota Woven City Payment Solution開発グループについて我々のグループはトヨタグループが取り組むToyota Woven Cityプロジェクトの一部として、街の中で利用される決済システムの構築を行います。Toyota Woven Cityは未来の生活を実験するためのテストコースとしての街です。