📰 Good News app. Backend in Golang. Docker Compose & Traefik v2.0.

Let’s run the project on local machine!

𝙱𝚊𝚝𝚢𝚛
7 min readSep 12, 2019

I am glad to see you on the fifth article out of six in this chapter.

If you are not familiar with what I am going to implement in this series of chapters, I would recommend you to read the introductory article:

All chapters of a “book”:

  1. 📰 Good News app. Backend in Golang behind Traefik reverse proxy with https available.
  2. [in progress] 📰 Good News app. Flutter for rapid mobile applications development.
  3. [in progress] 📰 Good News app. Hummingbird as a promising replacement for frontend frameworks.

And here are articles of current chapter:

  1. Prerequisites & Idea, project and database structure and API endpoints.
  2. Project creation, go modules & GIN (beautiful framework) integration.
  3. Colly usage.
  4. MongoDB setup using official Golang driver.
  5. Running all together locally with Docker and Docker Compose & Traefik v2.0 configuration.
  6. Publishing to Digital Ocean, Let’s Encrypt and DNS Challenge configuration.

So let’s start!

In this article we are going to write a Dockerfile for building our Golang project that is going to be tiny. After that we will create a Docker Compose file that will include configuration for our server and MongoDB which will be behind Traefik reverse proxy. And in the end of the article we will test if everything works as expected. Please, make sure that you have Docker installed on your local machine. You can check on it in prerequisites part in the first article.

Docker

I would like to say a few words about Docker. Basically, Docker is a set of software that make it possible to run your project(s) in a container that emulates how it is going to be run in production. Containers are isolated and could communicate with each other that make it possible to run your project and database in different containers but they have a way to transfer information between them.

So it is time to create a Dockerfile for the project that we have been working on. Dockerfile contains a set of rules based on which container will be created and run commands which are listed in Dockerfile. Please create Dockerfile in the root folder of your project.

Here we create one temporary container where we will build our project to one executable file and then we create scratch container where we will place our executable file and run it without any overwhelming configurations (thanks to Golang).

So let’s briefly see what is going on in the Dockerfile. We download golang:1.12-alpine image and add some libraries that we need. Then we change our working directory, copy go.mod and go.sum files in order to download necessary libraries which are being used in the project. After that we copy all the files as well as images and build our project with output parameter -o that will generate an executable file to /app.

After all steps are done for the first container, we create the final container that is going to be tiny and won’t take a lot of space on your machine which is big advantage. So we copy needed files from our first container such as timezone files, certs, and executable file itself. Then we copy our images to make them available while making requests to the server. I was struggling some time to find out the solution for that because when run the server without Docker, it knows that it should take images from /images folder however when we create our final Docker container there is no images inside it, actually they were only in the first one. Then we expose :80 port (that’s why we changed it in server/server.go file in the previous article) and run our executable file. That’s it for Dockerfile that builds a container with our project running inside it.

Docker Compose

Docker Compose is a convenient tool over Docker that lets us write a list of rules which describe multiple containers’ configurations and run them all together. That is very useful when you need to launch a backend and a database so they run together and have access to each other. That is exactly our case. In addition we will use Traefik as a reverse proxy and add it to the Docker Compose file as well. Being honest, there is no need to use Traefik now because we run only one backend and don’t use any configuration for https however it will be a good practice before deploying all of it on a dedicated server on Digital Ocean that we will do it in the next article.

Traefik v2.0

Traefik is a reverse proxy / load balancer that’s easy, dynamic, automatic, fast, full-featured, open source, production proven, provides metrics, and integrates with every major cluster technology (taken from the official site). They have released v2.0 recently and I am going to use it. Below you see the picture that shows advantages of using reverse proxy because for a long time I wasn’t understanding why I should use it however now I use for each project of mine.

As you can see you can use it for deploying your backend and frontend on the same dedicated server and your database will not be accessible from outside.

So now you have to create docker-compose.yml file in the root folder of the project and paste the code below.

As mentioned before, we have three services: Traefik (reverse-proxy), Golang backend (api) and MongoDB (mongo).

For Traefik service, we specify an image traefik:v2.0 that will be downloaded from Docker Hub, then we give it a name traefik, provide it with two commands: --api and --providers.docker. First one is used to enable the web UI and the second one tells Traefik to listen to docker. Then we expose two ports: 6969 to make our backend available on this port and 6970 to open access to web UI. Read more about Traefik here, it is really powerful and you won’t regret learning it, trust me!

For Golang backend service, we specify build option so it looks for Dockerfile in the current folder (./). Then if you look into environment variables, we generate API_DEBUGMODE, API_MONGODBNAME and API_MONGODBURL which will be available inside our project code as we can see in utils/utils.go file. Variables which are used in creation of those three environment variables are taken from .env file. Then we say that this container depends on mongo container and provide some labels which are necessary for Traefik configuration. Basically we enable traefik for this container and the rule for the host is going to be localhost, so all requests which are coming to localhost will be redirected to this container. It is very simple now however in the next article Traefik configuration is going to become more complex.

For MongoDB service, there are three main parts: environment, volumes and labels. We provide two environment variables which are predefined by MongoDB image and it will create admin account based on the provided information. They are taken from .env file as well. In volumes we provide a path where all information from database will be stored. It is good to have in cases of backup or when any accident happens to our database image, we will always have that data on our machine. And in labels we specify that we don’t want to make enabled through Traefik.

Run it!

It is time to run it all together! Make sure that Docker is launched, you are in the root folder of the project in a terminal window and type the following command.

> docker-compose build && docker-compose up -d

Wait for some time till whole process is finished. Type docker ps to ensure that all of the containers are launched and running successfully.

Open a browser window and go to localhost:6969/v1/news/sources. You should see nothing, right. Because we need to configure MongoDB as well. Please run all commands below one by one without # comments. All credentials for MongoDB should be the same with those which are located in .env file in the root of the project (in case if you have changed them).

# Opening shell of mongo db running within our docker container
> docker exec -it mongo mongo -u "GGCTeamBatr" -p "MySuperSecretPassword" --authenticationDatabase admin
# Changing to (creating) a needed db
> use good_news_db
# Creating a super user
> db.createUser({user: 'suuuper_user', pwd: 'soop3r_U$eR_PSWD', roles:[{role:'dbOwner', db:'good_news_db'}]})
# Inserting test data to test collection
> db.test_collection.insert({ test: "test" })
# Displaying all collections of our previously created db in order to make sure that our test collection was successfully created
> show collections
# Saying goodbye to mongo shell
> exit

So now we have run docker ps to see all running docker containers and find CONTAINER ID (first column) of container named api. Then stop that container by typing > docker stop <api_contrainer_id> and instead of <api_contrainer_id>put the value found under CONTAINER ID. Then build and run the containers one more time to rebuild our docker container with new settings applied to MongoDB before.

> docker-compose build && docker-compose up -d

So now you can open a browser window and go to localhost:6969/v1/news/sources. Now you should see news sources which are pre-filled before server launch. After 3 minutes, you will be able to see first news gathered from parsing news sites by opening localhost:6969/v1/news.

So that’s it for this article. We have launched all containers successfully! And in the next article we will see how to deploy all of this on Digital Ocean.

I am glad that you have read this far 🙌 Below you will find the link to the next article.

If you have any comments or suggestions, please feel free to write them down or email me at batr@ggc.team 🙂

If you would like to know when I post new articles, follow me on twitter 🐦

--

--

𝙱𝚊𝚝𝚢𝚛

Social Entrepreneur, Bootstrapper, Open Source Staff, MS in CS — batyr.io