A friendly introduction to Dockerfile and Docker-compose

Shivam Garg
5 min readMay 19, 2021

What I learned about dockerfile and docker-compose file

You can read the basic concepts of docker written in this amazing Article, Starting with Docker.

What is a Dockerfile?

A Dockerfile is merely a written set of instructions, that helps to bundle up all the required files and dependencies for your application, in the form of a docker image. These instructions can be used to install node-dependencies from package.json or install python dependency from requirement.txt, or any other kind of installations or configurations.

Example of a dockerfile

I have written a basic nodeJS application that uses github APIs to use a repository as a database, the code can be found here Book-lib.

You’ll find a Dockerfile in this repository,

What is it doing?

  1. From is used to assign a base image, You can create your own base image, or you can find many images already on DockerHub.
  2. WORKDIR defines the working directory of a docker container, it will be automatically created at the time of running a container.
  3. Next commands after this will be functional in this working directory only.
  4. ENV can be used to set environment variables for the project. Here, I defined port as an environment variable. I can access this as process.env.PORT in my javascript file of the project.
  5. RUN is used to execute commands at the time of the building of the image, in order to install packages for your container.
  6. COPY, copies all the files to the working directory of docker from your machine.
  7. CMD is also used to execute commands but it runs at the time when the container starts, and usually, it is used to run an application inside the container, like npm start .

How to create a docker container by this dockerfile?

  1. The first step is to create the image by using docker build command.
docker build -t <-tag-name-> /path/to/Dockerfiledocker build -t shivam1410/book-lib-test ~/Desktop/docker/book-lib/

-t : A tag name to your image.

2. then run the container by using docker run command, if you do not know about this command you should probably read Starting with docker-CLI.

docker run -d -p 10000:10000 shivam1410/book-lib-test

3. Visit localhost:10000 to see If the application is running.

  • keep your dockerfile in the project directory for ease of use.
  • The docker build command will create a docker image, However, it doesn't ensure that the container will run as expected, for that You need to write the right instructions in the dockerfile.
  • You can push this image to the Docker hub (a public registry) or a private registry also. Docker hub is a public registry that doesn't mean it won't allow you to have private repositories.

Docker builds images in a layered architecture

Each instruction written in a dockerfile creates a layer for a docker image, the first instruction forms a base layer and every next instruction layer upon the previous layer. These layers are stored as cache in the docker directory, so when a new docker image is created by using a docker file, it will only run the instructions that changed.

So, try to keep all the unchangeable instructions at the top, and changeable at the bottom, to minimize the build time. if docker encounters any change for an instruction it will build all the following instructions.

The container run over the final layer of the image, and this container layer is writable. You can read the Digging into Docker layers for some depth.

Docker-Compose

Docker-compose can be used to run multi-container services, By multi-container, I mean there is more than one container running on the same or different network. You can write all your configurations in a single YAML file.

What is it doing?

version: It specifies the version of the docker-compose file, read more about it here.

services: Services contain configuration for all the containers, that you wish to use in a docker-compose setup.

Hostname : web and redis are the hostname of the container, they are defined in a key-value structure, configuration for each container is defined in front of its hostname only.

build vs image : I have used build in one container, and image in other, what does it mean? Well, Build is used to explicitly build a docker image by using a dockerfile. I have specified the location for that dockerfile in front of build. And image can take the name of the pre-build image, and then it will be automatically pulled from the docker hub.

volume mapping: when you want to mount a volume from the host in your container, in order to preserve data after the termination of the container.
<name of volume>:<location/in/container>

port mapping : It is used when you want to access the bridge networking, and use your container outside the private network of docker.
<container-port>:<host-port>

Networks : if I do not specify anything, docker-compose will directly create a default network for your project, but you can specify a network, and docker-compose will link containers to that network. This can be done to make a container discoverable on the same network or hide it from another network.

In the above diagram that I created in google slides, I have shown that the world can access only the frontend part, and those services can talk within the network easily and outside the network by using some configuration. The frontend can talk to the backend, but the backend part is not accessible to the world.

You can run the docker-compose file by using docker-compose command

docker-compose up

Reference

Docker layer

--

--