こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
今回は久しぶりにK8s関連の記事を投稿してみます。
K8sをある程度学んだあとに出てくる内容としてよく挙げられるのはIstio(イスティオ)かなと思います。
Istioは結構複雑(K8sですらかなり複雑)なように見えますが、環境構築自体は結構簡単に出来ましたので、気になっている人はとりあえず構築して触ってみるといいのかなぁと思いました。
私も構築している現在、サービスメッシュのサの字もわかっていません。Istioを導入するとトラフィックを良い感じにルーティングしたりA/Bテストが出来るようになったりセキュリティ的にも良いらしいよねくらいのざっくりした理解しかしていません!!!!
・・・理解は徐々に。これからです💦
構築参考サイト
基本的にIstioとKialiの公式サイトに準じれば問題なく構築できるかと思います。
用語
Istio
公式から説明や画像を引用させて頂きますが、個人的には「データプレーンはサービス間の通信である。サービス・メッシュがなければ、ネットワークは送信されるトラフィックを理解することができず、それがどのような種類のトラフィックなのか、あるいは誰から、あるいは誰へのトラフィックなのかに基づいた判断を下すことができない。」という部分が肝な気がしました。
K8sではアプリケーションレベルでの管理が可能で、NodePortやClusterIPを使うことでアプリケーション(≒Pod)間のつなぎ込みが出来たり、Podが意図せずにダウンした時、K8sのコントローラがそれを検知してPodを自動で再デプロイし、アプリケーションの提供が可能でした。
一方でIstioを導入するとアプリケーション間で通信しているトラフィックをベースとして管理することが可能になると。より細かい視点で管理が可能になるので、セキュリティを向上させたり、監視が容易になったりすると。。。
強いて図に起こすのであれば以下のようになるでしょうか・・・
青実線がK8sのPodやServiceを示し、赤実線がPod-Service間の通信・トラフィックを示しています。
そして青点線がK8sのコントローラが見れる部分。赤点線がIstioが見れる部分なのかなと。
Istio は、既存の分散アプリケーションに透過的に重ねられるオープンソースのサービス メッシュです。Istio の強力な機能は、サービスの保護、接続、監視を行うための統一的かつより効率的な方法を提供します。Istio は、サービス コードの変更をほとんどまたはまったく行わずに、ロード バランシング、サービス間の認証、監視を行うためのパスです。
Istioにはデータプレーンとコントロールプレーンの2つのコンポーネントがある。データプレーンはサービス間の通信である。サービス・メッシュがなければ、ネットワークは送信されるトラフィックを理解することができず、それがどのような種類のトラフィックなのか、あるいは誰から、あるいは誰へのトラフィックなのかに基づいた判断を下すことができない。
サービスメッシュは、プロキシを使用してすべてのネットワークトラフィックを傍受し、設定された構成に基づいてアプリケーションを認識する機能の幅広いセットを可能にします。
Envoyプロキシは、クラスタ内で起動する各サービスと共にデプロイされるか、VM上で実行されるサービスと共に実行される。
コントロールプレーンは、希望する設定とサービスのビューを受け取り、動的にプロキシサーバをプログラムし、ルールや環境の変化に応じてプロキシサーバを更新します。
Envoy
NGINXとかの類友なイメージです。
Proxyの役割をしてくれる人。IstioではPodの中にサイドカーコンテナとしてデプロイされるみたいですが、Istio環境だけでしか使えないというわけではないです。
サイドカーコンテナ
サイドカー コンテナは、同じアプリケーション内でメイン アプリケーション コンテナと一緒に実行されるセカンダリ コンテナです。これらのコンテナは、主要なアプリケーション コードを直接変更することなく、追加のサービスやロギング、監視、セキュリティ、データ同期などの機能を提供することにより、メイン アプリケーション コンテナの機能を強化または拡張するために使用されます。
例えば、今回IstioとKialiを導入するにあたり、sampleで用意されているBookinfoアプリをデプロイするのですが、その中のPodの1つにdescribeをかけてみると以下のようになっています。pod内に2つのコンテナが動いていることが確認できます。
root@k8s-master:~/istio-1.20.3# kubectl get pod
NAME READY STATUS RESTARTS AGE
details-v1-698d88b-ngdvp 2/2 Running 0 105m
productpage-v1-675fc69cf-b24bt 2/2 Running 0 105m
ratings-v1-6484c4d9bb-c4b4f 2/2 Running 0 105m
reviews-v1-5b5d6494f4-xf495 2/2 Running 0 105m
reviews-v2-5b667bcbf8-9gkm6 2/2 Running 0 105m
reviews-v3-5b9bd44f4-5hngr 2/2 Running 0 105m
root@k8s-master:~/istio-1.20.3# kubectl describe pod productpage-v1-675fc69cf-b24bt
Containers:
productpage:
Container ID: containerd://e2b3f3f398fd687511956e0feaa3ad9f7c91419d05929c4d1118b815fbfca4a6
Image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
Image ID: docker.io/istio/examples-bookinfo-productpage-v1@sha256:e2723a59bde95d630ed96630af25058ebea255219161d6a8ac6c25d67d7e1b5a
Port: 9080/TCP
Host Port: 0/TCP
State: Running
istio-proxy:
Container ID: containerd://69cdfadfce47617807e53afc9360a9ebbecf39d735c98d912f6b7b715c6c4b75
Image: docker.io/istio/proxyv2:1.20.3
Image ID: docker.io/istio/proxyv2@sha256:18163bd4fdb641bdff1489e124a0b9f1059bb2cec9c8229161b73517db97c05a
Port: 15090/TCP
Host Port: 0/TCP
State: Running
Kiali
IstioをWebGUIベースで管理することが出来るアプリケーションです。
読み方をChatGPTに聞いてみたら「カイアリ」と回答されたのですが、あっているのでしょうか?
構築
Istio環境構築
まず、公式サイトに書かれている前提条件を満たしていることを確認します。
root@k8s-master:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 9m16s v1.28.1
k8s-worker01 Ready <none> 8m8s v1.28.1
k8s-worker02 Ready <none> 7m16s v1.28.1
k8s-worker03 Ready <none> 6m41s v1.28.1
以下のコマンドを実行してIstioをダウンロードします。
カレントディレクトリに、ダウンロードしたistioのディレクトリがあるので移動します。
root@k8s-master:~# curl -L https://istio.io/downloadIstio | sh -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 101 100 101 0 0 424 0 --:--:-- --:--:-- --:--:-- 426
100 4899 100 4899 0 0 8824 0 --:--:-- --:--:-- --:--:-- 8824
Downloading istio-1.20.3 from https://github.com/istio/istio/releases/download/1.20.3/istio-1.20.3-linux-amd64.tar.gz ...
Istio 1.20.3 Download Complete!
Istio has been successfully downloaded into the istio-1.20.3 folder on your system.
Next Steps:
See https://istio.io/latest/docs/setup/install/ to add Istio to your Kubernetes cluster.
To configure the istioctl client tool for your workstation,
add the /root/istio-1.20.3/bin directory to your environment path variable with:
export PATH="$PATH:/root/istio-1.20.3/bin"
Begin the Istio pre-installation check by running:
istioctl x precheck
Need more information? Visit https://istio.io/latest/docs/setup/install/
root@k8s-master:~# ls
istio-1.20.3 snap zabbix-release_6.4-1+ubuntu22.04_all.deb
root@k8s-master:~# cd istio-1.20.3
root@k8s-master:~/istio-1.20.3# ls
bin LICENSE manifests manifest.yaml README.md samples tools
istioctlコマンドを使うためにPATHを通します。
istioctl versionと打ってみてバージョンが出ればOKです。
root@k8s-master:~/istio-1.20.3# istioctl
istioctl: command not found
root@k8s-master:~/istio-1.20.3# export PATH=$PWD/bin:$PATH
root@k8s-master:~/istio-1.20.3# istioctl version
no ready Istio pods in "istio-system"
1.20.3
istioをインストールします。
公式サイトでは”istioctl install --set profile=demo -y”と書いているのですが、別にしなくても問題ありませんし、どうもIstioOperatorと呼ばれるものの設定みたいで、このOperatorは非推奨的な感じみたいなので、実行しないで問題ありません。
オプション等を入れずにinstallしましょう。
root@k8s-master:~/istio-1.20.3# istioctl install
This will install the Istio 1.20.3 "default" profile (with components: Istio core, Istiod, and Ingress gateways) into the cluster. Proceed? (y/N) y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
namespaceにistio-systemが出来ていることと、そのnamespaceの中に色々とデプロイされていることを確認します。istioのingress(LoadBalancer)のEXTERNAL-IPがPendingステートなのは、MetalLBでIPアドレスの予約をしていないためです。Bookinfoのサンプルアプリをデプロイする際にこれが必要になりますが、後程設定を入れていきます。
GCPのGKEとかAWSのEKSみたいなところで環境構築している人は自動で割り当たっていると思います。
root@k8s-master:~/istio-1.20.3# kubectl get ns
NAME STATUS AGE
default Active 36m
istio-system Active 99s
kube-node-lease Active 36m
kube-public Active 36m
kube-system Active 36m
root@k8s-master:~/istio-1.20.3# kubectl get all --namespace istio-system
NAME READY STATUS RESTARTS AGE
pod/istio-ingressgateway-5fc67fbd74-nzvsq 1/1 Running 0 111s
pod/istiod-bc4584967-pl4jt 1/1 Running 0 2m5s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-ingressgateway LoadBalancer 10.105.75.228 <pending> 15021:30100/TCP,80:32524/TCP,443:31628/TCP 111s
service/istiod ClusterIP 10.96.56.249 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 2m5s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/istio-ingressgateway 1/1 1 1 111s
deployment.apps/istiod 1/1 1 1 2m5s
NAME DESIRED CURRENT READY AGE
replicaset.apps/istio-ingressgateway-5fc67fbd74 1 1 1 111s
replicaset.apps/istiod-bc4584967 1 1 1 2m5s
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/istio-ingressgateway Deployment/istio-ingressgateway <unknown>/80% 1 5 1 111s
horizontalpodautoscaler.autoscaling/istiod Deployment/istiod <unknown>/80% 1 5 1 2m5s
Kiali環境構築
公式サイトを読み進めているとかなり最初の方に”If you downloaded Istio, the easiest way to install and try Kiali is by running: kubectl apply -f ${ISTIO_HOME}/samples/addons/kiali.yaml”と記載があることがわかると思います。
実際に自分の環境を見てみると確かにyamlが用意されていることがわかります。
root@k8s-master:~/istio-1.20.3# ls samples/addons/
extras grafana.yaml jaeger.yaml kiali.yaml loki.yaml prometheus.yaml README.md
yamlを使ってkialiをデプロイします。
istio-system namespaceにKiali関連のserviceやdeploymentなどがデプロイされていることがわかります。
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/addons/kiali.yaml
root@k8s-master:~/istio-1.20.3# kubectl get all --namespace istio-system | grep -i kiali
pod/kiali-545878ddbb-l4vs6 1/1 Running 0 45s
service/kiali ClusterIP 10.110.183.205 <none> 20001/TCP,9090/TCP 45s
deployment.apps/kiali 1/1 1 1 45s
replicaset.apps/kiali-545878ddbb 1 1 1 45s
WebUIで接続するためのNodePortを作成していきたいと思います。
NodePortがデプロイされていることを確認し、describeでどのポートでアクセスできるかを確認します。今回は32126と30584が該当となります。
root@k8s-master:~/istio-1.20.3# kubectl expose pod kiali-545878ddbb-l4vs6 --type=NodePort --name=kiali-nodeport --namespace=istio-system --target-port=20001
service/kiali-nodeport exposed
root@k8s-master:~/istio-1.20.3# kubectl get svc --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.105.75.228 <pending> 15021:30100/TCP,80:32524/TCP,443:31628/TCP 32m
istiod ClusterIP 10.96.56.249 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 32m
kiali ClusterIP 10.110.183.205 <none> 20001/TCP,9090/TCP 17m
kiali-nodeport NodePort 10.106.174.176 <none> 20001:32126/TCP,9090:30584/TCP 19s
root@k8s-master:~/istio-1.20.3# kubectl describe svc kiali-nodeport --namespace istio-system
Name: kiali-nodeport
Namespace: istio-system
Labels: app=kiali
app.kubernetes.io/instance=kiali
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=kiali
app.kubernetes.io/part-of=kiali
app.kubernetes.io/version=v1.76.0
helm.sh/chart=kiali-server-1.76.0
pod-template-hash=545878ddbb
sidecar.istio.io/inject=false
version=v1.76.0
Annotations: <none>
Selector: app.kubernetes.io/instance=kiali,app.kubernetes.io/managed-by=Helm,app.kubernetes.io/name=kiali,app.kubernetes.io/part-of=kiali,app.kubernetes.io/version=v1.76.0,app=kiali,helm.sh/chart=kiali-server-1.76.0,pod-template-hash=545878ddbb,sidecar.istio.io/inject=false,version=v1.76.0
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.106.174.176
IPs: 10.106.174.176
Port: port-1 20001/TCP
TargetPort: 20001/TCP
NodePort: port-1 32126/TCP
Endpoints: 172.16.39.194:20001
Port: port-2 9090/TCP
TargetPort: 20001/TCP
NodePort: port-2 30584/TCP
Endpoints: 172.16.39.194:20001
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
http://192.168.2.30:32126/にWebブラウジングします。(IPアドレスはノードのIPアドレスです)
アクセスできましたが、エラーが発生してしまっていました。
エラー内容を見た感じprometheusを導入していないとだめなようです。
このエラーを解消するために追加でprometheus/grafana/Jeagerをデプロイしていきます。全部yamlが用意されているので簡単に終わるかと思います。
- Prometheus:
システムやサービスのメトリクスを収集、保存、クエリする。 - Grafana:
多様なデータソースからデータを可視化する。 - Jaeger:
分散システム内のリクエストのフローとレイテンシーをトレースし、可視化する。
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/addons/prometheus.yaml
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/addons/grafana.yaml
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/addons/jaeger.yaml
改めてKialiにアクセスするとエラーは解消されてグラフが表示されます。
sampleアプリをデプロイする
サンプルのアプリをデプロイしてIstio/Kialiで見てみたいと思います。
具体的には公式が用意しているBookinfoサンプルアプリをデプロイしていきます。
デプロイ後default namespaceにsvcとpodがデプロイされていることを確認します。公式サイトだとpod内のコンテナが2つずつデプロイされるようですが、今回デプロイしたところ1つずつでした。
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
root@k8s-master:~/istio-1.20.3# kubectl get services --namespace default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.103.137.131 <none> 9080/TCP 93s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 88m
productpage ClusterIP 10.107.222.101 <none> 9080/TCP 92s
ratings ClusterIP 10.103.73.109 <none> 9080/TCP 92s
reviews ClusterIP 10.101.53.111 <none> 9080/TCP 92s
root@k8s-master:~/istio-1.20.3# kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
details-v1-698d88b-4zws8 1/1 Running 0 98s
productpage-v1-675fc69cf-tg826 1/1 Running 0 98s
ratings-v1-6484c4d9bb-x8bzv 1/1 Running 0 98s
reviews-v1-5b5d6494f4-2qwg8 1/1 Running 0 98s
reviews-v2-5b667bcbf8-bfrh6 1/1 Running 0 98s
reviews-v3-5b9bd44f4-qp867 1/1 Running 0 98s
root@k8s-master:~/istio-1.20.3# 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>
これはどうもIstioが稼働する範囲を指定し忘れたことが原因っぽいです。
以下のコマンドを使ってdefaultのnamespaceでもistioが稼働するようにします。
root@k8s-master:~/istio-1.20.3# kubectl label namespace default istio-injection=enabled
namespace/default labeled
改めてデプロイしなおして、Pod内のコンテナ数が2になるか確認します。
内部的にはEnvoyが各Podにデプロイされたことになっているはずです。公式サイトに用意されているexecコマンドを実行して<title>Simple Bookstore App</title>と出力されればOKです。
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
root@k8s-master:~/istio-1.20.3# kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
details-v1-698d88b-ngdvp 2/2 Running 0 62s
productpage-v1-675fc69cf-b24bt 2/2 Running 0 62s
ratings-v1-6484c4d9bb-c4b4f 2/2 Running 0 62s
reviews-v1-5b5d6494f4-xf495 2/2 Running 0 62s
reviews-v2-5b667bcbf8-9gkm6 2/2 Running 0 62s
reviews-v3-5b9bd44f4-5hngr 2/2 Running 0 62s
root@k8s-master:~/istio-1.20.3# 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>
このサンプルアプリケーションを使うためにはIngressが稼働していることが必要になりますので、MetalLBをデプロイ・設定していきます。
MetalLBの環境構築は私の過去の記事を参考にします。
以下のコマンドを実行し、MetalLBをデプロイします。
root@k8s-master:~/istio-1.20.3# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
MetalLBに設定を入れ込むためのyamlファイルを2つ用意します。
今回MetalLBにプールしてもらうIPアドレスレンジは192.168.2.35-192.168.2.38としました。
用意したら2つともapplyしましょう。
root@k8s-master:~/istio-1.20.3# cat IPAddressPoolMetalLB.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.2.35-192.168.2.38
root@k8s-master:~/istio-1.20.3# cat L2Advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
root@k8s-master:~/istio-1.20.3# kubectl apply -f IPAddressPoolMetalLB.yaml
ipaddresspool.metallb.io/first-pool created
root@k8s-master:~/istio-1.20.3# kubectl apply -f L2Advertisement.yaml
l2advertisement.metallb.io/example created
apply後、istioのIngress gatewaysのEXTERNAL-IPにIPアドレスが振られていることを確認します。PoolしていたIPアドレスが1つ割り当たっているはずです。
root@k8s-master:~/istio-1.20.3# kubectl get svc --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.105.75.228 192.168.2.35 15021:30100/TCP,80:32524/TCP,443:31628/TCP 65m
用意されているyamlを使ってgatewayをデプロイします。
istio analyzeで構成に問題ないことを確認します。
root@k8s-master:~/istio-1.20.3# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
root@k8s-master:~/istio-1.20.3# istioctl analyze
✔ No validation issues found when analyzing namespace: default.
http://192.168.2.35/productpageにアクセスするとBookinfoの画面が表示されます。
何度かこのページにアクセスしてみると若干レイアウトの異なるページが表示されると思います。挙動から何らかの設定によりバージョン違いのページに対してトラフィックが分散されていることがわかりますね。細かいことは調べません。自分で今後もっと簡単な環境を実装してみて、挙動を理解します。
Kialiで確認してみると、グラフィカルに確認できます。
見方は正直よくわからないので、これも今後自分で実装してみてその威力を確認できればかなぁと思いました。