In this post, I walk through creating a simple Go web app that runs in a Docker container, and lists the hostname of the container it’s running in. I chose Go as I’ve recently gotten started writing code in Go and it’s a lot of fun to work with.

The container will install Go, so there is no need to install it locally on your machine. Docker is a prerequisite, however.

First, lets take a look at the folder structure of where to keep your dockerfile and main.go code.

Folder Structure

~/dockerfile
~/go/src/app/main.go

Dockerfile

The dockerfile contains the instruction of how to build our docker image and the app to run when the container is created from the image. Let’s start by creating the dockerfile:

cd ~
touch dockerfile

Here I referenced the following Docker/Golang official image documentation. Using your favourite code editor, modify the contents of the dockerfile to look as follows:

FROM golang:1.14

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...
EXPOSE 3000
CMD ["app"]

main.go

Now let’s create the main.go file and the folder structure to store it.

mkdir ~/go
mkdir ~/go/src
mkdir ~/go/src/app
touch ~/go/src/app/main.go

Here is the contents of the main.go file:

package main

import (
  "fmt"
  "net/http"
  "os"
)

func homePage(w http.ResponseWriter, r *http.Request) {
    // get the hostname of the container
    hostname, err := os.Hostname()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    // print the hostname of the container
    fmt.Fprintf(w, "Go App running on host: %s\n", hostname)
}

func setupRoutes() {
    http.HandleFunc("/", homePage)
}

func main() {
    // print to terminal if container run with -it flag
    fmt.Printf("Go Web App Started on Port 3000\n")
    setupRoutes()
    http.ListenAndServe(":3000", nil)
}

Build the Container

To build the container, ensure you are in the ~/ directory which hosts your dockerfile, then type the following.

docker build -t go-app .

dockerBuild

Let’s take a look at the container image by running:

docker image ls

I have two docker containers in my example. The one we just created is called go-app with an IMAGE ID of 8128cf5f8047.

dockerImage

Run the Container

Finally, let’s run the container from the image, but ensure we automatically delete the container after it is stopped. The -d flag will ensure it runs detached (non-interactive), the -rm flag will remove the container when it is stopped, and the -p flag will map local port 3000 to port 3000 in the container

docker run -d --rm -p 3000:3000 --name running-app go-app

Let’s run the curl command to see what happens

curl localhost:3000

Go App running on host: 18987a97c027

Now browse to http://localhost:3000 to see the running container in your browser

web

Running docker container ls will display the running container and it’s port mapping below.

CCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
18987a97c027        go-app              "app"               13 seconds ago      Up 12 seconds       0.0.0.0:3000->3000/tcp   running-app

I can push the container to Docker Hub using the following commands

# Login. You will need a Docker Hub account
docker login

# tag the image. We gathered the image id earlier. You will need a Docker Hub account
docker tag 8128cf5f8047 markkerry/go-app:v1

# Push the image to Docker Hub
docker push markkerry/go-app:v1

Wrapping Up

To stop the container, simply run

docker container stop running-app

If you ran the container with the -it (interactive) flag instead of -d (detached), press ctrl + c to cancel out of the interactive container session.

Running docker container ls will show the container is no longer running and was also deleted after it stopped.

If you want to delete the image, get the IMAGE ID by running docker image ls, then running the following (8128cf5f8047 in my example is the IMAGE ID):

docker image rm 8128cf5f8047

Next I plan the create a container which does something else than simply run a web page stating the host of the container it is running in. But this does feel like a nice first step when progressing towards Docker Swarm or Kubernetes. Also, I will hopefully look to deploy to an Azure Container Instance or Azure Kubernetes Service.