Continuous Deployment With Heroku, Docker, And Github Actions
Today we will talk about how to setup a very simple continuous deployment pipeline for a REST API using heroku, docker and github actions
Prerequisites
- heroku account
- heroku cli
- docker
- git
- github account
- nodejs
- Basic knowledge of git, github, javascript, express and docker
You need a heroku account to deploy the project. We will use the heroku cli and docker to setup and deploy our project from our command line. Make sure that you have created an account on heroku and install heroku cli and docker. We will need a github account to setup a remote repository and use github actions.
Project Setup
We will create a simple rest api with node and express for this tutorial
- create a new directory with name
cd-heroku-docker
- cd into that directory
- run the
$ npm init -y
command. this will setup a node project in your directory - run the
$ npm install express morgan cors
command to install our dependencies - run the
$ git init
command to initialize a git repository
Create a file named index.js
and paste the following code into to file. This will
be our server code.
index.js
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const app = express();
app.use(cors());
app.use(morgan("common"));
app.get("/ping", (req, res) => {
res.json({ message: "pong" });
});
app.listen(process.env.PORT || 8000, () => {
console.log(`server started on port ${process.env.PORT || 8000}`);
});
When it will respond with {"message":"pong"}
when it receives
a get request on /ping
route.
Add a start script to your package.json
file as shown below
package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
...
We start the server at the port process.env.PORT
because
heroku will use that while deploying our container. Test the script by running
$ npm start
in your command line and going to http://localhost:8000/ping
Create a file named .gitignore
and paste the following code into to file. It will
prevent node_modules
from being committed to github.
.gitignore
node_modules
Create a file named Dockerfile
without any file extension and paste the following
code into it. Docker and heroku will use this to build our docker image
Dockerfile
FROM node:lts-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm","start"]
Notice that the Dockerfile does not contain the EXPOSE
option because heroku
does not support it.
Create a file named .dockerignore
and paste the following code into it
.dockerignore
node_modules
This will prevent docker from copying our node_modules directory.
At this point our file structure should look something like this
|-- node_modules/
|-- index.js
|-- Dockerfile
|-- .dockerignore
|-- .gitignore
|-- package.json
|-- package.lock.json
Docker Test
Lets commit our code to our local git repository and test our project locally by building out docker image and spinning up a container. After that we will setup a heroku project and github repository with github actions to enable continuous deployment. Run the following commands
$ git add .
$ git commit -m 'project setup'
$ docker build -t cd-heroku-docker .
$ docker run -p 8000:8000 cd-heroku-docker
- visit http://localhost:8000/ping your will see
{"message":"pong"}
in the browser - you will also see the logs of the application in the terminal where you ran the
docker run
command you can stop the container by pressingCTRL + C
Now we have created a docker image and successfully tested it by running a container. Now we will deploy this project to heroku and then setup a remote github repository for github actions
Deploying With Heroku
Make sure you have the heroku cli installed by running $ heroku --version
command.
Run the following commands to authenticate the heroku cli
$ heroku login
- this command will open a browser tab. Log in with you heroku account to continue$ heroku container login
- to log into the container registry$ heroku create <your project name here>
this command will create a new heroku app in your account you can name your application anything you want.
You might get an error while running this command if your project name is already
taken by someone else. Try again with a different project name.
After running this command heroku will give you a link which looks like
https://<your project name>.herokuapp.com
this is the url where our app will be
hosted. If you visit this link you will see the default heroku app page because we
have not yet deployed our application yet. Let's deploy our application.
run the following command
$ heroku container:push web -a <your app name>
This will build your image and push it to the heroku container registry. Now let's deploy our image that we just pushed. Run the following command
$ heroku container:release web -a <your app name>
Now if you visit https://<your app name>.herokuapp.com/ping
you will get{'message':'ping'}
back.
We have successfully deployed our application to heroku
Setup GitHub action
We have successfully deployed our app on heroku. But we will have to redeploy our application every time we do some changes. What if our code deployed itself automatically every time we made some changes. That's why we are going to setup a GitHub action to do just that
To do that we will use this github action. Someone has already put in the work
to create a github action for heroku, we are just going to use it. But before that we
are going to need a heroku api key so that github can push to heroku on our behalf.
To create a api key run $ heroku authorizations:create
command. This command will create
an token
and print it on the screen. Copy and paste it somewhere safe and secure we
will need this token in a moment.
The next thing to do is to create a github repository for your project. I am
not going to go in depth about this, I hope that you can create a repository on github
once you have done that copy the repository link that looks something like
https://github.com/<user name>/<repository name>.git
let us add it to our application.
Run the following command to add a remote repository and push our code to the remote repository
$ git remote add origin <link of your repository>
$ git push -u origin master
Now we have pushed our code to the remote repository lets add a github action to
automate deployment. In our project create a folder named .github
and inside it
create another folder named workflows
and inside it create a file named main.yml
.github/workflows/main.yml
name: Deploy
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: akhileshns/heroku-deploy@v3.12.12 # This is the action
with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: "<your app name>" #Must be unique in Heroku
heroku_email: "<your heroku email>"
usedocker: true
replace <your app name>
and <your heroku email>
with the correct values.
Now we need to add our heroku api key that we created and copied a few minutes ago.
Visit your github repository in your browser and then navigate to
settings --> secrets --> new repository secret.
Then in the key field add HEROKU_API_KEY
and in value field paste the token you copied a few
minutes ago and click on add secret
Coming back to our terminal. Run the following commands to push our changed code to our repository to see the magic
$ git add .
$ git commit -m 'add github action'
$ git push
If you visit your repository's actions tab in your browser you will see that the github action has started running and it will build and deploy our new image soon.
Now every time you make some changes in your master branch and push it to github this github action will make use of heroku to build and deploy the new docker image. Test it by changing the message you are sending from your application and pushing it to the master branch and then visiting your heroku application in the browser
Thank you for reading the blog post I hope that you found it helpful