/go-docker

My study repo for Dockerising Go apps, based on Docker Docs tutorial

Primary LanguageDockerfile

Go app Docker Containers

This repo contains code written following the tutorial on Docker Docs. The details of Docker and Docker Compose concepts I learned are in another repo. My notes here are complementary and/or refer to Go specific conteiners.

All commands here are run on Linux, but they are the same for windows (except for the sudo at the beginning). It's also possible to run docker without sudo, there's some documentation for that somewhere.

Example app

The application here was not written by me. It is part of the tutorial and is available on another GitHub repo, so I kept it out of my repo to focus on what I'm actually learning here - Docker.

Dockerfile

This file must be in the root of the project. It tells Docker how to build the image.

The (optional) first line of the Dockerfile is the #syntax parsing directive, which tells Docker what syntax to use while parsing the Dockerfile.

The next line is the FROM command. This gives a base image to build the image from.

The WORKDIR indicates the path in the image to use as the default destination for all commands.

The COPY line takes two parameter: what to copy and where to. The first parameter is relative to the directory where Dockerfile is, and the second to WORKDIR.

ENV can optionally be used to set environment variables for the dockerised app.

The RUN command executes when building the image.

CMD tells Docker to execute the command when a container is started from the image built.

Image

To build the local image:

sudo docker build --tag docker-gs-ping .

To list local images

sudo docker image ls
# or shor
sudo docker images

Add another tag to an image by running:

sudo docker image tag <IMAGE_NAME>:<EXISTENT_TAG> <IMAGE_NAME>:<NEW_TAG>

If you run docker images again you will see two entries on the list with the same image id but different tags.

To remove an image or tag run docker image rm <IMAGE_ID OR IMAGE_NAME:TAG>

Multistage builds

These will build much more compact images, by "rebuilding" the image with only the essentials. This tutorial doesn't cover in depth, so I'm just copying the Dockerfile.multistage file from there, and will later take a look at a specific guide on Docker docs.

To build from this new Dockerfile (that is not the default):

sudo docker build -t docker-gs-ping:multistage -f Dockerfile.multistage .

Run the container

sudo docker run docker-gs-ping

Will give you a very useless container running, because it's isolated and won't receive requests from outside it's network. To expose it, use the --publish or -p flag, followed by <HOST_PORT>:<CONTAINER_PORT>. For example, to expose the container's port 8080, which it listens to, on port 3000 of the host (-d flag runs the container in the background):

sudo docker run -dp 3000:8080 docker-gs-ping:multistage

Network

Networks allow containers to communicate. To create one in the background called "mynet":

sudo docker network create -d bridge mynet

Bridge is one possible network configuration. You can list active networks:

sudo docker network list

Persisting Data

You can create a volume to persist your data (this one will be named "roach" as the tutorial runs an image of CockroachDB):

sudo docker volume create roach

To pull an image from Docker Hub and run locally:

sudo docker run -d \
  --name roach \
  --hostname db \
  --network mynet \
  -p 26257:26257 \
  -p 8080:8080 \
  -v roach:/cockroach/cockroach-data \
  cockroachdb/cockroach:latest-v20.1 start-single-node \
  --insecure

Configure DB engine

To start SQL shell in same container CockroachDB is running:

sudo docker exec -it roach ./cockroach sql --insecure

In SQL shell, create a DB, user and grant permissions. Then exit the SQL shell:

CREATE DATABASE mydb;
CREATE USER totoro;
GRANT ALL ON DATABASE mydb TO totoro;
quit

Extended example

sudo docker build --tag docker-gs-ping-roach .

Run the image, setting the env variables (the DB is running in insecure mode, so the password can be anything):

sudo  docker run -it --rm -d \
  --network mynet \
  --name rest-server \
  -p 80:8080 \
  -e PGUSER=totoro \
  -e PGPASSWORD=myfriend \
  -e PGHOST=db \
  -e PGPORT=26257 \
  -e PGDATABASE=mydb \
  docker-gs-ping-roach

rest-server is how you will refer to this container in docker commands, to stop, run, remove.

db is how you will refer in your app.

Using the app

Your container is now running. To send a GET request to / (message counter):

curl localhost

To send a POST request to /send (send message):

curl --request POST \
  --url http://localhost/send \
  --header 'content-type: application/json' \
  --data '{"value": "Hello, Docker!"}'

Verify persistence

Stop the server and DB containers:

sudo docker container stop rest-server roach

Remove:

sudo docker container rm rest-server roach

Start DB then server again:

sudo  docker run -d \
  --name roach \
  --hostname db \
  --network mynet \
  -p 26257:26257 \
  -p 8080:8080 \
  -v roach:/cockroach/cockroach-data \
  cockroachdb/cockroach:latest-v20.1 start-single-node \
  --insecure
sudo docker run -it --rm -d \
  --network mynet \
  --name rest-server \
  -p 80:8080 \
  -e PGUSER=totoro \
  -e PGPASSWORD=myfriend \
  -e PGHOST=db \
  -e PGPORT=26257 \
  -e PGDATABASE=mydb \
  docker-gs-ping-roach

See that the messages are still there on localhost / route.

Remove the containers again to continue.

Docker compose

Makes life a lot easier, as all Docker Commands will be stored in one file, and all you have to do to run your containers is run docker-compose.yml file.

Check docker compose documentation for more details.

Docker Compose automatically reads .env variables. Set any PGPASSWORD variable in it for docker compose to use.

Variable substitution, like PGUSER=${PGUSER:-totoro} allows to set a default value to an env variable if none are found in the .env file.

To check for errors in your yml file:

docker-compose config

To build and run the app:

sudo docker-compose up --build

This will throw an error because the user fails authenticatins. To correct this, keep the coker compose running and open a new terminal to run the SQL shell like before:

sudo docker exec -it roach ./cockroach sql --insecure

And repeat the steps to create a user.

To remove the containers that are running your server:

sudo docker-compose down

To run in detached mode:

sudo docker-compose up --build -d

And to stop:

sudo docker-compose stop