Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Join us at AWS re:Invent 2024! Learn how to use MongoDB for AI use cases.
MongoDB Developer
Atlas
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
Atlaschevron-right

Serverless MEAN Stack Applications with Cloud Run and MongoDB Atlas

Abirami Sukumaran, Stanimira Vlaeva8 min read • Published Jun 13, 2022 • Updated Apr 02, 2024
DockerGoogle CloudAtlasJavaScript
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Plea and the Pledge: Truly Serverless

As modern application developers, we’re juggling many priorities: performance, flexibility, usability, security, reliability, and maintainability. On top of that, we’re handling dependencies, configuration, and deployment of multiple components in multiple environments and sometimes multiple repositories as well. And then we have to keep things secure and simple. Ah, the nightmare!
This is the reason we love serverless computing. Serverless allows developers to focus on the thing they like to do the most—development—and leave the rest of the attributes, including infrastructure and maintenance, to the platform offerings.
In this read, we’re going to see how Cloud Run and MongoDB come together to enable a completely serverless MEAN stack application development experience. We'll learn how to build a serverless MEAN application with Cloud Run and MongoDB Atlas, the multi-cloud developer data platform by MongoDB.

Containerized deployments with Cloud Run

All serverless platform offer exciting capabilities:
  • Event-driven function (not a hard requirement though)
  • No-infrastructure maintenance
  • Usage-based pricing
  • Auto-scaling capabilities
Cloud Run stands out of the league by enabling us to:
  • Package code in multiple stateless containers that are request-aware and invoke it via HTTP requests
  • Only be charged for the exact resources you use
  • Support any programming language or any operating system library of your choice, or any binary
Check this link for more features in full context.
However, many serverless models overlook the fact that traditional databases are not managed. You need to manually provision infrastructure (vertical scaling) or add more servers (horizontal scaling) to scale the database. This introduces a bottleneck in your serverless architecture and can lead to performance issues.

Deploy a serverless database with MongoDB Atlas

MongoDB launched serverless instances, a new fully managed, serverless database deployment in Atlas to solve this problem. With serverless instances you never have to think about infrastructure — simply deploy your database and it will scale up and down seamlessly based on demand — requiring no hands-on management. And the best part, you will only be charged for the operations you run. To make our architecture truly serverless, we'll combine Cloud Run and MongoDB Atlas capabilities.

What's the MEAN stack?

The MEAN stack is a technology stack for building full-stack web applications entirely with JavaScript and JSON. The MEAN stack is composed of four main components—MongoDB, Express, Angular, and Node.js.
  • MongoDB is responsible for data storage.
  • Express.js is a Node.js web application framework for building APIs.
  • Angular is a client-side JavaScript platform.
  • Node.js is a server-side JavaScript runtime environment. The server uses the MongoDB Node.js driver to connect to the database and retrieve and store data.
MEAN stack

Steps for deploying truly serverless MEAN stack apps with Cloud Run and MongoDB

In the following sections, we’ll provision a new MongoDB serverless instance, connect a MEAN stack web application to it, and finally, deploy the application to Cloud Run.

1. Create the database

Before you begin, get started with MongoDB Atlas on Google Cloud.
MongoDB Atlas on Google Cloud subscription page
Once you sign up, click the “Build a Database” button to create a new serverless instance. Select the following configuration:
Create new serverless instance in MongoDB Atlas configuration page
Once your serverless instance is provisioned, you should see it up and running.
Database deployments page in MongoDB Atlas
Click on the “Connect” button to add a connection IP address and a database user.
For this blog post, we’ll use the “Allow Access from Anywhere” setting. MongoDB Atlas comes with a set of security and access features. You can learn more about them in the security features documentation article.
Use credentials of your choice for the database username and password. Once these steps are complete, you should see the following:
Screen showing 'You are ready to connect' in MongoDB Atlas
Proceed by clicking on the “Choose a connection method” button and then selecting “Connect your application”.
Screen showing the connection string for MongoDB Atlas
Copy the connection string you see and replace the password with your own. We’ll use that string to connect to our database in the following sections.

2. Set up a Cloud Run project

First, sign in to Cloud Console, create a new project, or reuse an existing one.
Remember the Project Id for the project you created. Below is an image from https://codelabs.developers.google.com/codelabs/cloud-run-hello#1 that shows how to create a new project in Google Cloud.
'Create a new project' configuration page in Google Cloud. The project id is highlighted.
Then, enable Cloud Run API from Cloud Shell:
  • Activate Cloud Shell from the Cloud Console. Simply click Activate Cloud Shell.
Google Cloud Shell Editor loading page
  • Use the below command:
gcloud services enable run.googleapis.com
We will be using Cloud Shell and Cloud Shell Editor for code references. To access Cloud Shell Editor, click Open Editor from the Cloud Shell Terminal:
Google Cloud Shell Code Editor
Finally, we need to clone the MEAN stack project we’ll be deploying.
We’ll deploy an employee management web application. The REST API is built with Express and Node.js; the web interface, with Angular; and the data will be stored in the MongoDB Atlas instance we created earlier.
Clone the project repository by executing the following command in the Cloud Shell Terminal:
git clone https://github.com/mongodb-developer/mean-stack-example.git
In the following sections, we will deploy a couple of services—one for the Express REST API and one for the Angular web application.

3. Deploy the Express and Node.js REST API

First, we’ll deploy a Cloud Run service for the Express REST API.
The most important file for our deployment is the Docker configuration file. Let’s take a look at it:
mean-stack-example/server/Dockerfile
1FROM node:17-slim
2
3WORKDIR /usr/app
4COPY ./ /usr/app
5
6# Install dependencies and build the project.
7RUN npm install
8RUN npm run build
9
10# Run the web service on container startup.
11CMD ["node", "dist/server.js"]
The configuration sets up Node.js, and copies and builds the project. When the container starts, the command “node dist/server.js” starts the service.
To start a new Cloud Run deployment, click on the Cloud Run icon on the left sidebar:
Select the 'Cloud Run' icon from the left sidebar
Then, click on the Deploy to Cloud Run icon:
Select the 'Deploy to Cloud Run' icon from the opened pane
Fill in the service configuration as follows:
  • Service name: node-express-api
  • Deployment platform: Cloud Run (fully managed)
  • Region: Select a region close to your database region to reduce latency
  • Authentication: Allow unauthenticated invocations
Under Revision Settings, click on Show Advanced Settings to expand them:
  • Container port: 5200
  • Environment variables. Add the following key-value pair and make sure you add the connection string for your own MongoDB Atlas deployment:
ATLAS_URI:mongodb+srv:/<username>:<password>@sandbox.pv0l7.mongodb.net/meanStackExample?retryWrites=true&w=majority
For the Build environment, select Cloud Build.
Finally, in the Build Settings section, select:
  • Builder: Docker
  • Docker: mean-stack-example/server/Dockerfile
Click the Deploy button and then Show Detailed Logs to follow the deployment of your first Cloud Run service!
After the build has completed, you should see the URL of the deployed service:
Screenshot displaying the message 'Deployment completed successfully!' and the deployment URL.
Open the URL and append ‘/employees’ to the end. You should see an empty array because currently, there are no documents in the database. Let’s deploy the user interface so we can add some!

4. Deploy the Angular web application

Our Angular application is in the client directory. To deploy it, we’ll use the Nginx server and Docker.
Just a thought, there is also an option to use Firebase Hosting for your Angular application deployment as you can serve your content to a CDN (content delivery network) directly.
Let’s take a look at the configuration files:
mean-stack-example/client/nginx.conf
1events{}
2
3http {
4
5 include /etc/nginx/mime.types;
6
7 server {
8 listen 8080;
9 server_name 0.0.0.0;
10 root /usr/share/nginx/html;
11 index index.html;
12
13 location / {
14 try_files $uri $uri/ /index.html;
15 }
16 }
17}
In the Nginx configuration, we specify the default port—8080, and the starting file—index.html.
mean-stack-example/client/Dockerfile
1FROM node:17-slim AS build
2
3WORKDIR /usr/src/app
4COPY package.json package-lock.json ./
5
6# Install dependencies and copy them to the container
7RUN npm install
8COPY . .
9
10# Build the Angular application for production
11RUN npm run build --prod
12
13# Configure the nginx web server
14FROM nginx:1.17.1-alpine
15COPY nginx.conf /etc/nginx/nginx.conf
16COPY --from=build /usr/src/app/dist/client /usr/share/nginx/html
17
18# Run the web service on container startup.
19CMD ["nginx", "-g", "daemon off;"]
In the Docker configuration, we install Node.js dependencies and build the project. Then, we copy the built files to the container, configure, and start the Nginx service.
Finally, we need to configure the URL to the REST API so that our client application can send requests to it. Since we’re only using the URL in a single file in the project, we’ll hardcode the URL. Alternatively, you can attach the environment variable to the window object and access it from there.
mean-stack-example/client/src/app/employee.service.ts
1@Injectable({
2 providedIn: 'root'
3})
4export class EmployeeService {
5 // Replace with the URL of your REST API
6 private url = 'https://node-express-api-vsktparjta-uc.a.run.app';
7
We’re ready to deploy to Cloud Run! Start a new deployment with the following configuration settings:
  • Service Settings: Create a service
  • Service name: angular-web-app
  • Deployment platform: Cloud Run (fully managed)
  • Authentication: Allow unauthenticated invocations
For the Build environment, select Cloud Build.
Finally, in the Build Settings section, select:
  • Builder: Docker
  • Docker: mean-stack-example/client/Dockerfile
Click that Deploy button again and watch the logs as your app is shipped to the cloud! When the deployment is complete, you should see the URL for the client app:
Screenshot displaying the message 'Deployment completed successfully!' and the deployment URL for the Angular service.
Open the URL, and play with your application!

Command shell alternative for build and deploy

The steps covered above can alternatively be implemented from Command Shell as below:
Step 1: Create the new project directory named “mean-stack-example” either from the Code Editor or Cloud Shell Command (Terminal):
mkdir mean-stack-demo cd mean-stack-demo
Step 2: Clone project repo and make necessary changes in the configuration and variables, same as mentioned in the previous section.
Step 3: Build your container image using Cloud build by running the command in Cloud Shell:
gcloud builds submit --tag gcr.io/$GOOGLECLOUDPROJECT/mean-stack-demo
$GOOGLE_CLOUD_PROJECT is an environment variable containing your Google Cloud project ID when running in Cloud Shell.
Step 4: Test it locally by running: docker run -d -p 8080:8080 gcr.io/$GOOGLE_CLOUD_PROJECT/mean-stack-demo and by clicking Web Preview, Preview on port 8080.
Step 5: Run the following command to deploy your containerized app to Cloud Run:
gcloud run deploy mean-stack-demo --image gcr.io/$GOOGLECLOUDPROJECT/mean-stack-demo --platform managed --region us-central1 --allow-unauthenticated --update-env-vars DBHOST=$DB_HOST
a. –allow-unauthenticated will let the service be reached without authentication.
b. –platform-managed means you are requesting the fully managed environment and not the Kubernetes one via Anthos.
c. –update-env-vars expects the MongoDB Connection String to be passed on to the environment variable DBHOST. Hang on until the section on Env variable and Docker for Continuous Deployment for Secrets and Connection URI management.
d. When the deployment is done, you should see the deployed service URL in the command line.
e. When you hit the service URL, you should see your web page on the browser and the logs in the Cloud Logging Logs Explorer page.
Service logs displayed in the Cloud Logging Logs Explorer page

5. Environment variables and Docker for continuous deployment

If you’re looking to automate the process of building and deploying across multiple containers, services, or components, storing these configurations in the repo is not only cumbersome but also a security threat.
  1. For ease of cross-environment continuous deployment and to avoid security vulnerabilities caused by leaking credential information, we can choose to pass variables at build/deploy/up time.
    --update-env-vars allows you to set the environment variable to a value that is passed only at run time. In our example, the variable DBHOST is assigned the value of $DB_HOST. which is set as DB_HOST = ‘<
    >’
    .
    Please note that unencoded symbols in Connection URI (username, password) will result in connection issues with MongoDB. For example, if you have a $ in the password or username, replace it with %24 in the encoded Connection URI.
  2. Alternatively, you can also pass configuration variables as env variables at build time into docker-compose (docker-compose.yml). By passing configuration variables and credentials, we avoid credential leakage and automate deployment securely and continuously across multiple environments, users, and applications.

Conclusion

MongoDB Atlas with Cloud Run makes for a truly serverless MEAN stack solution, and for those looking to build an application with a serverless option to run in a stateless container, Cloud Run is your best bet.

Before you go…

Now that you have learnt how to deploy a simple MEAN stack application on Cloud Run and MongoDB Atlas, why don’t you take it one step further with your favorite client-server use case? Reference the below resources for more inspiration:
If you have any comments or questions, feel free to reach out to us online: Abirami Sukumaran and Stanimira Vlaeva.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Delivering a Near Real-Time Single View into Customers with a Federated Database


Jun 28, 2023 | 8 min read
Tutorial

Instant GraphQL APIs for MongoDB with Grafbase


Oct 12, 2023 | 7 min read
Article

Atlas Multi-Cloud Global Cluster: Always Available, Even in the Apocalypse!


Sep 23, 2022 | 4 min read
Quickstart

Single Click to Success: Deploying on Netlify, Vercel, Heroku, and Render with Atlas


Apr 10, 2024 | 6 min read
Table of Contents