This article was originally published in spanish on my blog.
In the past Cloud Next event, Google announced a new product of its services: Cloud Run. This is an evolution of App Engine which let us run any backend language on a Docker container.
In this article, I will describe how to start with this service and run your first Node.js app with it. Let's go!
Create a project on Google Cloud.
Go to Google Cloud Console and create a new project. I'm named hello-cloud-run
but you can name it as you want. Keep in mind the ProjectID
which we are using later.
To be able to use Google Cloud Platform you will need a Gmail/GSuite account, and to activate the billing. If it is the first time you sign up, you have $300 free in credits to use for one year.
API Activation
We need to activate some APIs to have not problems. One is the Cloud Run API and another one is Cloud Build API which we will use later.
Click on Enable APIs and Services and look for Cloud Run
Activate the Cloud Run API and do the same with Cloud Build API
Our App code
I have created this example code. It is a Node.js application that in the root path returns a JSON object with two properties: The today date and the time that the application is running up.
Create a Node project with the following command (remember to have Node.js installed):
$ npm init -y
Then, install express
as dependence:
$ npm i express
Create an index.js
file with the following content:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const dateStart = Date.now();
app.get('/', (req, res) => {
const today = new Date();
res.json({
date: today,
up: `${(Date.now() - dateStart) / 1000} seg.`
});
});
app.listen(port, () => {
console.log(`Server running on port: ${port}`);
console.log('Press CTRL + C to quit');
})
Let's update the package.json
file to add the start
script:
...
"scripts": {
"start": "NODE_ENV=production node index.js"
},
...
On this way, when we execute npm start
command the app will run. We can testing locally.
Next step is to create the Dockerfile
with this we define the container which contains the application code. Here you have the content:
FROM node:10
WORKDIR /usr/src/app
ENV PORT 8080
ENV HOST 0.0.0.0
COPY package*.json ./
RUN npm install --only=production
# Copy the local code to the container
COPY . .
# Start the service
CMD npm start
With this file we are configuring an environment with Node v10
as a base, the working directory will be /usr/src/app
. We are defining as environment variables the PORT: 8080
and HOST: 0.0.0.0
. We are copying the package.json
and package-lock.json
to the working directory and installing the dependencies with RUN npm install --only=production
.
Finally, we are moving the app code to the container working directory with COPY . .
And with the last one CMD npm start
the app is run.
We can try if everything is ok so far, generating the image and the start the docker container. Write the following commands on your terminal:
$ docker build --tag hello-cloud-run:01 .
$ docker run -p 8080:8080 hello-cloud-run:01
Keep in mind you need to have Docker installed on your system.
The build
command you have created an image following the Dockerfile
steps with the name hello-cloud-run:01
. The run
command let you run the app on http://localhost:8080
If all is ok you should see the following on your browser:
Automate the container deploying
Once our project is configurated on Google Cloud and the application code is written and containerized, the following step is to upload it to Google Container Registry.
We are going to create a YAML file with the steps to build and deploy the code using Google Cloud Build. This service is similar to TravisCI but customized to Google Cloud.
On this way, every time we push our code to Github (for example) Cloud Build will build the Docker image and upload the new code to Cloud Container Registry and deploy it into Cloud Run. So awesome!
First, we need to create a trigger on Cloud Build:
Once created, we choose Github as source repository option
We need to authenticate on the service chosen (in this case Github) and to choose the repository.
You need to store the application code on it. If you prefer other option like Bitbucket or Cloud Source, go ahead.
You can use this repository as the base project.
On settings, to choose Cloud Build Configuration file (yaml or json) as Build configuration, putting the name cloudbuild.yaml
which we write later.
All right! On the options, you can choose if you want to dispatch the trigger every time you push to a specific branch repo or with a tag.
Add roles and permissions
Once you have activated the Cloud Run API we need to follow the next steps to bring access from outside to our application.
-
Grant Cloud Run Admin role to Cloud Build Service account
- From Cloud Console, access to IAM Menu
- On the members' list, locate and select
[PROJECT_NUMBER]@cloudbuild.gserviceaccount.com
- Click on EDIT button (pencil icon) to approve the new role.
- Click on Add another role
- Select Cloud Run and then Cloud Run Admin
- Click on Save
-
Grant IAM Service Account User to Cloud Build Service Account from Cloud Run Runtime service account
- From Google Cloud Console, access to Service Accounts
- On the members' list, locate and select
[PROJECT_NUMBER]-compute@developer.gserviceaccount.com
- Click on Show Info Panel up on the right corner.
- On Permissions panel, click on Add Member button.
- Introduce the Cloud Build service account
[PROJECT_NUMBER]@cloudbuild.gserviceaccount.com
in the New Member new field. - On the Role dropdown, select Service Accounts and then Service Account User.
- Click on Save.
Now in our code, we are going to create the cloudbuild.yaml
file which executes the necessary commands to build the docker image, upload it to container registry and deploy it to Cloud Run:
steps:
# build the container image
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/hello-cloud-run:${SHORT_SHA}', '.']
# push the container image to Container Registry
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/hello-cloud-run']
# deploy container image to Cloud Run
- name: 'gcr.io/cloud-builders/gcloud'
args: ['beta', 'run', 'deploy', 'hello-cloud-run', '--image', 'gcr.io/$PROJECT_ID/hello-cloud-run:${SHORT_SHA}', '--region', 'us-central1', '--allow-unauthenticated']
env:
- 'PORT=8080'
images:
- gcr.io/$PROJECT_ID/hello-cloud-run
Keep in mind that <PROJECT_ID>
is your project identifier.
Checking all is working
So now, we will deploy our application code to a repository, in my case I chose Github. (this is my repo for this example). When we made a change and we will push it to master
branch, the build configuration will trigger and it will follow all the steps to upload it to Container Registry and then deploy it to Cloud Run!
When you made push
to your repo, check inside Google Cloud Console if Cloud Build has triggered an event
If it is Ok, you can go to Container Registry section and check if the Docker image has been created:
And the last, check if in Cloud Run section you have an application running:
One last thing is to let external invocations to the service because for default is private.
Add allUsers
to the new members and the Cloud Run > Cloud Run Invoker
role.
You can see a more detail explanation on this post in Dev.to
And yes! You finish! Click on the URL associated to your Cloud Run deployment and if all is OK you can see something similar to this on your browser
Top comments (3)
can get more info on Serving VueJS/reactjs/angularjs Builds via Express.js in index.js file?
res.json({
date: today,
up:
${(Date.now() - dateStart) / 1000} seg.
});
for vue js belove thing is not working:
app.use(express.static('./dist'));
app.get('/*', function(req,res) {
res.sendFile(path.join(__dirname,'/dist/index.html'));
});
Hey Carlos.. Great post ..
Quick note - You would need to update the cloudbuild.yaml file to include the --platform flag as that's a new addition in Run.
Do you know if this approach works for Angular apps? I had trouble with the port when I was trying with angular. No problems with nodejs tho.