DevOps Series: Intro to Docker (Part - 2)

Photo by Ian Taylor on Unsplash

DevOps Series: Intro to Docker (Part - 2)

This blog is the second of a series of blogs that I will be writing as I continue to upskill in DevOps. I am excited to share my journey with you and hope you find these posts informative and helpful.

So far you've seen us create a container with an image that is already existing in our local image cache that we pulled in from the docker hub. But how will doing this help you or your particular application? That's a very good question. We will now look into how to create our own image (image of your application) using a Dockerfile and start a container with that image.

What is a Dockerfile?

A Dockerfile is a script that contains a collection of instructions that are used to build a Docker image. The Dockerfile provides a set of instructions to Docker to build a Docker image automatically. To put it simply, It has a couple of lines of configuration placed inside of it which define how our container behaves and what programs it contains and what should the container do when it starts up.

Though the configurations that go into a Dockerfile vary from application to application based on the specific requirements the application has, the structure of how it looks still remains the same. Please refer to the image below to get a rough idea of how to write a Dockerfile.

Now, lets try working on creating a simple Dockerfile and move on to understanding what each of those lines mean and understand the details of build process,

# Base Image specified here
FROM alpine

# Download and install a dependency
RUN apk add --update redis

# specifing a command to run during the start up of the container
CMD ["redis-server"]

Before getting into understanding what is a base image or any other things about writing Dockerfile, writing a Dockerfile is something like being given a computer with no operating system and expecting chrome (This is the application we are trying to containerise ) to be installed in it. what would be the steps we will be taking in this scenario?

  1. Install an Operating System

  2. Startup the default browser

  3. Browse chrome.google.com and download chrome installer

  4. Open the Downloads directory or any other directory chrome installer is downloaded to.

  5. Execute the chrome installer, follow the steps and install it.

  • Step - 1 here is like specifying the base image for the container

  • Step - 2 to 4 here are like downloading dependencies and installing them

  • Step - 5 is like executing the startup command in the container

Now, coming down to the simple Dockerfile we created above, the line

FROM alpine we are basically mentioning here that we are using the alpine docker image as an operating system for the image we are creating.

Why alpine?

That is a very good question to ask, what if I ask you why macOS or why Windows? you'd probably answer by saying macOS or Windows comes with a pre-installed set of programs or software tools that are helpful to me. Hmm, yeah that makes sense. The reason we are using alpine here is also kinda the same, alpine has a set of programs or tools that are very helpful to accomplish what we are trying to do (install redis ). we can check the line:2 of code above RUN apk add --update redis this is not a docker command or something that is related to docker. apk is a pre-installed package manager of alpine.

What happens behind the scenes? (Build Process)

Step - 1 in the above-mentioned code is kind of standard, it's just checking if the alpine image already exists in the image cache in the local machine and if not reaches out to the docker hub to download the image into the image cache.

From step - 2 is when things will start getting interesting,

Once the alpine image is downloaded, step-2 (RUN apk add --update redis ) created a temporary container using the downloaded alpine image filesystem snapshot and executes the command apk add --update redis. This will update the temporay container filesystem to something like this.

After this command, the file system snapshot is taken again and a temporary image is created again for use in the upcoming steps.

Now in step-3, the image created in step-2 is used to create a new temporary container again and the command that we need to execute i.e. (redis-server) will be executed and finally the container is stopped and the filesystem snapshot is taken again which in this case is the final image that we are expecting.

Please refer to the entire process that is happening behind the scenes in the image below:

Generating the Image Manually (without Dockerfile):

We can very much do what we are achieving using a Dockerfile above manually using docker commit command. This is what the sequence of steps we should be doing if we choose to avoid using Dockerfile.

1. docker run -it alpine run (start a container with alpine image)

2. apk add --update redis

Now, open another terminal tab and execute docker commit command to take the snapshot of the current container file system.

1. docker ps

2. docker commit -c 'CMD["redis-server"]' <alpine-container-id>

-c here allows us to specify the command that needs to executed when the container is started using this image.

Tagging an Image

At this point, aren't you a little tired of having to get the IDs of the images to start a container? Yeah, I thought so and so did the people who invented it..xD. so they came up with a feature called tagging. isn't it good if we can just start a container with something like docker run redis/ docker run hello-world much less annoying isn't it? Hmm, there is a way you can tag the images you are creating too, using the -t flag during the docker build command:

docker build -t <tag-name> <specify the directory of files/folder to use for this build>

One good example would be docker build -t sridhar5/redis:latest , while you can absolutely give any tag to the image you are creating, there are however a few practices that are usually followed when tagging an image.

docker build -t sridhar5/redis:latest .

In this command if we look at the tag name: sridhar5/redis:latest, this is the usal practice to tag an image, <your user-name>/project-repo-name:version

if the image is already tagged, this command can also be used to run the container,

docker run <tag-name-of-the-image>

Credit to the instructor of the "Docker and Kubernetes: The Complete Guide" course on Udemy for all the pictures and his amazing explanation.

I hope this blog has given you some further insights on Docker. In the next blog, we will create a basic node application and try containerising the application and work with docker hands-on. I'm still learning and trying to upskill myself in DevOps. So if you find anything wrong with my understanding above, please leave a comment below (Always curious to learn) and if you have any questions or comments, please feel free to leave them below. Thank you for reading. Will see you in the next one. Stay Tuned. Peace..✌️