K8sにIstio/Kialiを導入しGUIなサービスメッシュ環境を整える

こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

今回は久しぶりにK8s関連の記事を投稿してみます。
K8sをある程度学んだあとに出てくる内容としてよく挙げられるのはIstio(イスティオ)かなと思います。
Istioは結構複雑(~~K8sですらかなり複雑~~)なように見えますが、環境構築自体は結構簡単に出来ましたので、気になっている人はとりあえず構築して触ってみるといいのかなぁと思いました。
私も構築している現在、サービスメッシュのサの字もわかっていません。Istioを導入するとトラフィックを良い感じにルーティングしたりA/Bテストが出来るようになったりセキュリティ的にも良いらしいよねくらいのざっくりした理解しかしていません！！！！
・・・理解は徐々に。これからです💦

# 構築参考サイト
基本的にIstioとKialiの公式サイトに準じれば問題なく構築できるかと思います。

https://istio.io/latest/docs/setup/getting-started/

https://kiali.io/docs/installation/quick-start/

https://cndjp.github.io/tutorials/documents/istio/install-istio/

# 用語
## Istio

公式から説明や画像を引用させて頂きますが、個人的には「データプレーンはサービス間の通信である。サービス・メッシュがなければ、ネットワークは送信されるトラフィックを理解することができず、それがどのような種類のトラフィックなのか、あるいは誰から、あるいは誰へのトラフィックなのかに基づいた判断を下すことができない。」という部分が肝な気がしました。

K8sではアプリケーションレベルでの管理が可能で、NodePortやClusterIPを使うことでアプリケーション(≒Pod)間のつなぎ込みが出来たり、Podが意図せずにダウンした時、K8sのコントローラがそれを検知してPodを自動で再デプロイし、アプリケーションの提供が可能でした。

一方でIstioを導入するとアプリケーション間で通信しているトラフィックをベースとして管理することが可能になると。より細かい視点で管理が可能になるので、セキュリティを向上させたり、監視が容易になったりすると。。。

強いて図に起こすのであれば以下のようになるでしょうか・・・
青実線がK8sのPodやServiceを示し、赤実線がPod-Service間の通信・トラフィックを示しています。
そして青点線がK8sのコントローラが見れる部分。赤点線がIstioが見れる部分なのかなと。

![istio.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/c9ba8025-1405-e202-f548-5a68d23a45b8.png)


>Istio は、既存の分散アプリケーションに透過的に重ねられるオープンソースのサービス メッシュです。Istio の強力な機能は、サービスの保護、接続、監視を行うための統一的かつより効率的な方法を提供します。Istio は、サービス コードの変更をほとんどまたはまったく行わずに、ロード バランシング、サービス間の認証、監視を行うためのパスです。

>Istioにはデータプレーンとコントロールプレーンの2つのコンポーネントがある。データプレーンはサービス間の通信である。サービス・メッシュがなければ、ネットワークは送信されるトラフィックを理解することができず、それがどのような種類のトラフィックなのか、あるいは誰から、あるいは誰へのトラフィックなのかに基づいた判断を下すことができない。
サービスメッシュは、プロキシを使用してすべてのネットワークトラフィックを傍受し、設定された構成に基づいてアプリケーションを認識する機能の幅広いセットを可能にします。
Envoyプロキシは、クラスタ内で起動する各サービスと共にデプロイされるか、VM上で実行されるサービスと共に実行される。
コントロールプレーンは、希望する設定とサービスのビューを受け取り、動的にプロキシサーバをプログラムし、ルールや環境の変化に応じてプロキシサーバを更新します。

![1_PyQ_HN1VUMkOlnOJ6S1pjA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/a3514ead-51fb-b7cd-9eed-424e138807ff.png)

https://istio.io/latest/about/service-mesh/

## Envoy

NGINXとかの類友なイメージです。
Proxyの役割をしてくれる人。IstioではPodの中にサイドカーコンテナとしてデプロイされるみたいですが、Istio環境だけでしか使えないというわけではないです。

https://www.envoyproxy.io/

## サイドカーコンテナ

>サイドカー コンテナは、同じアプリケーション内でメイン アプリケーション コンテナと一緒に実行されるセカンダリ コンテナです。これらのコンテナは、主要なアプリケーション コードを直接変更することなく、追加のサービスやロギング、監視、セキュリティ、データ同期などの機能を提供することにより、メイン アプリケーション コンテナの機能を強化または拡張するために使用されます。

https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/

例えば、今回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

```

![istio-ページ2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/a633836b-bbf8-db14-eae6-494307e0e4a5.png)

## Kiali

IstioをWebGUIベースで管理することが出来るアプリケーションです。
読み方をChatGPTに聞いてみたら「カイアリ」と回答されたのですが、あっているのでしょうか？

https://kiali.io/

# 構築
## 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を導入していないとだめなようです。
![2024022301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/1cd28720-c806-e117-3a36-f9e13db380c7.png)
このエラーを解消するために追加で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にアクセスするとエラーは解消されてグラフが表示されます。
![2024022302.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/d57bc0a6-5cce-9372-5274-361fc8909b3b.png)
## 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の環境構築は私の過去の記事を参考にします。

https://qiita.com/ohtsuka-shota/items/2bcf2cd0d0b0c159cb8d

以下のコマンドを実行し、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の画面が表示されます。
何度かこのページにアクセスしてみると若干レイアウトの異なるページが表示されると思います。挙動から何らかの設定によりバージョン違いのページに対してトラフィックが分散されていることがわかりますね。細かいことは調べません。自分で今後もっと簡単な環境を実装してみて、挙動を理解します。
![2024022303.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/f3ec10d6-2c33-8dbc-b454-1d32fd9ae99b.png)
![2024022304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/02aac1aa-8e71-d9cd-d91f-e5c8dc34fe46.png)
![2024022305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/010e0070-9b23-964d-d00a-85f87b52201a.png)
Kialiで確認してみると、グラフィカルに確認できます。
見方は正直よくわからないので、これも今後自分で実装してみてその威力を確認できればかなぁと思いました。
![2024022306.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/34ca7c0f-4177-a63b-dfab-97c0fb562c8d.png)