Create a Multi-Stage Dockerfile for Golang Application
This article will show you how to create a Dockerfile for Golang application so it can run as a Docker container. You should install Docker first to be able to run docker commands.
You need to create a Dockerfile for your project to create docker containers. Using that file, you can create a Docker container which can run on any platform without installing any libraries.
Let’s create simple Golang Application (for those who dont have pre-existing golang application)
Step 1 — Create a new directory and run
Then create main.go file
package main import (
"github.com/labstack/echo"
)//main function
func main() {
// create a new echo instance
e:= echo.New()
e.GET("/data/:data",GetData)e.Logger.Fatal(e.Start(":8000"))
}
Then create handlers.go file
Echo provides an easy mechanism for drawing variables from the built-in Context object. “GetData” function extracts QueryParam specified by the caller. Using the QueryParams we can send a response to the caller.
package mainimport (
"fmt"
"net/http"
"github.com/labstack/echo"
)//GET API which return the name of the cats specified in QueryParam//http://localhost:8000/data?name=damini
func GetData(c echo.Context) error {
name:= c.QueryParam("name")
return c.String(http.StatusOK, fmt.Sprintf("your name is : %s", catName))
}
Now we are ready to go. After completing the earlier steps, we can run our application using the command “go run main.go”. Our application will be running on port 8000.
Step 2 — Create A DockerFile (Multi-stage build)
One of the most challenging things about building images is keeping the image size down. Each instruction in the Dockerfile adds a layer to the image, and its better to clean up any artifacts you don’t need before moving on to the next layer and to do we are following multi-stage approach.
With multi-stage builds, we can use multiple FROM
statements in your Dockerfile. Each FROM
instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artifacts from one stage to another, leaving behind everything you don’t want in the final image.
Create a file in the root directory called Dockerfile
.
The first thing is we need to define which image we want to build from. Here we will use version 3.14 of alpine available from Docker Hub:
FROM golang:alpine3.14 as builder
Next, create the working directory for your application.
# Create app directory
WORKDIR /app
Copy the go.mod file and install all the dependices.
# Install app dependencies
ADD go.mod .
RUN go mod download
Add the rest of the application to the app directory.
ADD . /app
Build the binary.
RUN CGO_ENABLED=0 GOOS=linux go build -a -o test.
Base image we want to build from and work directory.
FROM alpine:3.14
WORKDIR /app
Copy the artifacts(in our case its test binary) from one stage to another.
COPY --from=builder /app/test .
Expose the port and start the application.
Expose 8000CMD ["./test"]
Your Dockerfile
should look like this:
FROM golang:alpine3.14 as builder# Create app directory
WORKDIR /app# Install app dependencies
ADD go.mod .
RUN go mod download# Copying rest of the application to app directory
ADD . /appRUN CGO_ENABLED=0 GOOS=linux go build -a -o test.#Second stage
FROM alpine:3.14
WORKDIR /app#copy artifact
COPY --from=builder /app/test .# Expose the port and start the application
Expose 8000CMD ["./test"]
.dockerignore file
Create a .dockerignore
file so as not to copy unnecessary files to the container:
*.log
This prevents the debug logs from being copied onto your Docker image.
Step 3 — Building your Docker Image
Building your Docker image is quite easy and can be done using a single command.
docker build -t <docker-image-name> <filepath>
The -t
flag lets you tag your image so it’s easier to find later
For example (if you are in project directory):
docker build -t goimage .
Once the build is complete, you can check your image by using this command:
docker image ls
Step 4 — Run Container
Now we can run the docker image using the command:
docker run -d -p <Host port>:<Docker port> <docker-image-name>
-d flag indicates the docker container is running in the background. The -p flag specifies which host port will be connected to the docker port.
Example:
docker run -d -p 8000:8000 goimage
You can use the docker ps
command to check the list of running containers.
docker ps -a
The above code reads the QueryParam name and type specified by the caller. Then return the response in String format. We need to import the “net/http” package to send HTTP status code in the response. We also need to import the “fmt” package to format the message string.