I had written a dockerized rest API server with a docker-compose. Everything was running fine locally, so now it was time to deploy it. Heroku is my platform of choice, but after looking up a bit I found that it does not support docker-compose. So in this article, we will be deploying docker and setting up a database on Heroku.
Note: This article requires that you have a containerized web application setup locally. If you do not, you may clone the sample repository as follows
$ git clone https://github.com/Sparsh759/Golang-Server-Sample.git
We will be using a container registry for Docker deployment. Firstly, we will install Heroku CLI. For Ubuntu 16+ the command bellow can be used in the terminal to install. Install link for other devices
$ sudo snap install — classic heroku
Now we should be ready to use the Heroku commands. Make sure that both the Heroku and the container login are done from the same user or else the container won’t log in.
First, we will log in to Heroku
$ heroku login -i
Then logging in the container
$ heroku container:login
Sometime there can be container login issues for which you can try to run the same command again a few times.
We are ready to create a Heroku app. Giving a name is optional as Heroku can give one by itself but giving one is beneficial as it will make it easier for us to understand what that app is for. Run the following commands at the root of your application.
$ heroku create <app-name>
So now we have created the app which can be seen from the Heroku website. It would be pretty empty for the time being but we will soon fill it up.
Before pushing our docker image on Heroku we can set up all the environment variable that we want for this project by adding them to the Config Vars, which we can find from the settings tab on the Heroku website in our app.
At this point, creating an explicit Procfile is recommended. We won’t be creating one as part of this article. You may read more about Procfile here.
The next command will build our image from dockerfile and push it to the container registry. This command takes a process-type option
heroku container:push <process-type>where process-type can vary but for many simple apps
web process type can suffice as it’s the only process type that can receive external HTTP traffic from Heroku’s routers. And as we are deploying a server here, the command we will use is
$ heroku container:push web --app <app-name>
If an error says ‘no images to push’ remember, your Dockerfile name should start with capital D or else heroku won’t read it.
After the previous step is completed then we release the image to our app with the following command
$ heroku container:release web --app <app-name>
Now everything will wor…NOPE. Even though we have given a port to our project and exposed it in our dockerfile, Heroku would ignore that port as it gives a dynamic port to the application itself. So giving a port won’t help, then what should we do. Well it’s still simple as Heroku puts the port as an environment variable with the name
PORT. If you have any command in dockerfile which uses the port, you can just replace it with
$PORT( no need to expose anything ). Or if the port is used in your server code, you can just read it with the available function in your language, for example in golang
We have successfully deployed out docker and our server should be running now. We can view its log in the ‘more’ section from the website.
If you wish to attach a database, we will be doing it in the following steps. We will be using the Heroku Postgres which we will get from the add-ons in the Resource section. Selecting the Heroku Postgres and going in the settings tab, we can find a view credentials option. The required credentials that we want to use as environment variables can be set in Config Vars.
The set-up is done and our project should be up and running. The URL of the app can be found in the settings tab in the domains section. We can now use postman to make calls and test if actually everything is working fine.
The docker-compose could also be written in the heroku.yml file but it has its own different structure which can be then kept for another article.