Dockerizing Golang Web App to Google Container Registry

Hi! in this article we will discuss about how can we dockerize existing Golang web app and upload our image to Google Container Registry. Prerequisite :

  1. Docker Installed

    I am using docker for windows, version Docker version 20.10.7, build f0df350

  2. Golang Web App

    You could use your existing Golang web app, use my boilerplate code from the source section, or just create your own basic web app.

  3. Google Cloud Account

    This will be required to upload our image to the Google Container Registry.

  4. Install Google Cloud SDK

We will divide our process into 2 step, Creating the docker file and Uploading our docker image to the container registry.

Creating Docker Image

Prepare the web app

In my case I will be cloning the existing Web App from my GitHub Repo, you could check the code in the description. Note that i am cloning into app folder

git clone https://github.com/arifluthfi16/go-backend-boilerplate app
$ git clone https://github.com/arifluthfi16/go-backend-boilerplate app
Cloning into 'app'...
remote: Enumerating objects: 26, done.
remote: Counting objects: 100% (26/26), done.
remote: Compressing objects: 100% (25/25), done.
Receiving objects:  50% (13/26)sed 26 (delta 0), pack-reused 0 eceiving objects:  42% (11/26)
Receiving objects: 100% (26/26), 14.65 KiB | 2.93 MiB/s, done.

After you finished cloning the web app, go ahead and CD inside to the project.

Make sure the web app is running correctly

If you are using the boilerplate provided, configure and make sure the .env file exists, since we will not be using database you does not need to concern about configuring the database config, you can leave it as is.

# WEB APP INFO
APP_NAME=Dockerize_Test
APP_VERSION=1.0


# DATABASE CONFIG
DB_HOST=example
DB_USERNAME=postgre
DB_PASSWORD=root
DB_NAME=example_db
DB_PORT=5432

Run go install to ensure all the package required are downloaded.

$ go mod download

Then you should be fine running

$ go run main.go

If you are using the provided boilerplate, you should be getting this as output.

image-20211031144350440

Please note that we are only running our web app using go run to only test if it is running correctly. Now try to build the app and see if it also run correctly. Inside the /app directory run :

go build .

If you are using Windows as I did, you would be getting an .exe output

image-20211031144443072

Open up your terminal and try to run the .exe file that we just generated. The command to run the .exe will be depend on the terminal you are using. I am using Git Bash if you are also using Git Bash you could run the command below.

$ ./gomvcboilerplate.exe

If you are using CMD you could just type.

gomvcboilerplate.exe

At this process we are expecting to see the similar output when we are running go run main.go. After it run successfully you could delete the .exe we will not need it to create our docker image.

Creating Docker Image

There is a few way to create a Golang docker image, in this article I will be making our Docker image from existing files on our system, to do that:

In your root folder create a new Dockerfile

image-20211030175013793

Inside the Dockerfile

FROM golang:1.17-alpine

WORKDIR /app

COPY ./app/go.mod ./
COPY ./app/go.sum ./

RUN go mod download

COPY ./app/. ./

RUN go build -o ./bin/app

EXPOSE 5050

CMD [ "./bin/app" ]

Now build the Dockerfile

docker build --tag dockerize-go-boilerplate .

image-20211031145107658

View local image, you should get something similar to result below :

$ docker image ls
REPOSITORY                       TAG         IMAGE ID       CREATED          SIZE
dockerize-go-boilerplate         latest      8ff83ab698bf   34 seconds ago   526MB

Running the docker image

To run the docker image we recently create simply use

docker run dockerize-go-boilerplate 

You should see result similar to this

image-20211031145354087

But if you open your browser and go to localhost:5050/example

It will show an error, this is because we still need to publish the port to our host machine. to do that :

docker run -p 3030:5050 dockerize-go-boilerplate 

This will publish the exposed port 5050 on our image to port 3030 in our host machine.

image-20211031145723358

Try to open your browser and hit localhost:3030/example/ you should see something like this

image-20211031153752806

Also in the console we can see the service log are being called.

image-20211031153742862

If you notice if we close the terminal when running the docker service our server will also be terminated, to fix this we can run our service in detached mode, simply by adding -d flag.

docker run -p 3030:5050 dockerize-go-boilerplate 

image-20211031154031198

If you seeing result above, you should be fine and you can still access localhost:3030/example after closing the terminal.

Now after finished creating our image next step will be pushing the image to Google Container Registry.

Push To Google Container Registry

The first step on pushing our image to the Google Container Registry is to build the image according to the GCR standard, to build our image we will be using the syntax :

docker build -t gcr.io/<project_id>/go-boilerplate:v1

To get your project id, simply login to the google cloud console https://console.cloud.google.com/ login with your account, and select the project that you are going to work with. in the top menu bar you should be seeing list of project. Click the project dropdown then you will see list of project with the corresponding project id

image-20211031215208185

image-20211031215231308

Copy the id, we will need that id to build our image. Now after you got your project id run again the build command with your project id.

docker build -t gcr.io/freebies-313015/go-boilerplate:v1 .

To see the image use docker image ls

$ docker image ls
REPOSITORY                              TAG         IMAGE ID       CREATED         SIZE
gcr.io/freebies-313015/go-boilerplate   v1          732223a0ba3a   6 hours ago     526MB

Pushing the image to the repository

To push the image to the Google Cloud Registry use

docker push gcr.io/freebies-313015/go-boilerplate:v1
$ docker push gcr.io/freebies-313015/go-boilerplate:v1
The push refers to repository [gcr.io/freebies-313015/go-boilerplate]
6a2898f27baf: Pushing [==========>                                        ]  12.22MB/56.11MB
c1ed681d9bfa: Pushed
082a30005fa0: Pushing [==>                                                ]  7.173MB/154.6MB
eaa69db84ecc: Pushed
c61ffb62d319: Pushed
b441a091eb28: Pushed
8a36f1f14af3: Pushed
bd7c18232287: Pushing [==>                                                ]  16.03MB/309.1MB
eade8b1abd17: Pushed
70b223a9dcd7: Pushed
e2eb06d8af82: Layer already exists

After the it completed, you should be able to see your image on the container registry.

image-20211031222422231

If you click upon the image, it will display a detailed meta data and all the available tags.

image-20211031222528378

Possible Errors

You will be required to be authenticated to your container registry before you are able to push your image

unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate
 your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication

If you encounter the error above you could visit the help page and look for guide to authenticate. It is recommended to use the gcloud credential helper. It is as simple as running :

$ gcloud auth login

Then you will automatically prompted to login with google account, then simply:

$ gcloud auth configure-docker

After you finished configuring the setup, try to run the docker push command once more.

You could find more here https://cloud.google.com/container-registry/docs/advanced-authentication

Thankyou for reading this article!

Source Code

Web App That I used to create the image:

https://github.com/arifluthfi16/go-backend-boilerplate

Sources

  1. https://cloud.google.com/container-registry/docs/advanced-authentication
  2. https://docs.docker.com/language/golang/build-images/