本記事はFIXERが提供する「cloud.config Tech Blog」に掲載された「動かしながら学んだKubernetes Istioのメモ」を再編集したものです。
はじめに
最近ずっとkubernetesの勉強しているなむゆです。
特にここ4週間くらいはIstioについて重点的に動かしたり資料を読んだりしていたのでその時に学んだ基礎的な点を記事にまとめておきたいと思います。
istioとは
Istioとは、高機能なオープンソースのサービスメッシュです。
Kubernetesのようなプラットフォームにインストールして使用され、内部にサービスメッシュを展開します。
現在はKubernetesのほかに、HashiCorpによってつくられたサービスディスカバリーのConsul、または個別の仮想に対応しています。
サービスメッシュとは
「高機能なサービスメッシュ」と書きましたが、ではそのサービスメッシュとは何かというと、マイクロサービスアーキテクチャーのようなサービスを複数展開し、相互に連携して全体の機能を実現しているときにそれらのサービス間のネットワークを仲介する機能です。
例えば、サービス間で通信したいとなった際に通信相手のサービスの名前解決を行なったり、それらの通信に失敗したときのリトライ機能などを基本的な機能として持ちます。
これにより、マイクロサービスアーキテクチャーにおいて課題になりがちであった、サービス間の通信の障害や通信が増えることによる性能劣化といった問題を解決し、マイクロサービスアーキテクチャーを実現しやすくしてくれます。
実際にどんな実装が行なわれていてどんな機能が実現されているかはサービスメッシュによって差があります。
これがあると何がうれしいの?
Istioはそんなサービスメッシュを実装しているもののうちのひとつです。 これがなくてもkubernetesにおいてリクエストやkubernetes内のネットワークを構築することはできなくはないのですが、サービスメッシュを使うとその仕組みをより高機能に、より簡単に実装できます。
例えば、クラスター内の通信について、リトライ処理を追加したりA/Bテストを行なう時に使うような割合でトラフィックを分割する仕組み、リクエストのタイムアウトの時間などを設定できます。
それらの通信についてメトリクスやログを取ることもでき、kialiやgrafana等の可視化ツールと連携してネットワークの監視を行なうこともできます。
これらの機能をいくつかの設定を行なうだけで実現できるのがサービスメッシュの強みになります。
アーキテクチャー
詳しい個別の情報についてはドキュメントをどうぞ。
ドキュメントが英語なのと個別に見ていくとキリがないので分かりやすい粒度でまとめてみます。
Istioのサービスメッシュは大きく分けるとData Planeという部分とControl Planeという部分に分かれます。
これらはオブジェクトとして物理的に分かれているものではなく概念的な分類なのですが、それぞれでIstio内で担う役割が違います。
Data Plane
まずData Planeなのですが、こちらは外部からやってきたものやサービスの間で交わされる通信を実際に行なう役割を担います。
具体的には、Envoyと呼ばれるリソースがあり、これがkubernetes内に立てられるサービスごとにペアとなるように作られます。
このペアのように作られる様子をサイドカーと呼んだりします。バイクに対するサイドカーのように、サービスごとに横付けされるように作られるためです。
で、これが何をするものなのかと言うと、例えるなら家ごとに置かれた郵便受けやポストのようなものになります。
具体的には、他のサービスやkubernetes外部と送受信を行なうプロキシになります。
外部からやってきた通信はまずEnvoyに届き、プロキシが横付けしたサービスにその内容を伝えます。
また、外部に対する通信もサービスからEnvoyに送り、そこから他のサービスやkubernetes外部に内容が送られます。
年賀状も家に届くときはまず郵便受けに届いてそこから取り出しますし、送るときは送り先に直接届けるのではなくポストに投函しますよね。
Envoyもそのような役割を果たし、ネットワーク関連の言葉で言うとプロキシの役割を果たします。そしてそれはサービス毎にサイドカーとして作られ横付けされたサービスに対するプロキシになるわけです。
また、Envoyを通して通信を行なうことで通信時のトラフィックの統計情報を収集する役割もあります。
Control Plane
Control Planeは、そんなData Planeを制御する役割を持ちます。
代表的な例としてはどんなurlのリクエストがやって来たらどこのサービスにそのリクエストを送り届けるかといったルーティングをVirtual Serviceを用いて行なうというものがあります。
これによってkubernetes外部からやってきたリクエストをどのサービスに渡すかを制御します。
他にも、kubernetes内のサービス間での通信を制御し、通信時にルールを設定することでセキュリティーの機能を実装することもできます。
これらの機能は、細かく分けるとさらにPilot(Istioの通信制御等のルールをEnvoyに伝えたりその他便利機能)、Citadel(証明書周り)、Galley(Istioに対して行なう設定受けつけ)といった部分に分かれますが、今は全部まとめてIstiodというものにまとめられているようです。
なので、IstiodはEnvoyの制御を行なうControl Planeの役割を大体になっているようなイメージになります。
ざっくりした動作の流れ
ここまでIstioの個別の部分の説明してきましたが、それだけだとそれを使ってどのような流れの処理になるのかイメージしづらいので、外部からリクエストがやってきてそれに対してレスポンスを行なうまでの流れをざっくりと解説してみます。
全体の図としてはこのようになります。マイクロサービスアーキテクチャーを採用しているのでサービスは複数あり、それぞれにEnvoyがサイドカーとして横付けされています。
この中で、EnvoyはData Planeに属しています。
この図の中で、黄色い付箋はそれぞれ1個のpodになります。
kubernetesにリクエストがやってきました!
まずはこれをIngress Gatewayが受け取ります。
Ingress Gatewayはkubernetes外部からやってくるリクエストの窓口で、ここからVirtualServiceのようなオブジェクトで設定したルールに応じて各種内部のサービスにリクエストを送り届けます。
というわけで今回はサービスAにリクエストを送りたいのでサービスAにサイドカーとして横付けされたEnvoyにリクエストが届きました。
EnvoyはそれをサービスAに渡します。
今回の処理ではサービスBでの処理も行なわなければならないため、サービスBに対しても通信を行ないます。
その際にも、まずはEnvoyと通信し、そこからサービスBへ通信を行ないます。
サービスBでも同様に、まずEnvoyが通信を受け取り、それをサービス本体に渡します。
こうしてサービスAとサービスBの通信が実現します。
サービスBでの処理が終わればまたEnvoyを通して処理結果をサービスAに返し…
サービスAはegress gatewayを経由してリクエスト元のkubernetesクラスター外にレスポンスを返します。
これがIstioを用いてkubernetes内で通信を行なう一連の流れになります。
実際にはさらにDBなどkubernetes外部のリソースと通信するために何度もegress gatewayを用いて通信を行なったりもします。
あれ、Control Planeは?
…本当はさらにControl Planeもこれらの処理に一枚噛んでいます。
同時に説明するとひとつの動作の説明が増えるので章を分けました。
先程の例でのControl Planeの役割を説明します。
例えば、Ingress gatewayにやっていたリクエストをどのサービスに渡すかのルーティングの制御をControl Planeが行ないます。
VirtualServiceに設定したルーティングのルールに従い、ingress gatewayで受け取ったリクエストをどのサービスに渡すかを決め、Envoyに対してリクエストを送らせるようにします。
また、サービスAとサービスBの間の通信において認証、認可の機能が必要になった場合のそれらの仕組みもControl Planeで実装します。
他に、DestinationRuleやVirtualServiceを操作してサービスのバージョンアップを行なう際のBlue/Greenデプロイやサーキットブレイカーなどを実装したりもします。
こうした形でControl PlaneはData Planeを裏から制御する振舞いをしています。
インストール方法
それでは実際の使い方を説明していきます。
環境としてはWindows 10 HomeのOSのPCにDocker DesktopのKubernetes機能で立てたシングルノードのkubernetesを使用します。
導入方法はこちらでまとめているので、まだ導入していない場合はこちらを参考にどうぞ。
導入されたらば、次に進みます。
まずはPC上にIstioctlをダウンロードしてきます。
こちらのサイトの「istioctl-(バージョン)-win.zip」をダウンロードしてきて解凍します。
解凍したらば、分かりやすい場所に移動してそのディレクトリにPathを通します。
Pathを通してistioctlが使用できる状態になれば、インストールする対象のクラスターを現在使用しているコンテキストに指定します。
例えばDocker Desktopで立てたkubernetesにインストールする場合はPowerShell等で下記のようなコマンドを実行します。
kubectl config use-context docker-desktop
コンテキストを切り替えたら、下記のコマンドで現在のコンテキストで接続するクラスターにistioをインストールします。
istioctl install --set profile=default -y
「profile=○○」という部分によって、インストールされる内容が変わります。defaultのほかにdemo、minimal等があり、それぞれのセットアップの内容はこちらに解説があります。
weatherforecastアプリをデプロイしてみる
ここからはIstio公式サイトのGetting Startedをベースに、.net coreアプリをkubernetes上にデプロイして動かしてみます。
Getting Startedではサンプルのアプリケーションとしてbookinfoアプリを動かしてみていますが、今回は普段触れることの多いので.net coreアプリも同様にデプロイできることを示すため以前のブログで作成したweatherforecastのアプリをデプロイしてみます。
そのため、アプリケーションを作成する部分については上記のブログを参考にしながら作成していることが前提となります。
手順2まで済ませたら、こちらの手順に合流しても大丈夫です。
docker buildする際にはあとでタグが分かりやすくするために以下のコマンドでビルドします。
docker build -t weather-forecast:weather-forecast .
コンテナが作成できたら、アプリケーションをデプロイしてIstioを用いてルーティングを行なうためのマニフェストファイルを作成していきます。
以下の3つのyamlコードをコピーして同じディレクトリのファイルに保存してください。
0_namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: weather-forecast
labels:
istio-injection: enabled
1_Istio.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: weather-forecast
namespace: weather-forecast
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: weather-forecast
namespace: weather-forecast
spec:
hosts:
- "*"
gateways:
- weather-forecast
http:
- match:
- uri:
exact: /weatherforecast
route:
- destination:
host: weather-forecast.weather-forecast.svc.cluster.local
port:
number: 80
2_WeatherForecast.yaml
apiVersion: v1
kind: Service
metadata:
name: weather-forecast
namespace: weather-forecast
labels:
app: weather-forecast
service: weather-forecast
spec:
ports:
- port: 80
name: http
selector:
app: weather-forecast
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: weather-forecast-v1
namespace: weather-forecast
labels:
app: weather-forecast
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: weather-forecast
version: v1
template:
metadata:
labels:
app: weather-forecast
version: v1
spec:
containers:
- name: weather-forecast
image: weather-forecast:weather-forecast
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
yamlファイルを作成できたら、PowerShellを開きます。
上記の3ファイルを置いてあるディレクトリまで移動しておいてください。
移動出来たら、そのディレクトリにある3つのマニフェストファイルをkubernetesに適用します。
kubectl apply -f .
これで作成したマニフェストファイルが適用され、指定したオブジェクトが生成されます。
一番重要なアプリケーションのPodが動作しているかどうかは以下のコマンドで確認できます。
kubectl get pods -n weather-forecast
STATUSの欄がRunningになっていればデプロイに成功しています!
デプロイに成功したら、このAPIを叩いてみましょう。
ブラウザーを開き、URLの入力欄にlocalhost:80/weatherforecastと入力してアクセスできます。
Json型のレスポンスが返ってくれば成功です!
このURLにアクセスすると、Gatewayで指定したとおり、80番ポートからkubernetesにリクエストが入ります。
それからIngressGatewayにおいてVirtualServiceに設定したとおりに/weatherforecastのパスにやってきたリクエストはweather-forecast.weather-forecast.svc.cluster.localのhostに送られます。
このhostはこちらで解説されているように、{サービス名}.{namespace名}.svc.cluster.localのルールに従って名前解決されるので、weather-foreastのnamespaceのweather-forecastサービスにリクエストが流れます。
weather-forecastのnamespaceのweather-forecastサービスにはDeploymentのオブジェクトで指定したとおりWeatherForecastのアプリのPodが結び付けられているので、めでたくリクエストはWeatherForecastのアプリケーションにたどり着きます。
このようにして、Istioを使用して通信のルーティングを行なうことができます。
おわりに
今回はIstioの基本的な点を説明しながら、実際に動かせるアプリケーションを立てる方法を説明しました。
以前のkubernetesの学習環境の導入方法やアプリのコンテナのビルドの方法と合わせることで、アプリケーション開発~kubernetes上でサービスを利用可能にするするまでの一連の作業が順を追って理解できると思うので、Istioだけでなくkubernetesでのアプリの開発、運用の基本的な方法を知りたいという方はこれらの過去記事もご覧ください。
参考
・What is Istio?
・Getting Started
Istioのインストール方法
・Kubernetes実践ガイド クラウドネイティブアプリケーションを支える技術
書籍。Istio周りについての章がある(9章)。ただし、Galley、Citadel等の機能はIstiodに統合され、Mixerの機能はEnvoyに合流してdeprecatedとなっているなど若干情報が古い部分もある模様。
なむゆ/FIXER
最近インフラ始めました。
k8s社内最強を目指します。