Chapter 11. Deploying Go Applications Using Docker

Docker is an open source ecosystem (technology and range of associated services) that allows you to package applications into containers that are simple, lightweight, and portable; they will run in the same way regardless of which environment they run on. This is useful when you consider that our development environment (perhaps a Mac) is different from a production environment (such as a Linux server or even a cloud service) and that there is a large number of different places that we might want to deploy the same application.

Most cloud platforms already support Docker, which makes it a great option to deploy our apps into the wild.

In Chapter 9, Building a Q&A Application for Google App Engine, we built an application for Google App Engine. We would need to make significant changes to our code if we decided that we wanted to run our application on a different platform even if we forget about our use of Google Cloud Datastore. Building applications with a mind to deploying them within Docker containers gives us an additional level of flexibility.

Note

Did you know that Docker itself was written in Go? See for yourself by browsing the source code at https://github.com/docker/docker.

In this chapter, you will learn:

  • How to write a simple Dockerfile to describe an application
  • How to use the docker command to build the container
  • How to run Docker containers locally and terminate them
  • How to deploy Docker containers to Digital Ocean
  • How to use the features in Digital Ocean to spin up instances that already have Docker preconfigured

We are going to put the Vault service we created in Chapter 10, Micro-services in Go with the Go kit Framework, into a Docker image and deploy it to the cloud.

Using Docker locally

Before we can deploy our code to the cloud, we must use the Docker tools on our development machine to build and push the image to Docker Hub.

Installing Docker tools

In order to build and run containers, you need to install Docker on your development machine. Head over to https://www.docker.com/products/docker and download the appropriate installer for your computer.

Docker and its ecosystem are evolving rapidly, so it is a good idea to make sure you're up to date with the latest release. Similarly, it is possible that some details will change in this chapter; if you get stuck, visit the project home page at https://github.com/matryer/goblueprints for some helpful tips.

Dockerfile

A Docker image is like a mini virtual machine. It contains everything that's needed to run an application: the operating system the code will run on, any dependencies that our code might have (such as Go kit in the case of our Vault service), and the binaries of our application itself.

An image is described with Dockerfile; a text file containing a list of special commands that instruct Docker how to build the image. They are usually based on another container, which saves you from building up everything that might be needed in order to build and run Go applications.

Inside the vault folder from the code we wrote in Chapter 10, Micro-services in Go with the Go kit Framework, add a file called Dockerfile (note that this filename has no extension), containing the following code:

FROM scratch 
MAINTAINER Your Name <[email protected]> 
ADD vaultd vaultd 
EXPOSE 8080 8081 
ENTRYPOINT ["/vaultd"] 

Each line in a  Dockerfile file represents a different command that is run while the image is being built. The following table describes each of the commands we have used:

Command

Description

FROM

The name of the image that this image will be based on. Single words, such as scratch, represent official Docker images hosted on Docker Hub. For more information on the scratch image, refer to https://hub.docker.com/_/scratch/.

ADD

Copies files into the container. We are copying our vaultd binary and calling it vaultd.

EXPOSE

Exposes the list of ports; in our case, the Vault service binds to :8080 and :8081.

ENTRYPOINT

The binary to run when the container is executed in our case, the vaultd binary, which will be put there by the previous call to go install.

MAINTAINER

Name and email of the person responsible for maintaining the Docker image.

Note

For a complete list of the supported commands, consult the online Docker documentation at https://docs.docker.com/engine/reference/builder/#dockerfile-reference.

Building Go binaries for different architectures

Go supports cross-complication, a mechanism by which we can build a binary on one machine (say, our Mac) targeted for a different operating system (such as Linux or Windows) and architecture. Docker containers are Linux-based; so, in order to deliver a binary that can run in that environment, we must first build one.

In a terminal, navigate to the vault folder and run the following command:

CGO_ENABLED=0 GOOS=linux go build -a ./cmd/vaultd/

We are essentially calling go build here but with a few extra bits and pieces to control the build process. CGO_ENABLED and GOOS are environment variables that go build will pay attention to, -a is a flag, and ./cmd/vaultd/ is the location of the command we want to build (in our case, the vaultd command we built in the previous chapter).

  • The CGO_ENABLED=0 indicates that we do not want cgo to be enabled. Since we are not binding to any C dependencies, we can reduce the size of our build by disabling this.
  • GOOS is short for Go Operating System and lets us specify which OS we are targeting, in our case, Linux. For a complete list of the available options, you can look directly in the Go source code by visiting https://github.com/golang/go/blob/master/src/go/build/syslist.go.

After a short while, you'll notice that a new binary has appeared, called vaultd. If you're on a non-Linux machine, you won't be able to directly execute this but don't worry; it'll run inside our Docker container just fine.

Building a Docker image

To build the image, in a terminal, navigate to Dockerfile and run the following command:

docker build -t vaultd

We are using the docker command to build the image. The final dot indicates that we want to build Dockerfile from the current directory. The -t flag specifies that we want to give our image the name of vaultd. This will allow us to refer to it by name rather than a hash that Docker will assign to it.

If this is the first time you've used Docker, and in particular the scratch base image, then it will take some time to download the required dependencies from Docker Hub depending on your Internet connection. Once that's finished, you will see output similar to the following:

Step 1 : FROM scratch
 --->
Step 2 : MAINTAINER Your Name <[email protected]>
 ---> Using cache
 ---> a8667f8f0881
Step 3 : ADD vaultd vaultd
 ---> 0561c999c1e3
Removing intermediate container 4b75fde507df
Step 4 : EXPOSE 8080 8081
 ---> Running in 8f169f5b3b44
 ---> 1d7758c20b3a
Removing intermediate container 8f169f5b3b44
Step 5 : ENTRYPOINT /vaultd
 ---> Running in b5d55d6429be
 ---> b7178985dddf
Removing intermediate container b5d55d6429be
Successfully built b7178985dddf

For each command, a new image is created (you can see the intermediate containers being disposed of along the way) until we end up with the final image.

Since we are building our binary on our local machine and copying it into the container (with the ADD command), our Docker image ends up being only about 7 MB: pretty small when you consider that it contains everything it needs to run our services.

Running a Docker image locally

Now that our image is built, we can test it by running it with the following command:

docker run -p 6060:8080 -p 6061:8081 --name localtest --rm vaultd

The docker run command will spin up an instance of the vaultd image.

The -p flags specify a pair of ports to be exposed, the first value is the host port and the second value (following the colon) is the port within the image. In our case, we are saying that we want port 8080 to be exposed onto port 6060 and port 8081 exposed via port 6061.

We are giving the running instance a name of localtest with the --name flag, which will help us to identify it when inspecting and stopping it. The --rm flag indicates that we want the image to be removed once we have stopped it.

If this is successful, you will notice that the Vault service has indeed begun because it is telling us the ports to which it is bound:

2016/09/20 15:56:17 grpc: :8081
2016/09/20 15:56:17 http: :8080

Tip

These are the internal ports; remember that we have mapped these to different external ports instead. This seems confusing but ends up being very powerful, since the person responsible for spinning up the instances of the service gets to decide which ports are right for their environment, and the Vault service itself doesn't have to worry about it.

To see this running, open another terminal and use the curl command to access the JSON endpoint of our password hashing service:

curl -XPOST -d '{"password":"monkey"}' localhost:6060/hash

You will see something that resembles the output from the running service:

{"hash":"$2a$0$wk4qc74ougOkbkt/TWuRQHSg03i1ataNupbDADBwpe"}

Inspecting Docker processes

To see what Docker instances are running, we can use the docker ps command. In the terminal, type the following:

docker ps

You'll get a text table outlining the following properties:

CONTAINER ID

0b5e35dca7cc

IMAGE

vaultd

COMMAND

/bin/sh -c /go/bin/vaultd

CREATED

3 seconds ago

STATUS

Up 2 seconds

PORTS

0.0.0.0:6060->8080/tcp, 0.0.0.0:6061->8081/tcp

NAMES

localtest

The details show you a high-level overview of the image we just started. Note that the PORTS sections shows you the mapping from external to internal.

Stopping a Docker instance

We are used to hitting Ctrl + C in the window running our code to stop it, but since it's running inside a container, that won't work. Instead, we need to use the docker stop command.

Since we gave our instance the name localtest, we can use this to stop it by typing this in an available terminal window:

docker stop localtest

After a few moments, you'll notice that the terminal that was running the image has now returned to the prompt.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.228.88