Docker is the most popular containerization technology owing to its simplicity and ease of use. Docker relieves the stress of portability issues in software development and distribution. You can deploy your docker containers to most cloud service providers.
Containerizing your Go apps with Docker can help you ensure consistent and reliable deployment across different environments. You can deploy your Go apps to different environments like development, staging, and production. Docker containers are lightweight and take up less space than traditional virtual machines. This can save you money on hosting costs, and it can also make your deployments faster.
Setting Up a Simple Web Server in Go
The Go standard library contains the packages you’ll need to set up a simple web server.
First, import the http, log, and json packages. You’ll use Go's http package to set up the server and GET request endpoint. The log package for logging possible errors to your console. The json package for encoding a struct to JSON for the API endpoint.
import (
"encoding/json"
"log"
"net/http"
)
You can encode a struct instance as JSON to the client as a response based on the validity of the request as thus:
type Message struct {
Response string `json:"response"`
Description string `json:"description"`
}
The handler function would return a successful message to the client if the request to the endpoint is a GET request.
// dockerTestEndpoint handles the API endpoint for testing Docker connectivity
func dockerTestEndpoint(writer http.ResponseWriter, request *http.Request) {
// Set the response header to indicate JSON content
writer.Header().Set("Content-Type," "application/json")
// If the request method is GET
if request.Method == "GET" {
// Set the response status code to 200 OK
writer.WriteHeader(http.StatusOK)
// Create a message struct for a successful response
message := Message{
Response: "Successful",
Description: "You've successfully hit the API endpoint " +
"From your Docker Container",
}
// Encode the message as JSON and send it as the response
err := json.NewEncoder(writer).Encode(&message)
if err != nil {
return
}
} else {
// If the request method is not GET
// Set the response status code to 400 Bad Request
writer.WriteHeader(http.StatusBadRequest)
// Create a message struct for a bad request response
message := Message{
Response: "Bad Request",
Description: "You've successfully hit the API endpoint From your " +
"Docker Container, But you made a bad request",
}
// Encode the message as JSON and send it as the response
err := json.NewEncoder(writer).Encode(&message)
if err != nil {
return
}
}
}
You set up the handler function in the main function with the route as /api/docker/go. The dockerTestEndpoint handler function validates that the request to the handler is a GET request. If it's a GET request, it encodes an instantiated Message struct instance to the client based on the request's status.
Here’s how you can mount the handler function on a route and setup the server to run on port 8080:
func main() {
// Register the handler function 'dockerTestEndpoint'
// to handle requests for the "/api/docker/go" URL.
http.HandleFunc("/api/docker/go", dockerTestEndpoint)
// Start the HTTP server and listen for incoming requests on port 8080.
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalln("There's an error with the server:", err)
}
}
The main function is the server's entry point, which listens on port 8080. The HandleFunc method mounts the routes on the handler function. The ListenAndServe method starts the server on the specified local host port 8080.
Getting Started Containerizing Your Go Apps With Docker
After installing and setting up Docker, you’ll need a Docker file named Dockerfile to create and build a Docker image for your Go app. You’ll specify commands for the base image and commands to copy the files, add the working directory, and run the app in the Dockerfile.
Run this command in the terminal of your workspace to create a Dockerfile.
touch Dockerfile
You’ll specify the commands for building your Docker image in the Dockerfile.
If there are any files you want to separate from your Docker image, you can use a .dockerignore file. The .dockerignore files work exactly like .gitignore files.
touch .dockerignore
Next, you’ll specify build commands in your Dockerfile to containerize your apps.
Defining Commands in the Dockerfile
Dockerfiles are customizable based on your project’s specifications. You’ll define commands to build the base image for building the application.
Here’s an example of the contents of a Dockerfile that builds the web server above:
# Use a Golang base image
FROM golang:latest
# Set the working directory inside the container
WORKDIR /app
# Copies all the files in the local directory to the working directory in the container
COPY . .
# Download the Go module dependencies
RUN go mod download
# Build the Go application
RUN go build -o app
# Set the entry point for the application
ENTRYPOINT ["./app"]
The Dockerfile uses golang:latest base image, to build the app after setting the working directory to /app.
The Dockerfile copies the files with the COPY command and downloads dependencies with the RUN command.
The file specifies a build and run operation with the RUN command, then sets the command to run when the container starts with the CMD command.
Save the Dockerfile in the same directory as your go.mod and main.go files; then run this command to build a Docker image from this Dockerfile:
docker build -t GolangTutorial .
The above command will create a Docker image with the tag golangtutorial. You can run a container with this command:
docker run -p 8080:8080 golangtutorial
The command maps port 8080 from the container to port 8080 on the localhost of the host machine. You can request the server running in the Docker container from the host machine.
Here’s the result from sending the CURL request to the server, this time running on Docker:
You Can Use Docker Compose for Container Orchestration
Docker Compose is a tool that you can use to orchestrate (work with many) Docker containers. Docker Compose allows you to define a multi-container application in a single YAML file. You can run and manage the entire application with a single command.
You can use Docker Compose for deploying and managing complex containerized applications. Docker Compose simplifies management with automated and consistent deployments.