{"id":22741483,"url":"https://github.com/danitrod/discovery-k8s-lab","last_synced_at":"2025-10-06T13:13:29.893Z","repository":{"id":105751478,"uuid":"346739968","full_name":"danitrod/discovery-k8s-lab","owner":"danitrod","description":"Deploy an application with cognitive capabilities on Kubernetes, + observability","archived":false,"fork":false,"pushed_at":"2021-03-17T13:38:05.000Z","size":1266,"stargazers_count":3,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-24T01:30:57.929Z","etag":null,"topics":["docker","ibm-cloud","ibm-kubernetes-service","kubernetes","newrelic","watson-discovery"],"latest_commit_sha":null,"homepage":"https://developer.ibm.com/tutorials/deploy-a-simple-app-on-kubernetes-that-serves-a-web-app-and-communicates-with-watson-discovery/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danitrod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-03-11T15:02:03.000Z","updated_at":"2021-08-09T23:23:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"f2fca6d7-1ccd-47b2-a14b-280e58c8281c","html_url":"https://github.com/danitrod/discovery-k8s-lab","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/danitrod/discovery-k8s-lab","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danitrod%2Fdiscovery-k8s-lab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danitrod%2Fdiscovery-k8s-lab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danitrod%2Fdiscovery-k8s-lab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danitrod%2Fdiscovery-k8s-lab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danitrod","download_url":"https://codeload.github.com/danitrod/discovery-k8s-lab/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danitrod%2Fdiscovery-k8s-lab/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278615605,"owners_count":26016208,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["docker","ibm-cloud","ibm-kubernetes-service","kubernetes","newrelic","watson-discovery"],"created_at":"2024-12-11T00:12:29.166Z","updated_at":"2025-10-06T13:13:29.854Z","avatar_url":"https://github.com/danitrod.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Deploy a web application on IBM Kubernetes Service\n\n## Introduction\n\nIn this lab, we will deploy a simple app, that serves a Single Page Application (SPA) and communicates with Watson Discovery, on Kubernetes. The [SPA](./react-app) will be served by a Node.js back end running [Fastify](https://fastify.io). The [back end](./server) will then make queries to Watson Discovery and return the results. Finally, we will setup our cluster for Full Stack Observability with New Relic to easily make sure everything is running ok in our cluster and analyze some metrics, logging and more.\n\n## Prerequisites\n\n- Any non-lite type of [IBM Cloud](https://cloud.ibm.com/registration) account (you must upgrade to create a free Kubernetes cluster)\n- [Docker](https://www.docker.com/)\n- [IBM Cloud CLI](https://github.com/IBM-Cloud/ibm-cloud-cli-release#downloads)\n- [Kubectl](https://v1-18.docs.kubernetes.io/docs/tasks/tools/install-kubectl/)\n\n## Setup\n\nBefore we start, install the following IBM Cloud CLI plugins:\n\n```\nibmcloud plugin install kubernetes-service\nibmcloud plugin install container-registry\n```\n\nCreate a free 1 worker [IBM Kubernetes Service](https://cloud.ibm.com/kubernetes/catalog/create) cluster.\n\nAnd finally, create a free [Watson Discovery](https://cloud.ibm.com/catalog/services/watson-discovery) instance.\n\n## Step-by-step\n\nThis step-by-step guide assumes a Linux/Unix like shell usage. Slight adaptations might be necessary for different CLI shells.\n\n### Step 1\n\nStart by logging in to IBM Cloud:\n\n```sh\nibmcloud login\n```\n\n### Step 2\n\nLogin to IBM Container Registry as well:\n\n```sh\nibmcloud cr login\n```\n\n### Step 3\n\nAdd a namespace for your project at IBM Container Registry (ICR):\n\n```sh\nexport ICR_NAMESPACE=\u003cyour_namespace\u003e\n\nibmcloud cr namespace-add $ICR_NAMESPACE\n```\n\n### Step 4\n\nLet's build the app. Build a Docker image for the app, tag and push it to ICR under your namespace:\n\n```sh\nexport APP_IMAGENAME=us.icr.io/$ICR_NAMESPACE/discovery-demo-app:v1\ndocker build -t $APP_IMAGENAME .\ndocker push $APP_IMAGENAME\n```\n\n(building the image should take a few minutes)\n\n### Step 5\n\nConnect to your IBM Kubernetes Service (IKS) cluster:\n\n```sh\nibmcloud ks cluster config --cluster \u003cyour_cluster_name\u003e\n```\n\nThe cluster name is the one you chose when creating it. In case you forgot, you can check that in the [IBM Cloud resource list](https://cloud.ibm.com/resources), under `Clusters`.\n\n### Step 6\n\nFor our back end to make requests to Watson Discovery, it will need the Discovery instance credentials, which will be defined by two environment variables. We will create the credentials as a Kubernetes secret, then inject them in the app by configuring environment variables on the [deployment yaml file](./server/deployment.yaml). You can find your `APIKEY` and `URL` for Watson Discovery by going to your [IBM Cloud resource list](https://cloud.ibm.com/resources), and clicking on your Watson Discovery instance under `Services`. Store them in environment variables as below and create the secret:\n\n```sh\nexport DISCOVERY_APIKEY=\u003cdiscovery_apikey\u003e\nexport DISCOVERY_URL=\u003cdiscovery_url\u003e\n\nkubectl create secret generic discovery-credentials --from-literal=api-key=$DISCOVERY_APIKEY --from-literal=url=$DISCOVERY_URL\n```\n\n### Step 7\n\nNow we will deploy our built image to Kubernetes. First, update the [deployment.yaml](./server/deployment.yaml) file to match your image name. You should update the line 24's image value - updating just the namespace will do just fine. **This is important!** Not changing the image name will cause your pod to not find any images. After doing that, we can deploy:\n\n```sh\nkubectl apply -f server/deployment.yaml\n```\n\n_In case you're wondering, the `deployment.yaml` file can be generated with `kubectl create deployment \u003cdeployment_name\u003e --image=\u003cimage_name\u003e --port \u003cport\u003e --dry-run=client -o yaml \u003e deployment.yaml`. The yaml file we used is just additionally configured to use the secret as environment variables._\n\n### Step 8\n\nOur app should now be running. You can check that with `kubectl get pods`. If there are any errors, you can check the logs with `kubectl logs \u003cpod_id\u003e`. The next step is to expose our app publicly, so we can access it. Let's do that:\n\n```sh\nkubectl expose deploy discovery-demo-app --type=NodePort\n```\n\nA Node Port will be created and it will forward the pod's exposed port to the node's public interface\n\n### Step 9\n\nOk! Now your app is ready to be publicly accessed! We will do that by getting the cluster worker node's public IP and accessing the port forwarded by the Node Port. First, run:\n\n```sh\nkubectl get svc\n```\n\nYou should see the discovery-demo-app `NodePort` and some columns of information. With a free cluster, you can't have an external IP for your service yet, but you can access the service through the worker node's public IP. You can find the TCP port forwarded by the Node Port in the above command's output. It should look something like `8080:\u003cport\u003e/TCP`, being a port in the range `30000 - 32767`.\n\nTake note of the port. You will use it to access the app.\n\n### Step 10\n\nGet your worker node's public IP. You can do that by running the following command:\n\n```sh\nibmcloud ks worker ls -c \u003cyour_cluster_name\u003e # Cluster name is same as in step 5\n```\n\nThat will output the ID of the worker in your cluster, together with its public and private IPs. Copy the public IP as we will use it next.\n\n### Step 11\n\nAccess the app! The URL should be formatted like this: `http://\u003cworker_ip\u003e:\u003cnode_port\u003e`. You can access it directly from your browser and see the magic happen. Try out a couple of queries for Watson Discovery news!\n\n![Screenshot](./doc/images/screenshot.png)\n\n### Step 12\n\nCongratulations, you now have an app running! We want to make sure it keeps running smoothly, so let's set up Observability with New Relic.\n\nFirst [register for a free New Relic account](https://newrelic.com/signup?utm_source=callforcode2021)\n\nThen [log in to your New Relic account](https://one.newrelic.com/) and follow the guided install for Kubernetes. During the guided install you will have to:\n\n1. Give your cluster a meaningful name\n1. Accept all setup options\n1. Choose `Manifest`\n1. Download the manifest file\n1. Apply the manifest file with `kubectl apply -f \u003cPATH_TO_DOWNLOADED_FILE\u003e -n default`\n1. You can first do the next step before going into the Kubernetes Cluster Explorer\n\nWe also want detailed application monitoring, and to get that, we only need to update the `server/deployment.yaml` file and uncomment the `NEW_RELIC_LICENSE_KEY` and `NEW_RELIC_APP_NAME` environment variable definitions.\n\nNow redeploy our app:\n\n```sh\nkubectl apply -f server/deployment.yaml\n```\n\n_The Node.js app is already instrumented with New Relic:_\n\n- _The New Relic library was imported with a `require('newrelic');` in the main module (`src/index.ts`)_\n- _The `package.json` file includes `newrelic` as a dependency_\n\nNow navigate to the New Relic Kubernetes Cluster Explorer and see what's happening in your cluster.\n\nIf you filter by the `discovery-demo-app` deployment, you can see the status of the running pod (click on the pod to see its status):\n\n![New Relic Dashboard](./doc/images/dashboard.png)\n\nYou can also see the response times for your service, do that by going to `Explorer \u003e APM` and searching for `discovery-demo`.\n\n![Service response time](./doc/images/response-time.png)\n\nMuch more can be done within New Relic One. If you want to learn more about the Kubernetes Cluster Explorer, watch [this video](https://www.youtube.com/watch?v=RKaEt26HjhI\u0026ab_channel=NewRelic).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanitrod%2Fdiscovery-k8s-lab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanitrod%2Fdiscovery-k8s-lab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanitrod%2Fdiscovery-k8s-lab/lists"}