How to Deploy a Node app to Heroku as a Docker container
Deploying a Node app to Heroku is incredibly simple. However deploying it as a Docker image requires a couple of extra steps.
Pre-requisites
Needless to say, before following the steps below, you'll need to have Node.js and Docker installed on your machine, along with a basic understanding of both. You'll also need a Heroku account and the Heroku CLI installed.
The example project used in this article has the following structure:
app-name
├── Dockerfile
├── index.js
├── heroku.yml
├── package.json
└── ...
First, we'll need a Node.js application to deploy! To demonstrate, I've used the Express Hello, World example.
// index.js
const express = require("express");
const app = express();
const port = 8080;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
Creating a Dockerfile
I've put together a basic Dockerfile which will install our dependencies and run our Node application.
The following Dockerfile will:
- Use Node 12 Alpine as its base
- Set the mainter label
- Set a an environment variable of
production
- Set an environment variable to an incoming variable
$PORT
- Copy everything from the project root into a
/var/www
directory in the container - Set the container work directory to where the files are
- Install the Node dependencies
- Expose itself to access on the given port
- Run
npm start
# Dockerfile
FROM node:12-alpine
LABEL maintainer="<Your name>"
ENV NODE_ENV=production
ENV PORT=$PORT
COPY . /var/www
WORKDIR /var/www
RUN npm install
EXPOSE ${PORT}
CMD [ "npm", "start"]
To build the Docker image, we run the docker build
command1 and tag the image with the name of the app:
docker build -t <app-name> .
then to run the image, we use the docker run
command2, and pass in two parameters:
-p
- Exposes port 8080 inside the container, to the public port 8080 through which we can access the application.3-e
- Sets the environment variable specified in the Dockerfile. In this case, the port number.4
docker run -p 8080:8080 -e PORT=8080 <app-name>
the application should now be running on http://localhost:8080/
.
Setting a Heroku app to run a container
If you already have an app running in Heroku, you can change the stack from the default heroku-x
to container
using the Heroku CLI5:
heroku stack:set -a <app-name> container
You can verify that the stack has changed either in the portal, or with the CLI, by running:
heroku apps:info -a <app-name>
You should see a list of values including Stack: container
.
Deploying and running the container
When deploying your application in a container, Heroku requires that your project contains a heroku.yml
file6. These manifest files allow you to instruct Heroku how to build, configure and run your containers. Whilst these configurations are incredibly useful in complex applications, I'd wager that the vast majority of Web applications just require a simple run command:
build:
docker:
web: Dockerfile
This configuration file appears very simple because there's a couple of things happening behind the scenes.
Firstly, as we haven't specified a run
section in the yaml file, Heroku will just use the CMD
specified in our Dockerfile.
Secondly, because Heroku automatically assigns the ports when you deploy, there's no need for us to pass any of the parameters we do when working locally. We just allow Heroku to provide the port numbers to the application.
And that's it! Push your code changes to your repository, and Heroku will take care of the rest.