{"id":21428092,"url":"https://github.com/redhat-developer-demos/hybrid-cloud-serverless","last_synced_at":"2025-07-14T10:31:40.442Z","repository":{"id":46814366,"uuid":"249659503","full_name":"redhat-developer-demos/hybrid-cloud-serverless","owner":"redhat-developer-demos","description":"Bursting Cloud (K)native Services across clouds using OpenShift and Skupper","archived":false,"fork":false,"pushed_at":"2023-01-24T23:24:13.000Z","size":278,"stargazers_count":37,"open_issues_count":7,"forks_count":14,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-06-03T13:17:34.815Z","etag":null,"topics":["demo","hybrid-cloud","kubernetes","openshift","skupperproject"],"latest_commit_sha":null,"homepage":"","language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redhat-developer-demos.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-24T09:02:51.000Z","updated_at":"2024-06-06T01:46:52.000Z","dependencies_parsed_at":"2023-01-25T12:45:10.697Z","dependency_job_id":null,"html_url":"https://github.com/redhat-developer-demos/hybrid-cloud-serverless","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/redhat-developer-demos/hybrid-cloud-serverless","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-developer-demos%2Fhybrid-cloud-serverless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-developer-demos%2Fhybrid-cloud-serverless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-developer-demos%2Fhybrid-cloud-serverless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-developer-demos%2Fhybrid-cloud-serverless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redhat-developer-demos","download_url":"https://codeload.github.com/redhat-developer-demos/hybrid-cloud-serverless/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-developer-demos%2Fhybrid-cloud-serverless/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265280659,"owners_count":23739852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["demo","hybrid-cloud","kubernetes","openshift","skupperproject"],"created_at":"2024-11-22T22:10:24.291Z","updated_at":"2025-07-14T10:31:39.433Z","avatar_url":"https://github.com/redhat-developer-demos.png","language":"Makefile","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Hybrid Cloud\n:experimental:\n:cloud-1: gcp\n:cloud-1-weight: 0\n:cloud-2: azr\n:cloud-2-weight: 15\n:cloud-3: aws\n:cloud-3-weight: 20\n\nimage:https://img.shields.io/badge/OpenShift-v4.5.x-red?style=for-the-badge[link=https://try.openshift.com]\nimage:https://img.shields.io/badge/OpenShift%20Serverless-v1.10-red?style=for-the-badge[link=\nhttps://www.openshift.com/learn/topics/serverless]\nimage:https://img.shields.io/badge/skupper-v0.3.0-red?style=for-the-badge[link=\nhttps://skupper.io]\n\n== Download Sources\n\nLets use the following variables to refer to the source repositories  :\n\n- *$HYBRID_CLOUD_HOME* -- https://github.com/redhat-developer-demos/hybrid-cloud-serverless\n- *$BACKEND_APP_HOME* -- https://github.com/redhat-developer-demos/hybrid-cloud-app-backend\n- *$FRONTEND_APP_HOME* -- https://github.com/redhat-developer-demos/hybrid-cloud-app-frontend\n\n\n[source,bash]\n----\ngit clone https://github.com/redhat-developer-demos/hybrid-cloud-serverless\nexport HYBRID_CLOUD_HOME=`pwd`/hybrid-cloud-serverless\ngit clone https://github.com/redhat-developer-demos/hybrid-cloud-app-backend\nexport BACKEND_APP_HOME=`pwd`/hybrid-cloud-app-backend\ngit clone https://github.com/redhat-developer-demos/hybrid-cloud-app-frontend\nexport FRONTEND_APP_HOME=`pwd`/hybrid-cloud-app-frontend\n----\n\n== Prerequisites\n\n* https://try.openshift.com[OpenShift4] cluster on three clouds with following components installed:\n** https://www.openshift.com/learn/topics/serverless[OpenShift Serverless]\n\n* https://skupper.io/releases/index.html[skupper]\n\n* https://mikefarah.gitbook.io/yq/[yq]\n\nLet us call the OpenShift Clusters as *Cloud-1(`{cloud-1}`)*, *Cloud-2(`{cloud-2}`)* and *Cloud-3(`{cloud-3}`)*.\n\nThe following table shows the cloud and what components gets installed on each of them:\n\n.Clouds and Components\n[cols=\"\u003c2,^1,^1,^1\", options=\"header\"]\n|===\n| Component | Cloud-1  |  Cloud-2 | Cloud-3\n| Cloud Provider  | {cloud-1}  |  {cloud-2} | {cloud-3}\n| Backend   | \u0026#x2713;  | \u0026#x2713;  | \u0026#x2713;\n| Frontend  | \u0026#x2713;  | \u0026#x274C; | \u0026#x274C;\n| Generate Site Token(`token.yaml`)  | \u0026#x2713;  | \u0026#x274C; | \u0026#x274C;\n| Weight    | 0 | 15 | 20\n|===\n\n[NOTE]\n====\n* You can use any cloud provider for any OpenShift4 supported cloud, the gcp/aws/azr is used in this example.\n* *Weight* controls how many requests that cloud can handle before skupper bursts them out to other clouds\n====\n\nBefore the `backend` or `frontend` applications are deployed, execute the following on *each cloud*:\n\n[source,bash]\n----\ncd $HYBRID_CLOUD_HOME\noc apply -k k8s/core\noc project hybrid-cloud-demo\noc apply -k k8s/rbac\n----\n\n=== Cloud-1\n\n=== Add Image Streams\n\n[source,bash]\n----\noc import-image hybrid-cloud-backend --confirm --all --from quay.io/rhdevelopers/hybrid-cloud-demo-backend\n# set local lookup policy\noc set image-lookup hybrid-cloud-backend\noc import-image hybrid-cloud-frontend --confirm --all --from quay.io/rhdevelopers/hybrid-cloud-demo-frontend\n# set local lookup policy\noc set image-lookup hybrid-cloud-frontend\n----\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc apply -k k8s/skupper/{cloud-1}\n----\n\n=== Cloud-2\n\n=== Add Image Streams\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc import-image hybrid-cloud-backend --confirm --all --from quay.io/rhdevelopers/hybrid-cloud-demo-backend\n# set local lookup policy\noc set image-lookup hybrid-cloud-backend\n----\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc apply -k k8s/skupper/{cloud-2}\n----\n\n=== Cloud-3\n\n=== Add Image Streams\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc import-image hybrid-cloud-backend --confirm --all --from quay.io/rhdevelopers/hybrid-cloud-demo-backend\n# set local lookup policy\noc set image-lookup hybrid-cloud-backend\n----\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc apply -k k8s/skupper/{cloud-3}\n----\n\nRun the following commands on *Cloud-1*, *Cloud-2* and *Cloud-3* to wait for skupper deployments to be ready:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc rollout status deployment skupper-site-controller\noc rollout status deployment skupper-router\noc rollout status deployment skupper-service-controller\n----\n\n== Backend Deployment\n\nOn all clouds *Cloud-1*, *Cloud-2* and *Cloud-3*, run the following commands to deploy `Knative` backend:\n\nDeploy backend application(Knative):\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\ncd $BACKEND_APP_HOME\noc apply -k k8s/knative\n----\n\nRun the following command to check the status:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\noc get pods,svc,ksvc\n----\n\nA successful deployments of `core`,`rbac`,`skupper` and `backend` components, should show an output like:\n\n[source,text]\n----\nNAME                                                        READY   STATUS    RESTARTS   AGE\npod/hybrid-cloud-backend-p948k-deployment-b49c9569b-ggv8z   2/2     Running   0          26s\npod/skupper-router-56c4544bbc-dhckt                         3/3     Running   0          43m\npod/skupper-service-controller-5bcf486799-v2hl2             2/2     Running   0          43m\npod/skupper-site-controller-5cf967f858-z2dx8                1/1     Running   0          43m\n\nNAME                                         TYPE           CLUSTER-IP       EXTERNAL-IP                                                  PORT(S)                             AGE\nservice/hybrid-cloud-backend                 ExternalName   \u003cnone\u003e           kourier-internal.knative-serving-ingress.svc.cluster.local   \u003cnone\u003e                              21s\nservice/hybrid-cloud-backend-p948k           ClusterIP      172.30.223.229   \u003cnone\u003e                                                       80/TCP                              26s\nservice/hybrid-cloud-backend-p948k-private   ClusterIP      172.30.140.107   \u003cnone\u003e                                                       80/TCP,9090/TCP,9091/TCP,8022/TCP   26s\nservice/hybrid-cloud-backend-skupper         LoadBalancer   172.30.1.23      \u003cpending\u003e                                                    80:31554/TCP                        29s\nservice/skupper-controller                   ClusterIP      172.30.119.15    \u003cnone\u003e                                                       443/TCP                             43m\nservice/skupper-internal                     ClusterIP      172.30.205.136   \u003cnone\u003e                                                       55671/TCP,45671/TCP                 43m\nservice/skupper-messaging                    ClusterIP      172.30.14.214    \u003cnone\u003e                                                       5671/TCP                            43m\nservice/skupper-router-console               ClusterIP      172.30.72.116    \u003cnone\u003e                                                       443/TCP                             43m\n\nNAME                                               URL                                                                 LATESTCREATED                LATESTREADY                  READY   REASON\nservice.serving.knative.dev/hybrid-cloud-backend    http://hybrid-cloud-backend.hybrid-cloud-demo.svc.cluster.local   hybrid-cloud-backend-p948k   hybrid-cloud-backend-p948k   True\n----\n\n== Connecting Clouds\n\nOn *Cloud-1*, run the following command to create `site-token` secret:\n\n[source,bash]\n----\ncd $HYBRID_CLOUD_HOME\noc apply -k k8s/van\n----\n\nThe `site-token` seceret will be used to connect clouds *Cloud-2* and *Cloud-3* to *Cloud-1* forming a _Virtual Application Network(VAN)_. \n\nRun the following command to export the `site-token` secret:\n\n[source,bash]\n----\noc get secret -n hybrid-cloud-demo site-token -o yaml \u003e $HYBRID_CLOUD_HOME/token.yaml\n----\n\nTo connect *Cloud-2* and *Cloud-3* with *Cloud-1*, run the following command on *Cloud-2* and *Cloud-3*:\n\n=== Cloud-2\n\nMake sure the *Cloud-2* starts to spill over after *4* requests in queue:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\nyq w $HYBRID_CLOUD_HOME/token.yaml 'metadata.annotations[skupper.io/cost]' --tag '!!str' {cloud-2-weight} | oc create -n hybrid-cloud-demo -f -\n----\n\n=== Cloud-3\n\nMake sure the *Cloud-3* starts to spill over after *2* requests in queue:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\nyq w $HYBRID_CLOUD_HOME/token.yaml 'metadata.annotations[skupper.io/cost]' --tag '!!str' {cloud-3-weight} | oc create -n hybrid-cloud-demo -f -\n----\n\nA successfull connection can be verified using the following commands, on *Cloud-1*:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\nexport SKUPPER_POD=$(oc get pods --selector=application=skupper-router -ojsonpath='{.items[0].metadata.name}')\nkubectl exec -it $SKUPPER_POD -- qdmanage query --type node\n----\n\nThe command should show an output as shown below:\n\n[source,json,subs=\"macros+,attributes+\"]\n----\n[\n  {\n    \"index\": 0, \n    \"nextHop\": \"(self)\", \n    \"name\": \"router.node/hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\", \n    \"validOrigins\": [], \n    \"linkState\": [\n      \"hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\", \n      \"hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\"\n    ], \n    \"instance\": 1599839762, \n    \"identity\": \"router.node/hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\", \n    \"protocolVersion\": 1, \n    \"lastTopoChange\": 1599840055, \n    \"type\": \"org.apache.qpid.dispatch.router.node\", \n    \"id\": \"hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\", \n    \"address\": \"amqp:/_topo/0/hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\"\n  }, \n  {\n    \"routerLink\": 0, \n    \"name\": \"router.node/hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\", \n    \"index\": 1, \n    \"validOrigins\": [\n      \"hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\"\n    ], \n    \"protocolVersion\": 1, \n    \"linkState\": [\n      \"hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\"\n    ], \n    \"instance\": 1599840049, \n    \"cost\": {cloud-2-weight}, \n    \"address\": \"amqp:/_topo/0/hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\", \n    \"type\": \"org.apache.qpid.dispatch.router.node\", \n    \"id\": \"hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\", \n    \"identity\": \"router.node/hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\"\n  }, \n  {\n    \"routerLink\": 1, \n    \"name\": \"router.node/hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\", \n    \"index\": 2, \n    \"validOrigins\": [\n      \"hybrid-cloud-aws-skupper-router-5946d4544f-mgswf\"\n    ], \n    \"protocolVersion\": 1, \n    \"linkState\": [\n      \"hybrid-cloud-gcp-skupper-router-7b9fcf9575-knrsd\"\n    ], \n    \"instance\": 1599840051, \n    \"cost\": {cloud-3-weight}, \n    \"address\": \"amqp:/_topo/0/hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\", \n    \"type\": \"org.apache.qpid.dispatch.router.node\", \n    \"id\": \"hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\", \n    \"identity\": \"router.node/hybrid-cloud-azr-skupper-router-675cb597fc-75g2x\"\n  }\n]\n----\n\n== Verify Status\n\n=== Cloud-1\n\nRunning `skupper status` on the clouds should show the following output:\n\n[source,text]\n----\nSkupper is enabled for namespace '\"hybrid-cloud-demo\" in interior mode'. It is connected to 2 other sites. It has 1 exposed service.\n----\n\n=== Cloud-2\n\nRunning `skupper status` on the clouds should show the following output:\n\n[source,text]\n----\nSkupper is enabled for namespace '\"hybrid-cloud-demo\" in interior mode'. It is connected to 2 other sites (1 indirectly). It has 1 exposed service.\n----\n\n=== Cloud-3\n\nRunning `skupper status` on the clouds should show the following output:\n\n[source,text]\n----\nSkupper is enabled for namespace '\"hybrid-cloud-demo\" in interior mode'. It is connected to 2 other sites (1 indirectly). It has 1 exposed service.\n----\n\n[NOTE] \n====\nSince *Cloud-1* is where we generated the `site-token` secret to connect to other sites, makes it directly connected to other clouds *Cloud-2* and *Cloud-3*. For other clouds you will see one direct to *Cloud-1* and one indirect connection to other cloud.\n====\n\n== Verify Exposed Services\n\nYou can verify that, in *all* connected clouds running the following command `skupper list-exposed` shows the following output:\n\nWhen `Knative` backend was deployed:\n\n[source,bash]\n----\nServices exposed through Skupper:\n    hybrid-cloud-backend-skupper (http port 80) with targets\n      =\u003e hybrid-cloud-backend.hybrid-cloud-demo name=hybrid-cloud-backend.hybrid-cloud-demo\n----\n\nWhen standard Kubernetes (vanilla) backend was deployed:\n\n[source,bash]\n----\nServices exposed through Skupper:\n    hybrid-cloud-backend (http port 80) with targets\n      =\u003e hybrid-cloud-backend.hybrid-cloud-demo name=hybrid-cloud-backend.hybrid-cloud-demo\n----\n\n== Frontend Deployment\n\nOn *Cloud-1* deploy the *frontend* by running the following command:\n\n[source,bash]\n----\ncd $FRONTEND_APP_HOME\noc apply -k k8s/knative\n----\n\nGet the URL to access the frontend application:\n\n[source,bash]\n----\nexport API_URL=http://$(oc get route -n hybrid-cloud-demo hybrid-cloud-frontend -ojsonpath='{.spec.host}')\n----\n\n== Burst Testing\n\nIt is possible to verify the brust without user input using the  following https://github.com/rakyll/hey[hey] scripts:\n\n=== Cloud-1 burst to Cloud-2\n\nIn order to burst from Cloud-1 to Cloud-2, you need to send atleast `{cloud-2-weight}` requests to the API:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\nhey -z 2s -c 20 -m POST -d '{\"text\": \"1+2\",\"uppercase\": false,\"reverse\": false}' -H \"Content-Type: application/json\" $API_URL/api/send-request\n----\n\n=== Cloud-1 burst to Cloud-2 burst to Cloud-3\n\nIn order to burst from Cloud-1 to Cloud-2, you need to send atleast `{cloud-2-weight} + {cloud-3-weight} = 35` requests to the API:\n\n[source,bash,subs=\"macros+,attributes+\"]\n----\nhey -z 2s -c 35 -m POST -d '{\"text\": \"1+2+3\",\"uppercase\": false,\"reverse\": false}' -H \"Content-Type: application/json\" $API_URL/api/send-request\n----\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhat-developer-demos%2Fhybrid-cloud-serverless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredhat-developer-demos%2Fhybrid-cloud-serverless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhat-developer-demos%2Fhybrid-cloud-serverless/lists"}