Skupperを使ってMAC PCとAWS上のOpenShiftのマルチクラスタネットワークを作ってみる

# 1. はじめに

みなさん、こんにちは。

本記事では、AMQP準拠のルータ(Qpid Dispatch Router)を用いて簡単にKubernetesのマルチクラスタのアプリケーション間通信を実現するオープンソースである[Skupper](https://skupper.io/)を紹介します。

また、Istioのサンプルアプリケーションである[Bookinfo](https://istio.io/latest/docs/examples/bookinfo/)のPodをMAC PCとAWS上に配置し、Skupperを用いて接続する方法を記載します。

# 2. Skupperとは

Skupperは、KubernetesのマルチクラスタをInterconnectするソフトウェアです。

クラスタ間のネットワークを構成する方法として、[Submariner](https://submariner.io/)などのIPsecを用いる方法や、[Istio](https://istio.io/latest/docs/setup/install/multicluster/)を使用してmTLSでクラスタ跨ぎでアプリケーション間通信を制御する方法などがありますが、NATやファイアウォール越えの対応やテナント分離の課題(Cluster adminでないとdeployできない)や、取れるネットワークトポロジがフルメッシュのみであり、クラスタ数増に伴う管理の煩雑化、性能の懸念、などの課題が出てきます。

**2022年2月17日　追記:**
**Multi-Cluster Networkingの考察記事を書いたので、詳しくはこちらをご参照下さい。**

https://qiita.com/ydo/items/964888a8a642926978ba

Skupperは、非特権でnamespace単位にdeployされたQpid Dispatch Router(以降、QDR)を介してPod間通信を可能にします。対象のServiceリソースのバックエンドがQDRとなり、QDRが宛先のクラスタへルーティングするイメージです。
ルータと言いながら外部公開はL5以上でアプリケーション間通信が伝搬する形になりますので、L4以下のネットワーク情報の公開が不要でセキュアに構成でき、また、ゼロトラストソリューションにも寄与できる期待があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/88d0cff2-eed0-548c-03c1-480d16c69096.png)

尚、QDRはステートレスなアプリケーションですので、スケールアウトできます。
また、QDR間を接続して構成したネットワークは、OSPFとIS-ISに似たリンクステートルーティングプロトコルのアルゴリズムを使用して、送信元から宛先すべてにコストベースで最適なパスを計算してルーティング、障害時は迅速に復元するように動作します。

## 2-1. Skupperのユースケースイメージ
Skupperは、VPNやファイアウォールのルール、アクセスポリシーなどの複雑なL3処理を介さず、場所を問わずどこからどこへでもアプリケーション間通信を可能にするネットワークとして、Virtual Application Network(VAN)を構成できる、というコンセプトを掲げています。

VANのユースケースとして、例えば、下記が考えられるかと思いました。特にネットワークエッジに分散配置できたら、面白そうです。

- プライベートクラウド上のKubernetesクラスタとパブリッククラウド上のKubernetesクラスタをP2Pで接続し、ハイブリッドクラウドを構成する。
- 本社をHubとして、支社 to 支社の通信を本社経由で管理。支社からのデータは本社で一元化。また、本社にいるデータ分析者が、支社データを支社内に閉じた状態で活用する
- Hubとなるクラスタを通信キャリアのネットワーク上に分散配置して、エッジとクラウドを中継するネットワークを構成する、など

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/7b2e065b-67bb-cb1a-46b5-9e869565e4e2.png)

https://skupper.io/docs/overview/connectivity.html


## 2-2. アプリケーション構成
Skupperのアプリケーション構成はシンプルで、Control Planeの`skupper-service-controller`とData Planeの`skupper-router`の2コンポーネントが提供されます。

- skupper-service-controller Pod(Deployment)
  - consolenやAPIを提供（APIへは`skupper`CLIでアクセス）
  - skupper routerの設定(qdrのqdrouterd.jsonの一部箇所)をconfig-syncと連携して変更


- skupper-router Pod(Deployment)
  - routerコンテナとconfig-syncコンテナが含まれる
  - routerコンテナはQDR
  - config-syncコンテナは、skupper-service-controllerと連携してAPIやGUI上で設定されたconfigをrouterと同期する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/17f17754-c77a-5847-9bfa-f460e59e5ada.png)



# 3. Skupperを触ってみる

以下のサンプルを参考に、ローカルのMacPCとAWSのそれぞれにBookinfoの各Deploymentをdeployして、アクセスしてみます。

https://github.com/skupperproject/skupper-example-bookinfo

尚、簡単な構成は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/4e771c84-868e-c06d-5f0f-a44a3a2b0673.png)



## 3-1. 前提条件
- MAC PCへVagrantがインストールされている(私の環境では Vagrant 2.2.19)
- MAC PCへ`ocコマンド`がインストールされている
- AWSへOpenShiftがインストールされている


参考記事：

https://qiita.com/ydo/items/874c7139119a17a4ecac

## 3-2. MAC PCへSkupper CLIツールをインストール
便利ツールなのでインストールしておきます。

```bash:MacPCにて
$ curl https://skupper.io/install.sh | sh
```

## 3-3. MAC PCへOpenShift環境を構築
今回は、MAC PCへ[MicroShift](https://github.com/redhat-et/microshift)をインストールしてOpenShift環境を構築し、SkupperとBookinfoアプリケーションを実行します。

尚、MicroShiftはOpenShiftの機能をできる限り落として、ラズパイなどのSmall Factorなデバイス環境でもOpenShiftを実行できる様にしたものです。似たようなものにK3sやK0sなどがあります。

MicroShift自体はまだ実験段階のプロジェクトでRed Hatのプロダクトではなく、正式なサポートを受けられないですが、簡単に手元の環境でOpenShiftを動かせてデモやPoCで使うのに便利です。

## 3-4. MicroShiftインストール
### 3-4-1. Vagrantfileを作成

```bash:Vagrantfile
$ vi Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "fedora/35-cloud-base"
  config.vm.provider "virtualbox" do |v|
    v.memory = 4096 # 4GB
    v.cpus = 2 # 2コア
  end

  # localhostからアクセスできる様にポートフォワードしておく
  config.vm.network :forwarded_port, guest: 6443, host: 6443, id: "console"
  config.vm.network :forwarded_port, guest: 22, host: 22, id: "ssh"

  # 任意のドメインを指定
  config.vm.hostname = 'microshift.local.com'
  config.vm.provision "shell", inline: <<-SHELL
dnf module list cri-o
dnf -y module enable cri-o:1.22
dnf -y install cri-o
curl https://copr.fedorainfracloud.org/coprs/g/redhat-et/microshift-nightly/repo/fedora-34/group_redhat-et-microshift-nightly-fedora-34.repo -o /etc/yum.repos.d/microshift-nightly-fedora34.repo 2>/dev/null
cat << EOF > /etc/cni/net.d/100-crio-bridge.conf
{
    "cniVersion": "0.4.0",
    "name": "crio",
    "type": "bridge",
    "bridge": "cni0",
    "isGateway": true,
    "ipMasq": true,
    "hairpinMode": true,
    "ipam": {
        "type": "host-local",
        "routes": [
            { "dst": "0.0.0.0/0" }
        ],
        "ranges": [
            [{ "subnet": "10.42.0.0/24" }]
        ]
    }
}
EOF
dnf install -y microshift
hostnamectl set-hostname microshift.local.com # the host needs a fqdn domain for microshift to work well
dnf -y install firewalld wget
systemctl enable firewalld --now
firewall-cmd --zone=public --permanent --add-port=6443/tcp
firewall-cmd --zone=public --permanent --add-port=30000-32767/tcp
firewall-cmd --zone=public --permanent --add-port=2379-2380/tcp
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --zone=public --add-port=10250/tcp --permanent
firewall-cmd --zone=public --add-port=10251/tcp --permanent
firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16
firewall-cmd --reload
firewall-cmd --permanent --change-zone=eth0 --zone=public
systemctl enable crio
systemctl start crio
systemctl enable microshift
systemctl start microshift
# Install the oc client
ARCH=x86_64
wget -q https://mirror.openshift.com/pub/openshift-v4/$ARCH/clients/ocp/candidate/openshift-client-linux.tar.gz
mkdir tmp;cd tmp
tar -zxvf ../openshift-client-linux.tar.gz
mv -f oc /usr/local/bin
cd ..;rm -rf tmp
rm -f openshift-client-linux.tar.gz
echo "export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig" >> /root/.bash_profile
  SHELL

end
```

### 3-4-2. MicroShiftをインストール

```sh
$ vagrant status
Current machine states:

default                   not created (virtualbox)

$ vagrant up

$ vagrant status
Current machine states:

default                   running (virtualbox)

### 3-4-3. KubeConfigをローカルへコピー
$ ssh vagrant@localhost sudo cat /var/lib/microshift/resources/kubeadmin/kubeconfig > ./kubeconfig-mac
```

## 3-5. Bookinfoアプリケーションのdeploy

MAC PCとAWSそれぞれにdeployされたOpenShiftのクラスタへBookinfoアプリケーションのPodを配置します。

### 3-5-1. 事前準備

MAC PC上でターミナルを2つ開き、MAC PC側のOpenShift操作用とAWS側のOpenShift操作用としてそれぞれ使います。
MAC PC、AWSそれぞれのKubeConfigのパスをKUBECONFIG環境変数へ設定しておきます。

```sh:MAC側のターミナル
$ export KUBECONFIG=./kubeconfig-mac
$ oc create ns bookinfo
$ oc project bookinfo
```

```sh:AWS側のターミナル
$ export KUBECONFIG=./kubeconfig-aws
$ oc create ns bookinfo
$ oc project bookinfo
```

### 3-5-2. Deployment起動

マニフェストは本稿の[おまけ①](https://qiita.com/ydo/items/692f8860822263b41012#%E3%81%8A%E3%81%BE%E3%81%91bookinfo%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%83%9E%E3%83%8B%E3%83%95%E3%82%A7%E3%82%B9%E3%83%88)にまとめてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/22f1178c-8202-9d11-dc4f-876c8c41036a.png)


```sh:MAC側のターミナル
$ oc apply -f review.yaml
$ oc apply -f rating.yaml

$ oc get pods
NAME                          READY   STATUS    RESTARTS   AGE
ratings-v1-74f65555dc-fvxgh   1/1     Running   0          74s
reviews-v1-548769b868-q7t4x   1/1     Running   0          78s
reviews-v2-54f97b8f6-n9mgr    1/1     Running   0          78s
reviews-v3-7db558b8f6-zdsvc   1/1     Running   0          78s
```

```sh:AWS側のターミナル
$ oc apply -f productpage.yaml
$ oc apply -f detail.yaml

$ oc get pods
NAME                           READY   STATUS    RESTARTS   AGE
details-v1-866649cddc-clkfb    1/1     Running   0          34s
productpage-54b495bbb9-vvtv5   1/1     Running   0          47s
```

### 3-5-3. Routeの設定

AWS側のターミナルにて、`productpage` Serviceへ接続するRouteを作成します。


```sh:AWS側のターミナル
$ oc create route edge productpage --service=productpage

$ oc get route
NAME          HOST/PORT                                                      PATH   SERVICES      PORT   TERMINATION   WILDCARD
productpage   productpageのエンドポイント          productpage   http   edge          None
```

https://productpageのエンドポイント へアクセスします。
reviewsの箇所がエラーになっていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/2fcbd76d-4941-631f-0bf1-52cf13e125cd.png)

 
## 3-6. Skupperを使ってMAC PCとAWSのクラスタを接続

ここでは、[3-2. MAC PCへSkupper CLIツールをインストール](https://qiita.com/ydo/items/692f8860822263b41012#3-2-mac-pc%E3%81%B8skupper-cli%E3%83%84%E3%83%BC%E3%83%AB%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)にてダウンロードした、skupperコマンドを使った方法を記載します。

尚、OpenShiftへSkupper Site Operatorがインストールされている場合は、以下のサイトに記載されているようなConfigMapを作成することで、自動的にdeployできます。

https://skupper.io/docs/declarative/index.html


### 3-6-1. Skupperルータのdeploy

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/9c41eede-57ad-1855-6ce6-b5ad7c6e5df7.png)


```sh:MAC側のターミナル
$ skupper init
Skupper is now installed in namespace 'bookinfo'.  Use 'skupper status' to get more information.

$ oc get pods
NAME                                          READY   STATUS    RESTARTS   AGE
ratings-v1-74f65555dc-fvxgh                   1/1     Running   0          12m
reviews-v1-548769b868-q7t4x                   1/1     Running   0          12m
reviews-v2-54f97b8f6-n9mgr                    1/1     Running   0          12m
reviews-v3-7db558b8f6-zdsvc                   1/1     Running   0          12m
skupper-router-7968576b67-ndnkh               2/2     Running   0          4m10s
skupper-service-controller-65dd76576c-wd8vv   1/1     Running   0          4m8s

$ skupper status
Skupper is enabled for namespace "bookinfo" in interior mode. It is not connected to any other sites. It has no exposed services.
The site console url is:  https://skupperコンソールのドメイン
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
```

```sh:AWS側のターミナル
$ skupper init
Skupper is now installed in namespace 'bookinfo'.  Use 'skupper status' to get more information.

$ oc get pods
NAME                                          READY   STATUS    RESTARTS   AGE
details-v1-866649cddc-clkfb                   1/1     Running   0          11m
productpage-54b495bbb9-vvtv5                  1/1     Running   0          11m
skupper-router-f7dbd86c4-zwrht                2/2     Running   0          4m8s
skupper-service-controller-67f884b954-wllcl   1/1     Running   0          4m6s

$ skupper status
Skupper is enabled for namespace "bookinfo" in interior mode. It is not connected to any other sites. It has no exposed services.
The site console url is:  https://skupperコンソールのドメイン
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
```

SkupperコンソールへアクセスするとデフォルトでBasic認証がかかっており、そのユーザ名とパスワードは`skupper-console-users` Secretに記載されています。デフォルトのユーザ名は`admin`、パスワードは以下のコマンドで確認できます。

```sh
$ oc get secret skupper-console-users -o json | jq .data.admin -r | base64 -d
```

### 3-6-2. MAC PCとAWS上のSkupperルータを接続するLinkを生成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/933cb343-dae9-5e1c-ec40-25ff7d7e2857.png)


deployしたMAC PCとAWS上のSkupperルータ間を接続するLinkを作成します。

Skupperでは、接続先のクラスタで`skupper token create`コマンドを実行し、他のクラスタにあるSkupperルータからの接続を許可するSecret Tokenを生成し、接続元のクラスタで`skupper link create <生成したToken>`コマンドを実行し、接続先のクラスタのSkupperルータへLinkを張るように指示します。

尚、Link作成時は必ず **プライベートな環境からパブリックな環境へ接続するLinkを作成する** ということを意識してください。
大まかに言うと、パブリック側でToken取得、プライベート側でLink作成という流れです。
今回は、AWS側でTokenを取得し、MAC PC側からLinkを作成します。

```sh:AWS側のターミナル
$ skupper token create mac2aws.yaml
Token written to mac2aws.yaml 
```

```sh:MAC側のターミナル
$ skupper link create mac2aws.yaml  

〜数分待ちます〜

$ skupper link status
Link link1 is active

$ skupper status
Skupper is enabled for namespace "bookinfo" in interior mode. It is connected to 1 other site. It has no exposed services.
The site console url is:  https://skupperコンソールのドメイン
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
```
`skupper status`コマンドの実行結果に、`It is connected to 1 other site.`が出力されていれば正常にLinkを生成できています。


尚、Skupperコマンドを使用せず、Secretを作成することでLinkを生成することも可能です。
例えば、下記の様な流れになります。

```sh:AWS側のターミナル
$ vi token-request.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    skupper.io/type: connection-token-request
  name: link1

$ oc apply -f token-request.yaml

$ oc get secret -o yaml link1 > ~/link1.yaml
```

```sh:MAC側のターミナル
$ oc apply -f link1.yaml
```

### 3-6-3. SkupperとServiceの関連付け(Serviceの仮想化)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/2156533f-62c7-51a2-3561-f0b752ad2983.png)



`skupper link`によって、マルチクラスターで通信可能なSkupperネットワークを構成できましたが、
まだ各ServiceはSkupperネットワークに組み込まれていることを認識しておらず、サービスディスカバリができません。

現状、AWS側のServiceは以下の状態となっており、`reviews`と`ratings`を管理していません。

```sh:AWS側のターミナル
$ oc get svc
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)               AGE
details                ClusterIP      172.30.170.94    <none>                                                                        9080/TCP              38m
productpage            LoadBalancer   172.30.91.218    ab978fa268317413a819a0415c527140-637765270.ap-northeast-1.elb.amazonaws.com   9080:32494/TCP        39m
skupper                ClusterIP      172.30.38.110    <none>                                                                        8080/TCP,8081/TCP     31m
skupper-router         ClusterIP      172.30.48.78     <none>                                                                        55671/TCP,45671/TCP   31m
skupper-router-local   ClusterIP      172.30.238.212   <none>                                                                        5671/TCP              31m
```

Skupperは、Serviceへ付与されたannotationを元に、Skupperネットワークと関連付けられたServiceを特定し、そのServiceを仮想的なServiceとして管理します。

今回は、AWS側で実行中の`productpage`がMAC PC上で実行中の`reviews`をサービスディスカバリできるように、MAC PC上の`reviews`　Serviceへannotationを付与します。
すると、AWS側で、仮想的なServiceとして`reviews`　Serviceを認識できる様になります。

以下の様に、AWS側でディスカバリしたいMAC PC側のServiceへ`oc annotate`コマンドを使用してannotationを付与し、ServiceがSkupperネットワークに含まれることをSkupperに通知します。

```sh:MAC側のターミナル
$ oc annotate service reviews skupper.io/proxy=http
```

AWS側で再度Serviceの状態を確認すると、`reviews`が表示されます。

```sh:AWS側のターミナル
$ oc get svc
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)               AGE
details                ClusterIP      172.30.170.94    <none>                                                                        9080/TCP              154m
productpage            LoadBalancer   172.30.91.218    ab978fa268317413a819a0415c527140-637765270.ap-northeast-1.elb.amazonaws.com   9080:32494/TCP        154m
reviews                ClusterIP      172.30.96.136    <none>                                                                        9080/TCP              111m
skupper                ClusterIP      172.30.38.110    <none>                                                                        8080/TCP,8081/TCP     147m
skupper-router         ClusterIP      172.30.48.78     <none>                                                                        55671/TCP,45671/TCP   147m
skupper-router-local   ClusterIP      172.30.238.212   <none>                                                                        5671/TCP              147m
```

ここで再度、https://productpageのエンドポイント へアクセスしてみると、
正常にreviewsとratingsが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559968/38d89936-6df9-a00d-08e2-dae3f1b0c516.png)


尚、annotationは`skupper expose`コマンドを使っても付与できます。

```sh:例
$ skupper expose service reviews --address reviews --protocol http
```


## 3-7. 環境のクリーンアップ

```sh
$ oc delete ns bookinfo
```

# 4. まとめ
本稿では、Skupperの紹介と、Skupperを使ったマルチクラスタ環境でBookinfoアプリケーションを実行するデモを構築してみました。

テストした感じ、簡単にクラスタ間ネットワークを構成できるお手軽感があるものの、オブザーバビリティはこれからな印象でした。
また、2クラスタ程度の接続なら問題ないですが、複数のクラスタでネットワークを構成するとなると、お絵描きしながらでないと混乱する＆クラスタ数が増えるとマニフェストの管理が煩雑になりそう、と言う所感でした。

ただ、QDR自体はマチュアな技術ですので、不足している部分は代替手段があるかなと思いますし、IPsecを使う方法と比較すると非常に軽量に動きますので、オススメです。特にエッジコンピューティングでハイブリッドクラウドを構成するのに使えそうだなと思いました。

みなさんも是非お試しください！

# 5. 参考リンク
- https://skupper.io/index.html
- https://github.com/skupperproject/skupper-example-bookinfo
- https://itnext.io/virtual-application-networks-van-for-multi-cloud-multi-cluster-and-cloud-edge-interconnect-1f63a8081f41
- https://access.redhat.com/documentation/ja-jp/red_hat_amq/2021.q2/html/creating_amq_interconnect_sites_using_the_operator/using-skupper-operator-skupper-rhel
- https://access.redhat.com/documentation/ja-jp/red_hat_amq/2021.q4/html/using_the_amq_interconnect_router/index

# おまけ①　Bookinfoアプリケーションのマニフェスト

## productpage.yaml
```yaml:productpage.yaml
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: productpage
  labels:
    app: productpage
    service: productpage
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: productpage
  type: LoadBalancer 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      containers:
      - name: productpage
        image: docker.io/maistra/examples-bookinfo-productpage-v1:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
```

## details.yaml
```yaml:details.yaml
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: details
  labels:
    app: details
    service: details
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true"
      labels:
        app: details
        version: v1
    spec:
      containers:
      - name: details
        image: docker.io/maistra/examples-bookinfo-details-v1:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
```

## ratings.yaml

```yaml:ratings.yaml
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: ratings
  labels:
    app: ratings
    service: ratings
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratings-v1
  labels:
    app: ratings
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ratings
  template:
    metadata:
      labels:
        app: ratings
        version: v1
    spec:
      containers:
      - name: ratings
        image: docker.io/maistra/examples-bookinfo-ratings-v1:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
```

## reviews.yaml

```yaml:reviews.yaml
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      containers:
      - name: reviews
        image: docker.io/maistra/examples-bookinfo-reviews-v1:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
      - name: reviews
        image: docker.io/maistra/examples-bookinfo-reviews-v2:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      containers:
      - name: reviews
        image: docker.io/maistra/examples-bookinfo-reviews-v3:0.12.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
```



# おまけ②　Skupperルータの状態確認コマンド

```
$ oc exec -it skupper-router-xxxxxxxxx-yyyyy -c router -- qdstat --all-entities
```

ルータの詳細については以下のサイトが参考になります。

https://access.redhat.com/documentation/ja-jp/red_hat_amq/2021.q1/html-single/using_amq_interconnect/index#routing-patterns-message-routing-router-rhel


https://qpid.apache.org/components/dispatch-router/index.html