これはRed Hat Advent Calendar 2023の15日目の記事です。
概要
この記事では、Red Hat Service Interconnect(RHSI)という、環境やプラットフォームに関係なくアプリケーションやサービスが相互に通信できるようにするソフトウェアを使って、アプリケーションのCloud Burstingを試みます。
※内容自体は、おおまかにはこちらを日本語に翻訳したものとなります。
そもそもRed Hat Service Interconnectとは
世の中には既にRed Hat Service Interconnect、およびそのUpstreamであるSkupperに関する優れた記事が沢山存在するため、細かい話は割愛しますが、Site
という概念をLink
というものでセキュアにつないだVirtual Application Network(VAN)というものを作ることができる、というソフトウェアです。
以下の記事などを参照することで、より詳しい情報を得ることができます。
- AMQP InterconnectベースでKubernetesのマルチクラスタ間のネットワークを構成するSkupperのご紹介
- Skupperを使ってMAC PCとAWS上のOpenShiftのマルチクラスタネットワークを作ってみる
- Red Hat Service InterconnectでNAT越えのアプリ間連携を簡単に!
- Skupperで遊ぶ
- Skupperを使ってクラスタ間を結びコンテナイメージをコピー
また、色々読み漁っていると、SkupperはIstioと一部類似しているというかオーバーラップしている部分がある気がするけど、何が違うのだろうと感じることもあるかと思いますが、RHSIとRed Hat OpenShit Service Mesh(OSSM、IstioのRed Hat製品版。正確にはMaistraがこの記事投稿時点のOSSM 2.xのアップストリームで、MaistraはIstioに基づいています。)の比較の話がこのへんにあったりしますので、製品版の話で恐縮ですがこちらも参考にしていただければと思います。
本題
RHSIのユースケースの一つとして、Cloud Burstingがあります。
Cloud Burstingは、例えば現在アプリケーションが動作している基盤のリソースが足りなくなった時に、一時的にクラウド側のリソースを使ってアプリケーションをスケールする、という、昔からよく聞くような話です。
RHSIは、これを後付けで比較的容易に実現させることができる可能性を持っています。
RHSIでは、複数の場所(この場所をSite
と呼びます)に跨って仮想的なService
(KubernetesのService
のことだと思ってもらって構いません)を容易に作成できますが、それぞれのSite
で、その仮想的なService
に様々なバックエンドをバインドすることができます。
RHSIはVAN anycastやDynamic Load Balancingといった機能を持っていて、これらの機能に基づき
- ある仮想
Service
にアクセスすると、そのService
にバインドされたバックエンドのうち、RHSIの備えるLinkState Routing Protocolに基づき、最小コストの経路のSite
にあるものにトラフィックをルーティングする -
Service
にはキャパシティ(リクエスト数やOpen Connection数などに対する閾値だと思ってもらえると良いと思います)があり、そのキャパシティを超える場合、次にコストの低い経路のSite
のものにトラフィックをルーティングする- ローカル(アクセス元と
Service
が同一のSite
)の場合はコストが0であるため、まずはローカルのバックエンドにルーティングし、キャパシティを超えた場合は他のSite
のバックエンドにルーティングする
- ローカル(アクセス元と
という振る舞いをします。
わかりにくいですが要するに、同じService
にアクセスが続いた時、あるSite
で捌けなくなったら他のSite
に転送し始めます。
※このキャパシティはprotocolなどによって違ったりするようですが、2023/12/15現在、ドキュメントを見ても何が閾値として使われているのかは明言されおらず、細かく調整するパラメータも存在せず、滲み出やすさはLink Costに依存しているようです。
この記事では、これらの機能を活用してアプリケーションのCloud Burstingを試みます。
使うアプリケーション
今回は、Quarkusで作られたマイクロサービス群がイベントで連携して業務を処理する、イベント駆動アーキテクチャで構成された Quarkus Coffeeshop アプリケーション使用します。
元々のQuarkus Coffeeshopのソースコードはこちらになりますが、この記事では、元がイベント駆動アーキテクチャを実現するためにApache Kafkaに直接接続していたところについて、OpenShift ServerlessのEventingで連携するように改変したものを使用しています。この改変版アプリケーションのイメージは事前にQuay.ioにアップロード済みで、アプリケーションを展開するための必要なマニフェストはこのリポジトリに入っています。
構成の全体図と補足、および前提
全体的な構成は以下のようになります。cluster1
やSomewhere
がオンプレミス、cluster2
がクラウドで、黄色い部分がVAN、点線でつながったService
が仮想的なService
だと思っていただけると良いかと思います。
なお後述しますが、今回の構成だとknative-eventing
内で色々操作できる権限が必要であるため、一般ユーザだけで同じ事をする場合はbroker-ingress
への参照を工夫するなどの手段をとります。
処理の流れは大体以下のようになっています。
- Web UIやAPIでコーヒーや食べ物をオーダーすると、Web UIはオーダーがきたイベントを流す
- オーダーがきたイベントがcounterに流れることでcounterがオーダーを受け付け、受け付けた事をDBに書き込み、状態更新イベント(受け付けた)と、コーヒーや食べ物のオーダーイベントを流す
- オーダーを受け付けたイベントはWeb UIに流れ、画面を更新する
- コーヒーのオーダーイベントは、いずれかのbaristaに流れ、コーヒーを作り始める
- 食べ物のオーダーイベントは、いずれかのkitchenに流れ、食べ物を作り始める
- コーヒーや食べ物を作り終わったbaristaやkitchenは、作り終えたイベントを流す
- 作り終えたイベントはcounterに流れ、DBのステータスを更新し、状態更新イベント(オーダーされたものが出来上がった)イベントを流す
- 状態更新イベント(オーダーされたものが出来上がった)イベントはWeb UIに流れ、画面を更新する
※イベントを流すのは、OpenShift ServerlessのEventingがTrigger
を使って行います。
補足
-
今回利用している
Gateway
はRHSIの機能の一つで、VAN内から特定のService
にアクセスしたときにクラスタの外部にあるIP:Portへのアクセスに変換したり、逆にVAN外から特定のIP:Portにアクセスしたときにクラスタ内のService
へのアクセスに変換するような役割を持っています。 -
先述のとおり、今回は
knative-eventing
にあるbroker-ingress
を直接exposeしてしまいましたが、例えば以下のようにbroker-ingress.knative-eventing.svc.cluster.local
へのExternalName
をexposeして参照するなどの手段によって、一般ユーザ権限だけで動作させることができるのを確認済みです。- OpenShift Serverless Operator自体は、管理者によって利用可能にしておいてもらう必要があります。
[lab-user@bastion ~]$ oc get service/broker-ingress -n cbcs
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
broker-ingress ExternalName <none> broker-ingress.knative-eventing.svc.cluster.local 80/TCP 117m
[lab-user@bastion ~]$ skupper service status
Services exposed through Skupper:
├─ quarkuscoffeeshop-counter (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-counter name=quarkuscoffeeshop-counter
├─ quarkuscoffeeshop-kitchen (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-kitchen name=quarkuscoffeeshop-kitchen
├─ broker-ingress (tcp port 80)
│ ╰─ Targets:
│ ╰─ broker-ingress name=broker-ingress
╰─ quarkuscoffeeshop-barista (http port 80)
╰─ Targets:
╰─ app=quarkuscoffeeshop-barista name=quarkuscoffeeshop-barista
baristaなどの各Deployment
は環境変数でbroker-ingress
への参照を変更できるため、本当に動くのか気になる方は是非試してみてください。
前提
-
2つの Red Hat OpenShift クラスタとして、
cluster1
とcluster2
があるとします- この2つのクラスタにある
Site
間でCloud Burstingします
- この2つのクラスタにある
-
DB用のRHELサーバがあるとします
-
Gateway
が動作することも確認したかったため、今回DBはクラスタの外のどこかのRHELサーバに置いて、Gateway
で通信させることにします - また、今回
Gateway
はDBと同一のサーバで起動することにします
-
-
RHSIのバージョンは
1.4.3
を利用します -
作業するマシンには https://gitlab.com/m-muraki/skupper-cloud-bursting-demo が
git clone
されているとします- ブランチは
ocp-rhsi
です
- ブランチは
-
今回の記事ではサブスクリプション関係の操作は省略していますが、実際は正しく処理する必要があります
作業
ここから実際の作業に入りますが、前提を揃えるのが大変だったり手順がそこそこ長いため、とりあえず動いているところが見たい、という方は以下のGifアニメーションをご覧いただければと思います。
Quarkus Coffeeshopの各マイクロサービスをcluster1
のSite
にデプロイ
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster1
に切り替えておきます -
skupper-cloud-bursting-demo/cluster1/app
ディレクトリで作業します - アプリケーションのURL(
Route
の.spec.host
)はwww.example.com
であるとします- この部分は、実際の設定に合わせて読み替えてください
Quarkus CoffeeshopのDB以外を動かすSite
用に、cbcs
という名前のproject
を作成
$ oc new-project cbcs
Now using project "cbcs" on server "https://api.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
Quarkus CoffeeshopのDBService
を置く用のSite
として、cbcs-db
という名前のproject
を作成
$ oc new-project cbcs-db
Now using project "cbcs-db" on server "https://api.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
Quarkus Coffeeshopが使うSecret
とConfigMap
を作成
$ oc create secret generic \
--from-literal POSTGRES_USER=coffeeshopuser \
--from-literal POSTGRES_PASSWORD=redhat-21 \
secret-quarkuscoffeeshop -n cbcs
secret/secret-quarkuscoffeeshop created
$ oc create secret generic \
--from-literal POSTGRES_USER=coffeeshopuser \
--from-literal POSTGRES_PASSWORD=redhat-21 \
secret-quarkuscoffeeshop -n cbcs-db
secret/secret-quarkuscoffeeshop created
Web UIのManifest内のホスト名は、環境に合わせて置換します。
$ oc create configmap \
--from-literal CORS_ORIGINS=http://www.example.com/dashboard/ \
--from-literal LOYALTY_STREAM_URL=http://www.example.com/dashboard/loyaltystream \
--from-literal POSTGRES_DB=coffeeshopdb \
--from-literal POSTGRES_URL=jdbc:postgresql://quarkuscoffeeshop-postgresql.cbcs-db.svc.cluster.local:5432/coffeeshopdb?currentSchema=coffeeshop \
--from-literal QUARKUS_LOG_LEVEL=INFO \
--from-literal STORE_ID=RALEIGH \
--from-literal STREAM_URL=http://www.example.com/dashboard/stream \
--from-literal SITE=Site1 \
configmap-quarkuscoffeeshop -n cbcs
configmap/configmap-quarkuscoffeeshop created
$ oc create configmap \
--from-literal POSTGRES_DB=coffeeshopdb \
configmap-quarkuscoffeeshop -n cbcs-db
configmap/configmap-quarkuscoffeeshop created
Quarkus Coffeeshopをデプロイ
$ oc apply -f .
deployment.apps/quarkuscoffeeshop-web created
service/quarkuscoffeeshop-web created
route.route.openshift.io/quarkuscoffeeshop-web created
deployment.apps/quarkuscoffeeshop-counter created
service/quarkuscoffeeshop-counter created
deployment.apps/quarkuscoffeeshop-barista created
service/quarkuscoffeeshop-barista created
deployment.apps/quarkuscoffeeshop-kitchen created
service/quarkuscoffeeshop-kitchen created
Quarkus Coffeeshopがデプロイされていることを確認
この段階ではcounterはレプリカ数が0になっていますが、後で起動するため、このままで問題ありません。
$ oc get deployment -n cbcs
NAME READY UP-TO-DATE AVAILABLE AGE
quarkuscoffeeshop-barista 3/3 3 3 45s
quarkuscoffeeshop-counter 0/0 0 0 45s
quarkuscoffeeshop-kitchen 3/3 3 3 45s
quarkuscoffeeshop-web 1/1 1 1 45s
$ oc get pod -n cbcs
NAME READY STATUS RESTARTS AGE
quarkuscoffeeshop-barista-65ff59d99f-7rjh4 1/1 Running 0 66s
quarkuscoffeeshop-barista-65ff59d99f-ggsn7 1/1 Running 0 66s
quarkuscoffeeshop-barista-65ff59d99f-xkrtk 1/1 Running 0 66s
quarkuscoffeeshop-kitchen-79bc8745c-6tnkq 1/1 Running 0 66s
quarkuscoffeeshop-kitchen-79bc8745c-fnjnf 1/1 Running 0 66s
quarkuscoffeeshop-kitchen-79bc8745c-vlphm 1/1 Running 0 66s
quarkuscoffeeshop-web-9fc5675cb-rjtkg 1/1 Running 0 66s
$ oc get service -n cbcs
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
quarkuscoffeeshop-barista ClusterIP 172.30.133.48 <none> 80/TCP 83s
quarkuscoffeeshop-counter ClusterIP 172.30.12.100 <none> 80/TCP 83s
quarkuscoffeeshop-kitchen ClusterIP 172.30.28.125 <none> 80/TCP 83s
quarkuscoffeeshop-web ClusterIP 172.30.111.217 <none> 80/TCP 83s
$ oc get route -n cbcs
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
quarkuscoffeeshop-web quarkuscoffeeshop-web-cbcs.apps.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com quarkuscoffeeshop-web 8080 edge/Redirect None
$ oc get all -n cbcs-db
No resources found in cbcs-db namespace.
OpenShift Serverlessのoperatorをインストールし、関連するリソースを作成
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster1
に切り替えておきます -
skupper-cloud-bursting-demo/cluster1/opensift-serverless
ディレクトリで作業します
OpenShift Serverlessのoperatorをインストールし、関連するリソースを作成します
$ oc apply -f 01_subs_openshift_serverless.yaml
subscription.operators.coreos.com/serverless-operator created
$ oc apply -f 02_knative_serving.yaml
knativeserving.operator.knative.dev/knative-serving created
$ oc apply -f 03_knative_eventing.yaml
knativeeventing.operator.knative.dev/knative-eventing created
$ oc apply -f 04_configmap_cbcs_mt_channel_based_broker_config.yaml
configmap/cbcs-mt-channel-based-broker-config created
$ oc apply -f 05_broker_cbcs_mt_channel_based_broker.yaml
broker.eventing.knative.dev/cbcs-mt-channel-based-broker created
$ oc apply -f 06_trigger_cbcs_kafka_broker_web.yaml
trigger.eventing.knative.dev/cbcs-mt-channel-based-broker-web-web-updates created
$ oc apply -f 07_trigger_cbcs_kafka_broker_counter.yaml
trigger.eventing.knative.dev/cbcs-mt-channel-based-broker-counter-orders-in created
trigger.eventing.knative.dev/cbcs-mt-channel-based-broker-counter-orders-up created
$ oc apply -f 08_trigger_cbcs_kafka_broker_barista.yaml
trigger.eventing.knative.dev/cbcs-mt-channel-based-broker-barista-barista-in created
$ oc apply -f 09_trigger_cbcs_kafka_broker_kitchen.yaml
trigger.eventing.knative.dev/cbcs-mt-channel-based-broker-kitchen-kitchen-in created
broker
とtrigger
が作成されていることを確認します
$ oc get broker -n cbcs
NAME URL AGE READY REASON
cbcs-mt-channel-based-broker http://broker-ingress.knative-eventing.svc.cluster.local/cbcs/cbcs-mt-channel-based-broker 81s True
$ oc get trigger -n cbcs
NAME BROKER SUBSCRIBER_URI AGE READY REASON
cbcs-mt-channel-based-broker-barista-barista-in cbcs-mt-channel-based-broker http://quarkuscoffeeshop-barista.cbcs.svc.cluster.local/barista-in 90s True
cbcs-mt-channel-based-broker-counter-orders-in cbcs-mt-channel-based-broker http://quarkuscoffeeshop-counter.cbcs.svc.cluster.local/orders-in 93s True
cbcs-mt-channel-based-broker-counter-orders-up cbcs-mt-channel-based-broker http://quarkuscoffeeshop-counter.cbcs.svc.cluster.local/orders-up 93s True
cbcs-mt-channel-based-broker-kitchen-kitchen-in cbcs-mt-channel-based-broker http://quarkuscoffeeshop-kitchen.cbcs.svc.cluster.local/kitchen-in 87s True
cbcs-mt-channel-based-broker-web-web-updates cbcs-mt-channel-based-broker http://quarkuscoffeeshop-web.cbcs.svc.cluster.local/web-updates 96s True
ここからは、このQuarkus Coffeeshopがもう1つのクラスタのSite
にCloud Burstingできるようにするための準備を行います。
もう1つのクラスタ側にQuarkus Coffeeshopをデプロイ
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster2
に切り替えておきます -
skupper-cloud-bursting-demo/cluster2/app
ディレクトリで作業します
Cloud Burstingに向けたSite
用に、それぞれproject
を作ります
$ oc new-project cbcs
Now using project "cbcs" on server "https://api.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
$ oc new-project cbcs-db
Now using project "cbcs-db" on server "https://api.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
$ oc new-project knative-eventing
Now using project "knative-eventing" on server "https://api.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
Quarkus Coffeeshopが使うSecret
とConfigMap
を作成します
今回は手動でSecret
とConfigMap
の同期相当の作業を行います。
$ oc create secret generic \
--from-literal POSTGRES_USER=coffeeshopuser \
--from-literal POSTGRES_PASSWORD=redhat-21 \
secret-quarkuscoffeeshop -n cbcs
secret/secret-quarkuscoffeeshop created
$ oc create configmap \
--from-literal POSTGRES_URL=jdbc:postgresql://quarkuscoffeeshop-postgresql.cbcs-db.svc.cluster.local:5432/coffeeshopdb?currentSchema=coffeeshop \
--from-literal QUARKUS_LOG_LEVEL=INFO \
--from-literal SITE=Site2 \
configmap-quarkuscoffeeshop -n cbcs
configmap/configmap-quarkuscoffeeshop created
Quarkus Coffeeshopをデプロイします
$ oc apply -f .
deployment.apps/quarkuscoffeeshop-counter created
deployment.apps/quarkuscoffeeshop-barista created
deployment.apps/quarkuscoffeeshop-kitchen created
Quarkus Coffeeshopがデプロイされていることを確認します
$ oc get all -n cbcs
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/quarkuscoffeeshop-barista 0/0 0 0 116s
deployment.apps/quarkuscoffeeshop-counter 0/0 0 0 116s
deployment.apps/quarkuscoffeeshop-kitchen 0/0 0 0 116s
NAME DESIRED CURRENT READY AGE
replicaset.apps/quarkuscoffeeshop-barista-58778897c9 0 0 0 116s
replicaset.apps/quarkuscoffeeshop-counter-6b8554bb95 0 0 0 116s
replicaset.apps/quarkuscoffeeshop-kitchen-84cc77dcc7 0 0 0 116s
$ oc get all -n cbcs-db
No resources found in cbcs-db namespace.
$ oc get all -n knative-eventing
No resources found in knative-eventing namespace.
各Site
の初期化とLink
の作成
ここからはRHSIのVANを作っていきます。
cluster1
のSite
の初期化を行い、Link
を作成するためのToken
を作成します
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster1
に切り替えておきます -
skupper-cloud-bursting-demo/cluster1/service-interconnect
ディレクトリで作業します
$ skupper version
client version 1.4.3
transport version not-found
controller version not-found
config-sync version not-found
flow-collector version not-found
$ oc apply -f 01_subs_service_interconnect.yaml
subscription.operators.coreos.com/skupper-operator created
$ oc apply -f 02_configmap_cbcs-site1.yaml -n cbcs
configmap/skupper-site created
$ skupper status -n cbcs
Skupper is enabled for namespace "cbcs" with site name "cbcs-site1" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-cbcs.apps.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f 03_configmap_cbcs-db-site1.yaml -n cbcs-db
configmap/skupper-site created
$ skupper status -n cbcs-db
Skupper is enabled for namespace "cbcs-db" with site name "cbcs-db-site1" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-cbcs-db.apps.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f 04_configmap_knative-eventing-site1.yaml -n knative-eventing
configmap/skupper-site created
$ skupper status -n knative-eventing
Skupper is enabled for namespace "knative-eventing" with site name "knative-eventing-site1" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-knative-eventing.apps.cluster-pbpbp.pbpbp.sandbox3038.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f 05_secret_tokenrequest-cbcs-site2-to-site1.yaml -n cbcs
secret/tokenrequest-cbcs-site2-to-site1 created
$ oc get secret/tokenrequest-cbcs-site2-to-site1 -o yaml -n cbcs | grep -v "namespace:" > /tmp/secret_token-cbcs-site2-to-site1.yaml
$ oc apply -f 06_secret_tokenrequest-cbcs-db-site2-to-site1.yaml -n cbcs-db
secret/tokenrequest-cbcs-db-site2-to-site1 created
$ oc get secret/tokenrequest-cbcs-db-site2-to-site1 -o yaml -n cbcs-db | grep -v "namespace:" > /tmp/secret_token-cbcs-db-site2-to-site1.yaml
$ oc apply -f 07_secret_tokenrequest-knative-eventing-site2-to-site1.yaml -n knative-eventing
secret/tokenrequest-knative-eventing-site2-to-site1 created
$ oc get secret/tokenrequest-knative-eventing-site2-to-site1 -o yaml -n knative-eventing | grep -v "namespace:" > /tmp/secret_token-knative-eventing-site2-to-site1.yaml
cluster2
のSite
の初期化を行い、先程cluster1
のSite
で作ったToken
を使ってLink
を作成します
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster2
に切り替えておきます -
skupper-cloud-bursting-demo/cluster2/service-interconnect
ディレクトリで作業します
$ skupper version
client version 1.4.3
transport version not-found
controller version not-found
config-sync version not-found
flow-collector version not-found
$ oc apply -f 01_subs_service_interconnect.yaml
subscription.operators.coreos.com/skupper-operator created
$ oc apply -f 02_configmap_cbcs-site2.yaml -n cbcs
configmap/skupper-site created
$ skupper status -n cbcs
Skupper is enabled for namespace "cbcs" with site name "cbcs-site2" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-cbcs.apps.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f 03_configmap_cbcs-db-site2.yaml -n cbcs-db
configmap/skupper-site created
$ skupper status -n cbcs-db
Skupper is enabled for namespace "cbcs-db" with site name "cbcs-db-site2" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-cbcs-db.apps.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f 04_configmap_knative-eventing-site2.yaml -n knative-eventing
configmap/skupper-site created
$ skupper status -n knative-eventing
Skupper is enabled for namespace "knative-eventing" with site name "knative-eventing-site2" in interior mode. Status pending... It has no exposed services.
The site console url is: https://skupper-knative-eventing.apps.azure-pbpbp-1.pbpbp-1.sandbox2180.opentlc.com
The credentials for internal console-auth mode are held in secret: 'skupper-console-users'
$ oc apply -f /tmp/secret_token-cbcs-site2-to-site1.yaml -n cbcs
secret/tokenrequest-cbcs-site2-to-site1 created
$ oc apply -f /tmp/secret_token-cbcs-db-site2-to-site1.yaml -n cbcs-db
secret/tokenrequest-cbcs-db-site2-to-site1 created
$ oc apply -f /tmp/secret_token-knative-eventing-site2-to-site1.yaml -n knative-eventing
secret/tokenrequest-knative-eventing-site2-to-site1 created
Site
間でLink
が作成され、connected
になっていることを確認します
$ skupper link status -n cbcs
Links created from this site:
Link tokenrequest-cbcs-site2-to-site1 is connected
$ skupper link status -n cbcs-db
Links created from this site:
Link tokenrequest-cbcs-db-site2-to-site1 is connected
$ skupper link status -n knative-eventing
Links created from this site:
Link tokenrequest-knative-eventing-site2-to-site1 is connected
Service
はまだexposeされていないことを確認します
$ skupper service status -n cbcs
No services defined
$ skupper service status -n cbcs-db
No services defined
$ skupper service status -n knative-eventing
No services defined
RHELサーバでDBを起動して、Gateway
を起動し、cbcs-db
でDBのService
をexpose
DBを起動し、RHSIを通して接続可能な状態にします。
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster1
に切り替えておきます -
skupper-cloud-bursting-demo/gateway_db
ディレクトリで作業します
RHELサーバでDBを起動します
[lab-user@bastion gateway_db]$ podman run -d --rm --name postgresql -p 5432:5432 -e POSTGRES_USER=coffeeshopuser -e POSTGRES_PASSWORD=redhat-21 -e POSTGRES_DB=coffeeshopdb -v ./init-postgresql.sql:/docker-entrypoint-initdb.d/init-postgresql.sql:Z postgres:11
7601886d56198be7c6eea1471b1eccd5ce365b83014a11d0d0de8062ee99f227
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7601886d5619 docker.io/library/postgres:11 postgres 52 seconds ago Up 52 seconds ago 0.0.0.0:5432->5432/tcp postgresql
RHELサーバでGateway
を初期化して、cbcs-db
でDBのservice
をexposeします
$ skupper gateway init --type podman -n cbcs-db
Skupper gateway: 'bastion.example.com-lab-user'. Use 'skupper gateway status' to get more information.
$ skupper service create quarkuscoffeeshop-postgresql --protocol tcp 5432 -n cbcs-db
$ skupper gateway bind quarkuscoffeeshop-postgresql 127.0.0.1 5432 -n cbcs-db
2023/11/16 15:25:24 CREATE io.skupper.router.tcpConnector quarkuscoffeeshop-postgresql:5432 map[address:quarkuscoffeeshop-postgresql:5432 host:127.0.0.1 name:quarkuscoffeeshop-postgresql:5432 port:5432 siteId:544d21d1-81eb-4c91-add8-88adcf47123b]
※上記のinitコマンド・createコマンド・bindコマンドのセットは、exposeコマンドだけでも同じ事ができます。
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7601886d5619 docker.io/library/postgres:11 postgres About a minute ago Up About a minute ago 0.0.0.0:5432->5432/tcp postgresql
5ce212f754be quay.io/skupper/skupper-router:2.4.3 /home/skrouterd/b... 28 seconds ago Up 28 seconds ago bastion.example.com-lab-user
$ skupper gateway status -n cbcs-db
Gateway Definition:
╰─ bastion.example.com-lab-user type:podman version:2.4.3
╰─ Bindings:
╰─ quarkuscoffeeshop-postgresql:5432 tcp quarkuscoffeeshop-postgresql:5432 127.0.0.1 5432
$ skupper service status -n cbcs-db
Services exposed through Skupper:
╰─ quarkuscoffeeshop-postgresql (tcp port 5432)
cluster1
で、DB以外のService
もexpose
DB以外にも仮想Service
を作り、この後のcluster2
のSite
でのバックエンドのバインドに備えます。
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster1
に切り替えておきます
まず、Service
がexposeされていないことを確認します
$ skupper service status -n cbcs
No services defined
$ skupper service status -n cbcs-db
No services defined
$ skupper service status -n knative-eventing
No services defined
既存のService
にannotationを付与することでService
をexposeします
$ oc annotate service quarkuscoffeeshop-barista skupper.io/proxy=http -n cbcs
service/quarkuscoffeeshop-barista annotated
$ oc annotate service quarkuscoffeeshop-kitchen skupper.io/proxy=http -n cbcs
service/quarkuscoffeeshop-kitchen annotated
$ oc annotate service quarkuscoffeeshop-counter skupper.io/proxy=http -n cbcs
service/quarkuscoffeeshop-counter annotated
$ oc annotate service broker-ingress skupper.io/proxy=http -n knative-eventing
service/broker-ingress annotated
Service
がexposeされていることを確認します
$ skupper service status -n cbcs
Services exposed through Skupper:
├─ quarkuscoffeeshop-barista (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-barista name=quarkuscoffeeshop-barista
├─ quarkuscoffeeshop-counter (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-counter name=quarkuscoffeeshop-counter
╰─ quarkuscoffeeshop-kitchen (http port 80)
╰─ Targets:
╰─ app=quarkuscoffeeshop-kitchen name=quarkuscoffeeshop-kitchen
$ skupper service status -n cbcs-db
Services exposed through Skupper:
╰─ quarkuscoffeeshop-postgresql (tcp port 5432)
$ skupper service status -n knative-eventing
Services exposed through Skupper:
╰─ broker-ingress (http ports 80 9092)
╰─ Targets:
╰─ eventing.knative.dev/brokerRole=ingress name=broker-ingress
このSite
にはquarkuscoffeeshop-postgresql
にはTargets
は存在せず、少し前の手順で設定したGateway
を通してRHELサーバのDBにアクセスすることになります。(Gateway
側にはquarkuscoffeeshop-postgresql
に対するBindings
が表示されています。)
Quarkus Coffeeshopのcounterをスケールアップします
counterはDBへアクセスしますが、上記の手順が終わるまではDBが起動していなかったり、Service
も見えなかったりするため、接続不能で少なからずエラーが発生してしまいます。そのため、今回は上記の手順によるDB起動とGateway
によるService
のexposeの後でcounterが起動するようにしています。
$ oc scale deployment/quarkuscoffeeshop-counter --replicas=3 -n cbcs
deployment.apps/quarkuscoffeeshop-counter scaled
oc get pods -n cbcs
NAME READY STATUS RESTARTS AGE
quarkuscoffeeshop-barista-65ff59d99f-7rjh4 1/1 Running 0 75m
quarkuscoffeeshop-barista-65ff59d99f-ggsn7 1/1 Running 0 75m
quarkuscoffeeshop-barista-65ff59d99f-xkrtk 1/1 Running 0 75m
quarkuscoffeeshop-counter-66fbdc8f5b-56f7t 1/1 Running 0 12s
quarkuscoffeeshop-counter-66fbdc8f5b-fjnpv 1/1 Running 0 12s
quarkuscoffeeshop-counter-66fbdc8f5b-ww6n8 1/1 Running 0 12s
quarkuscoffeeshop-kitchen-79bc8745c-6tnkq 1/1 Running 0 75m
quarkuscoffeeshop-kitchen-79bc8745c-fnjnf 1/1 Running 0 75m
quarkuscoffeeshop-kitchen-79bc8745c-vlphm 1/1 Running 0 75m
quarkuscoffeeshop-web-9fc5675cb-rjtkg 1/1 Running 0 75m
skupper-prometheus-9d89c8fcb-6tprt 1/1 Running 0 22m
skupper-router-7f5df585f-td8rd 2/2 Running 0 22m
skupper-service-controller-5dd798bb94-twxhq 2/2 Running 0 22m
exposeされたService
に対して、cluster2
のcbcs
にあるDeployment
をバインド
先程作られた仮想Service
に対して、cluster2
のSite
にあるバックエンドもバインドします。これが完了すると、同じService
に対して複数のSite
にあるバックエンドが紐付いた状態になり、捌けなくなったときの転送先ができることになります。
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster2
に切り替えておきます
cluster2
のcbcs
でService
が見えることと、そこではまだ何もバインドされていないことを確認します
$ skupper service status -n cbcs
Services exposed through Skupper:
├─ quarkuscoffeeshop-barista (http port 80)
├─ quarkuscoffeeshop-counter (http port 80)
╰─ quarkuscoffeeshop-kitchen (http port 80)
$ skupper service status -n cbcs-db
Services exposed through Skupper:
╰─ quarkuscoffeeshop-postgresql (tcp port 5432)
$ skupper service status -n knative-eventing
Services exposed through Skupper:
╰─ broker-ingress (http ports 80 443 9092)
Service
にDeployment
をバインドします
$ skupper service bind quarkuscoffeeshop-barista deployment quarkuscoffeeshop-barista --target-port 8080 -n cbcs
$ skupper service bind quarkuscoffeeshop-kitchen deployment quarkuscoffeeshop-kitchen --target-port 8080 -n cbcs
$ skupper service bind quarkuscoffeeshop-counter deployment quarkuscoffeeshop-counter --target-port 8090 -n cbcs
Service
にDeployment
をバインドされたことを確認します
バインドするのはcbcs
のものだけで、それ以外は他のSite
にあるバックエンドへのアクセスを行わせるため、ここでは何もしません。
$ skupper service status -n cbcs
Services exposed through Skupper:
├─ quarkuscoffeeshop-kitchen (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-kitchen name=quarkuscoffeeshop-kitchen namespace=cbcs
├─ quarkuscoffeeshop-barista (http port 80)
│ ╰─ Targets:
│ ╰─ app=quarkuscoffeeshop-barista name=quarkuscoffeeshop-barista namespace=cbcs
╰─ quarkuscoffeeshop-counter (http port 80)
╰─ Targets:
╰─ app=quarkuscoffeeshop-counter name=quarkuscoffeeshop-counter namespace=cbcs
$ skupper service status -n cbcs-db
Services exposed through Skupper:
╰─ quarkuscoffeeshop-postgresql (tcp port 5432)
$ skupper service status -n knative-eventing
Services exposed through Skupper:
╰─ broker-ingress (http ports 80 9092)
cbcs
のDeployment
をスケールして、cluster1
側からくるトラフィックに対応できるようにします
- 作業を行う前に、context(
oc
コマンドの接続先)をcluster2
に切り替えておきます
$ oc scale deployment/quarkuscoffeeshop-barista --replicas=10 -n cbcs
deployment.apps/quarkuscoffeeshop-barista scaled
$ oc scale deployment/quarkuscoffeeshop-kitchen --replicas=10 -n cbcs
deployment.apps/quarkuscoffeeshop-kitchen scaled
$ oc scale deployment/quarkuscoffeeshop-counter --replicas=10 -n cbcs
deployment.apps/quarkuscoffeeshop-counter scaled
cbcs
でそれぞれスケールしたPod
が動作していることを確認します
$ oc get pods -n cbcs
NAME READY STATUS RESTARTS AGE
quarkuscoffeeshop-barista-58778897c9-2jwlt 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-2wf2n 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-9vr2j 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-jlmsb 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-prvw4 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-q2qvz 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-s2khk 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-v9dbg 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-vbkm9 1/1 Running 0 29s
quarkuscoffeeshop-barista-58778897c9-zjzlt 1/1 Running 0 30s
quarkuscoffeeshop-counter-6b8554bb95-5tghj 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-dcmzm 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-hggfp 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-lnlxx 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-ltbsx 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-pxkw7 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-vf7px 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-w5nxg 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-x7s4s 1/1 Running 0 11s
quarkuscoffeeshop-counter-6b8554bb95-zlzl8 1/1 Running 0 11s
quarkuscoffeeshop-kitchen-84cc77dcc7-29lkh 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-5s65v 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-9qvbt 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-b47ms 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-c99dm 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-cpldx 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-pptvd 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-rpbnq 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-thgrj 1/1 Running 0 19s
quarkuscoffeeshop-kitchen-84cc77dcc7-wr8fg 1/1 Running 0 19s
skupper-prometheus-687bc6955c-5ppt8 1/1 Running 0 17m
skupper-router-6964dcc694-x4fn6 2/2 Running 0 17m
skupper-service-controller-6886cb8465-twwv5 2/2 Running 0 17m
cluster1
とcluster2
両方のcbcs
にあるcounterのpod
は、cbcs-db
のService
であるquarkuscoffeeshop-postgresql
にアクセスしますが、その際は先述のとおりGateway
を通してRHELサーバにあるDBにアクセスする形になります。
ここまでで、Quarkus Coffeeshopはcluster1
とclsuter2
にあるSite
をまたいでBurstingすることが可能になりました。
Quarkus Coffeeshopに大量のオーダーを入れてみて、実際にどのような動作をするか確認
- アプリケーションのURL(
Route
の.spec.host
)はwww.example.com
であるとします- この部分は、実際の設定に合わせて読み替えてください
オーダーを大量に投入します
$ for x in `seq 1 100`; do curl -i -X POST -H 'Content-Type: application/json' -d '{"commandType":"PLACE_ORDER","id":"'$(uuidgen)'","orderSource":"WEB","storeId":"RALEIGH","rewardsId":"","baristaItems":[{"name":"customer'$(printf "%03d" ${x})'","item":"CAPPUCCINO","price":"3.75"}],"kitchenItems":[{"item":"CROISSANT","price":3.00,"name":"customer'$(printf "%03d" ${x})'"}]}' http://www.example.com/order; done
HTTP/1.1 202 Accepted
content-length: 286
content-type: application/json
set-cookie: 377d16b6ad7e93d35752ce1b8a45cd37=b44bc865c92313a8273a503a442108da; path=/; HttpOnly
{"commandType":"PLACE_ORDER","baristaItems":[{"item":"CAPPUCCINO","price":3.75,"name":"customer001"}],"kitchenItems":[{"item":"CROISSANT","price":3.00,"name":"customer001"}],"id":"5b7ffd8f-e37a-44b4-b6f2-91bf81fdb373","storeId":"RALEIGH","orderSource":"WEB","rewardsId":"","total":null}HTTP/1.1 202 Accepted
content-length: 286
content-type: application/json
set-cookie: 377d16b6ad7e93d35752ce1b8a45cd37=b44bc865c92313a8273a503a442108da; path=/; HttpOnly
...
{"commandType":"PLACE_ORDER","baristaItems":[{"item":"CAPPUCCINO","price":3.75,"name":"customer099"}],"kitchenItems":[{"item":"CROISSANT","price":3.00,"name":"customer099"}],"id":"cfac0925-7432-4682-abf5-95c3fe282876","storeId":"RALEIGH","orderSource":"WEB","rewardsId":"","total":null}HTTP/1.1 202 Accepted
content-length: 286
content-type: application/json
set-cookie: 377d16b6ad7e93d35752ce1b8a45cd37=b44bc865c92313a8273a503a442108da; path=/; HttpOnly
{"commandType":"PLACE_ORDER","baristaItems":[{"item":"CAPPUCCINO","price":3.75,"name":"customer100"}],"kitchenItems":[{"item":"CROISSANT","price":3.00,"name":"customer100"}],"id":"187b7e13-7a41-4293-8efc-ca7db2a09163","storeId":"RALEIGH","orderSource":"WEB","rewardsId":"","total":null}$
オーダーを投入したら、どのSite
でオーダーが処理されたかをQuarkus CoffeeshopのWeb UIで確認すると、受付(counterが設定します)や作業完了(baristaとkitchenが設定します)がSite1
やSite2
に分散し、多くはSite2
で処理されるのが確認できます。
RHSIのWebコンソールで実際のトラフィックがどうなっているかを確認します
まとめ
Red Hat Service Interconnectを使用することで、後付けで比較的容易にアプリケーションのCloud Burstingできるようになる可能性があるようでした。
とはいえ、例えば今回のようなcluster2
から離れた位置にあるDBにアクセスする際には大きな遅延が発生するなど、常用には向いていない部分があります。counterだけはBurstingしないとしても、やはりその他でそれなりの遅延が発生します。
そのため、こういった利用方法は、サービスレベルが一部低下する可能性があっても、止まるよりましなので迅速に一時的な拡張を行いたい場合であったり、現行システムを騙しながら段階的に移行したい場合など、何かのトレードオフを受け入れた上での一時的な目的達成に絞って適用するほうが現実的であるとも考えられます。