Deploy a REST API on Kubernetes with Bitnami’s Helm Charts

Vikram Vaswani

In the first part of this series, you developed and integrated a sample REST API with a MongoDB database running on your local system. In this second and concluding part, you will transition your API from your local system to a Kubernetes environment, thereby making it available to a wider audience for review, test and usage.

To achieve this, you will use the following Helm charts and containers:

As with container images, Bitnami’s Helm charts are secure and packaged according to current best practices, so you can use them immediately with your preferred Kubernetes provider or environment.

Assumptions and Prerequisites

This guide makes the following assumptions:

Step 1: Deploy a MongoDB service on Kubernetes

The first step is to deploy MongoDB on your Kubernetes cluster. The easiest way to do this is with Bitnami’s MongoDB Helm chart, which gives you a ready-to-use deployment with minimal effort and within a few minutes.

Use the commands below to deploy MongoDB on your Kubernetes cluster. If you wish, you can also replace the database name and credentials shown below with your own values, but make a note of them as you will need them in subsequent steps.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install mongodb bitnami/mongodb --set mongodbRootPassword=root --set mongodbUsername=myapp --set mongodbPassword=myapp --set mongodbDatabase=mydb --set replicaSet.enabled=true

The parameters passed to the chart define the MongoDB administrator password and also create a new database named mydb with corresponding user credentials.

Wait for the deployment to complete before proceeding to the next step.

Step 2: Adapt the application source code

Next, you must adapt your application’s source code to read MongoDB connection parameters from the Kubernetes environment. This is a necessary prelude to deploying the application with Bitnami’s Node.js Helm chart.

Edit the myapp/config/datastores.js file and modify the default data store entry to look like this:

default: {
  adapter: 'sails-mongo',
  url: "mongodb://" + process.env.DATABASE_USER + ":" + process.env.DATABASE_PASSWORD + "@" + process.env.DATABASE_HOST + "/" + process.env.DATABASE_NAME
}

These values will be injected into the application’s environment by the Helm chart at deployment time.

Bitnami’s Node.js Helm chart starts the application using the npm start command. By default, this will start the Sails application in production mode. Since this is a development deployment, modify the application’s package.json file so that the start command looks like this:

{
  ...
  "scripts": {
    "start": "node app.js",
  ...
  }
}

Step 3: Create and publish a Docker image of the application

Bitnami’s Node.js Helm chart has the ability to pull a container image of your Node.js application from a registry such as Docker Hub. Therefore, before you can use the chart, you must create and publish a Docker image of the application by following these steps:

  • Create a file named Dockerfile in the application’s working directory, and fill it with the following content:

    FROM bitnami/node:13
    
    # Copy the application code
    COPY . /app
    
    # Set working directory
    WORKDIR /app
    
    # Create a non-root user
    RUN useradd -r -u 1001 -g root nonroot
    RUN chown -R nonroot /app
    USER nonroot
    
    # Set the application port to 3000
    ENV PORT="3000"
      
    # Start the application
    CMD ["node", "app.js"]
    

    This Dockerfile uses the Bitnami Node.js 13.x development image to copy the application files from the current directory. It also creates a non-root user account that the application will run under. For security reasons, it’s recommended to always run your application using a non-root user account. Finally, it sets the application to run on port 3000 (the default port expected by the Bitnami Node.js Helm chart) and starts the Node.js server.

Note: The Dockerfile used above produces a development image which contains additional development tools and dependencies. For production scenarios, you should instead use Bitnami’s Node.js 13.x production image with a multi-stage build process, as described in this tutorial on creating a production-ready image of a Node.js application.

  • Build the image using the command below. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.

    docker build -t DOCKER-USERNAME/myapp:1.0 .
    

    The result of this command is a development image containing the application, the Node.js runtime and all the related dependencies and development tools.

  • Log in to Docker Hub and publish the image. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.

    docker login
    docker push DOCKER-USERNAME/myapp:1.0
    

Step 4: Deploy the REST API on Kubernetes

By default, Bitnami’s Node.js Helm chart installs its own preconfigured MongoDB service. While this is useful in some scenarios, it must be disabled in this case, as you will be connecting your Node.js application to the MongoDB deployment created in Step 1. When disabling this default behavior, it is mandatory to pass the chart, as alternative, a Kubernetes secret containing the details of the MongoDB deployment it should use.

Follow the steps below to create the Kubernetes secret.

  • Obtain the cluster IP address of the MongoDB deployment created in Step 1:

    kubectl get svc | grep mongodb
    
  • Create a Kubernetes secret containing the MongoDB service’s IP address, port, database name and access credentials. Replace the MONGODB-IP-ADDRESS placeholder with the cluster IP address obtained from the previous command. If you used different database credentials or values when deploying the chart in Step 1, replace the values shown below appropriately.

    kubectl create secret generic my-mongodb --from-literal=host=MONGODB-IP-ADDRESS --from-literal=username=myapp --from-literal=password=myapp --from-literal=database=mydb --from-literal=port=27017
    

    This will create a Kubernetes secret named my-mongodb with the values needed for the Helm chart to successfully integrate with the MongoDB deployment.

  • Deploy the REST API using Bitnami’s Node.js Helm chart and the MongoDB secret. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.

    helm install node bitnami/node \
      --set image.repository=DOCKER-USERNAME/myapp \
      --set image.tag=1.0 \
      --set getAppFromExternalRepository=false \
      --set mongodb.install=false \
      --set externaldb.secretName=my-mongodb \
      --set service.type=LoadBalancer 
    

    Let’s take a closer look at this command:

    • The service.type=LoadBalancer parameter makes the application available at a public IP address.
    • The getAppFromExternalRepository=false parameter controls whether the chart will retrieve the application from an external repository. In this case, since the application is already published as a container image, such retrieval is not necessary.
    • The image.repository and image.tag parameters tell the chart which container image and version to pull from the registry. The values assigned to these parameters should match the image published in Step 3.
    • The mongodb.install=false parameter disables the built-in MongoDB chart, and the externaldb.secretName parameter names the secret holding details of the alternate MongoDB deployment to use.
  • Wait for the deployment to complete. Obtain the public IP address of the load balancer service:

    kubectl get svc | grep node
    

Step 5: Test the REST API

Your REST API is now deployed on Kubernetes. You can proceed to test it by sending it various types of HTTP requests and inspecting the responses. Replace the SERVICE-IP-ADDRESS placeholder in the commands below with the public IP address of the load balancer service obtained at the end of the previous step.

  • Send a POST request to the API to create a new item record:

    curl -H "Content-Type: application/json" -X POST -d '{"name":"eggs","quantity":"12"}' http://SERVICE-IP-ADDRESS/item
    

    You should see output similar to that shown below:

    POST request

  • Check if the item record was created with a GET request:

    curl http://SERVICE-IP-ADDRESS/item
    

    You should see output similar to that shown below:

    GET request

    You can also connect to the MongoDB deployment on Kubernetes to confirm that the record exists. If you used different database credentials or values when deploying the chart in Step 1, replace the values shown below appropriately.

    kubectl run --namespace default mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.2.3-debian-10-r31 --command -- mongo mydb --host mongodb --authenticationDatabase mydb -u myapp -p myapp --eval "db.item.find()"
    

    You should see output similar to that shown below:

    Database check

Your Node.js REST API is now running on Kubernetes and available for public review. You can now continue adding features to your API, upgrading the application and scaling out the database using normal Kubernetes procedures, which you can learn more about in our tutorial on deploying, scaling and upgrading applications on Kubernetes.

Note: As you continue developing and deploying your REST API, consider using a tool like Skaffold, which continuously monitors your application source code and deploys the latest version automatically on Kubernetes. Learn more about building a continuous development pipeline for a Node.js application with Skaffold.