A really brief introduction :
Docker provides the ability to package and run an application in a loosely isolated environment called a container. The isolation and security allow us to run many containers simultaneously on a given host.
Fun fact : Docker and popular container-orchestration application Kubernetes are built with Go.*
fig : A figure illustrating docker architecture
Two Important Terms :
Image : Image are blue print containing all the required dependencies and packages required from which container are created. For simplicity, if we take this from an object-oriented programming point of view, an image is a class, where all the requirements are defined and declared.
Container : A container is an instance of the image. These images are stored somewhere in the cloud and pulled as needed.
From this point we will be focusing on containerization of Gin Application with Mysql database. Assuming you have already Docker and Docker Compose installed on your system (Installation links are provided in the end of this document) . Important terms that comes along the way are also discussed.
We will be containerizing github.com/umschaudhary/go-polls
Writing a Dockerfile :
Create a file named Dockerfile
at the root level of project where server.go
resides. Let’s fill up the Dockerfile now.
FROM golang:1.16
RUN mkdir /app
WORKDIR /app
ADD go.mod go.sum .
RUN go mod download
RUN go get github.com/githubnemo/CompileDaemon
EXPOSE 8000
ENTRYPOINT CompileDaemon --build="go build server.go" --command=./server
Let’s Review Docker Commands mentioned above in Dockerfile :
FROM : FROM refers which base image to use for the container. The golang:1.16 image is a Linux-based image which has golang installed and no other additional programs or software.
WORKDIR : WORKDIR Changes the working directory. In our case to /app. Setting a working directory for subsequent RUN and CMD commands. If we do not specify a working directory, we have to provide a full path for running our server.go file while using the CMD/ENTRYPOINT instruction
eg: CMD [“go”, “run”, “path/server.go”].
ADD : ADD instruction literally copies the file from one location to another. ADD SOURCE DESTINATION is the syntax of the command. Similary, there is COPY command to for similar purpose. Here, we are copying the go.sum and go.mod file first so that we will have all the libraries installed before copying all the files.
RUN : RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
ENTRYPOINT : Entrypoint runs the command inside the container once a container is created from an image. You can only have one Entrypoint instruction in a
Dockerfile
. If multiple Entrypoint instructions are used, the last one will be executed. Here, once the container is created, the Entrypoint command will run our golang project.
Writing a Docker Compose file :
version: '3'
services:
db:
image: mysql/mysql-server:5.7
ports:
- "3305:3306"
environment:
- "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}"
- "MYSQL_USER=${DB_USER}"
- "MYSQL_PASSWORD=${DB_PASSWORD}"
- "MYSQL_DATABASE=${DB_NAME}"
web:
build: .
ports:
- "8000:8000"
volumes:
- ".:/app"
depends_on:
- db
links:
- "db:database"
we need docker compose for defining and running multi-container Docker applications. In our case Database and our Gin application. Let’s review terms mentioned inside compose file.
version ‘3’: Docker compose version, Latest is 3.7
services: The services section defines all the different containers to be created. We have two services namely,
web
anddb
.web: This is the name of our Gin app service. It can be anything. Docker Compose will create containers with this name.
build: This clause specifies the Dockerfile location.
.
represents the current directory where the docker-compose.yml file is located and Dockerfile is used to build an image and run the container from it. We can also enter a path to Dockerfile there.ports: The ports clause is used to map or expose the container ports to the host machine. Here mapping port
"8000:8000"
, so that we can access our services on8000
port of host machine.volumes: Here, we are attaching our code files directory to the containers, ./app directory so that we don’t have to rebuild the images for every change in the files. This will also help in auto-reloading the server when running in debug mode.
links: Links literally links one service to another. Here, we are linking the database container to the web container, so that our web container can reach the database in the bridge network. (Networking alert !!). Please if you want to learn about network in docker in detail do refer to : Network containers
image: If we don’t have a Dockerfile and want to run a service directly using an already built image, we can specify the image location using the ‘image’ clause. Compose will pull the image and fork a container from it. In our case We mentioned mysql/mysql-server:5.7 to our database service
environment: Any environment variable that needs to be set up in the container can be created using the ‘environment’ clause.
environment:
- "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}"
- "MYSQL_USER=${DB_USER}"
- "MYSQL_PASSWORD=${DB_PASSWORD}"
- "MYSQL_DATABASE=${DB_NAME}"
To get ${MYSQL_ROOT_PASSWORD}
and other variables mentioned above we have to create .env
file in a project root. We can refer to .env.example file for references. The contents of .env file should look like this:
MYSQL_ROOT_PASSWORD=root
DB_USER=umesh
DB_PASSWORD=Akash@123
DB_HOST=db
DB_PORT=3306
DB_NAME=golang
SERVER_PORT=8000
Notice DB_HOST
is set to db
i.e usually we provide DB_HOST
to localhost/127.0.0.1
. Here db
refers to the database service we created on services section of compose file.
Another important thing while configuring docker with mysql database is we need to modify our database URL to something like this :
URL := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS, HOST, DBNAME)
Typically Non Docker version looks like this:
URL := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS, HOST, PORT, DBNAME)
The above code can be found inside infrastructure/db.go
file
Running our Containers :
We are now all set up to spin up our containers. We can start our containers by :
docker-compose up --build command
Other commands worth knowing are :
docker-compose up // runs the built containers
docker-compose up --build // builds and runs the containers
There are whole list of other commands for docker-compose. We can see information about the docker-compose using docker-compose --help
on a terminal.
If you see something like this on your terminal that means, we have our server running up:
Now we can easily fire up our favorite browser and navigate to http://localhost:8000
to see that our server is working like a charm.
Some Important Concepts to know docker in deep : I would like to mention some concepts that are needed to be cover up by individual to understand and learn docker in more depth:
- Docker Architecture
- Docker Ecosystem
- Docker Fundamentals
- Layers
- Managing Data for Dockers
- Logs
- Troubleshooting in Docker
- Advance Concepts
- Docker Networks
- Docker compose
- Working With multiple Dockerfile
- Docker Security
- Production
- Docker Swarm
- Nginx
Docker Commands Lookup Table
Command 1 | Action 2 |
docker ps | Lists all running containers. -a option will list stopped and running both |
docker inspect [container_name] | Provides all info about the container |
docker stop [container_name] | Stops the running container |
docker kill [container_name] | Kills(stops) the container and removes the container from the system |
docker rmi [image/s] | Removes the provided image |
docker images | Lists all images on the system |
docker exec [-it] | Executes command in a Docker container |
docker system | Gets the Docker system information such as memory usage and housekeeping stuff |
docker system prune | This command will save you from getting the “No memory left” nightmare with production systems |
Some important links worth visiting:
- docker-curriculum.com
- thenewstack.io/dockerize-go-applications
- freecodecamp.org/news/docker-simplified-966..
- geekflare.com/docker-tutorials
Install Docker & Docker Compose :
Docker : docs.docker.com/get-docker
Docker-Compose : docs.docker.com/compose/install
PS : Feedbacks are welcomed :) !!
Thank You !!