Skip to main content

Command Palette

Search for a command to run...

Diving into Docker (Part 3) : Container

Everything you need to know about container and its lifecycle

Published
9 min read
Diving into Docker (Part 3) : Container
D

I'm a mobile/web developer 👨‍💻 who loves to build projects and share valuable tips for programmers

Follow me for Flutter, React/Next.js, and other awesome tech-related stuff 😉

In the previous blog...

We learned about Images. What image is, and how it works internally. In this blog, we are gonna dive deep into Containers and learn what they are, how they differ from VMs, their use cases, their lifecycle, and much more. So let's get right into it.


What is a container?

Containers are one of the main ideas behind Docker. If you understand what a container is and how to run one, most Docker commands will start to make sense.

A container is a running copy of an image. What does that mean!!?

In the previous blog, we learned about images and saw that an image is like a blueprint/class that has everything needed to run an app. And to make use of the class what do we do in programming!!?? Yes, we make objects out of it.

That's what a container is. A container is what you get when you start that image. And you can start many containers from the same image, as you would with a class and an object.

Let's now see the difference between Containers and VMs, because hey, we had VMs earlier, which solved our problems, right? Then why container?

Containers vs Virtual Machines (VMs)

Containers and VMs both run on a host machine (your laptop, a server, or a cloud instance). But they work differently.

How VMs work

VMs use a hypervisor. You might or might not know about a hypervisor, so let me give you the basic idea about it.

Hypervisor

A hypervisor is software that lets you run multiple virtual machines (VMs) on one physical computer. It creates virtual machines, Gives each VM its own CPU, memory and storage. It keeps VMs isolated from each other and shares the physical hardware safely.

So instead of one computer running one OS, you can run: Window, Linux, Another Linux, etc all on the same machine

So each VM has, its own OS and kernel. This is why we say "Hypervisors virtualize hardware."

How do containers work?

Unlike VMs, containers do not create an OS for every app. It shares the host operating system and also shares its kernel.

What it does is split OS resources into isolated containers, meaning each container has its own filesystem, processes, and network space.

This is why we say, “Containers virtualize the operating system.”

One downside of containers is that they are less secure by default than VMs, because isolation is not as strong as that of VMs. There are ways to improve security, but they can add complexity.


Running your first container

Let's now create our first container, and the easiest way to start a container is:

docker container run <image> <app>

Example:

docker container run -it ubuntu /bin/bash

What this does:

  • docker container run creates and starts a new container

  • -it connects your terminal to the container (interactive mode)

  • ubuntu Is the image

  • /bin/bash is the app (a shell) that runs inside the container

Your terminal prompt will change because you are now inside the container.

What's happening behind the scenes?

So when you hit enter after running the above command, the Docker client will send this command to the API server running on the Docker Daemon. Docker Daemon will search for the Docker host's local image repository to see if it already has a copy of the requested image. If it finds the image, it will pull it locally, otherwise, it will go to the Docker hub (image repository) and see if it can find it there.

Once the image is pulled, Docker Daemon tells containerd and runc to create and start the container (remember the Docker architecture we discussed in Part -1). Once its done you will be able to get inside the container.

A container runs as long as the main app is running. If the app exists, the container stops. If you stop the container, it stops. If you remove the container, it is gone.


Stopping, starting, and deleting containers

Common lifecycle commands:

  • Stop a running container:
docker container stop <container>
  • Start a stopped container:
docker container start <container>
  • Remove a container forever:
docker container rm <container>

Working with container processes

If you are inside a container running /bin/bash, and you kill that main bash process, the container stops.

To exit the container but keep it running:

  • Press: Ctrl-PQ

Now you are back on your host machine, but the container is still running in the background.

Check running containers:

docker container ls

Re-attach using exec

You can open a new shell inside the running container:

docker container exec -it <container_id> bash

This creates a new process inside the container.

So if you type exit here, the container can still stay alive because the original main process is still running.


Container lifecycle

You can give a custom name to your container like this

docker container run --name boo -it ubuntu:latest /bin/bash

After running it, we will be inside the container. Let's create a file here

cd tmp
echo "Hello World" > newfile
ls -l
cat newfile

Detach without stopping it:

  • Ctrl-PQ

Stop it:

docker container stop boo

Start it again:

docker container start boo

Go back inside:

docker container exec -it boo bash

Check the file:

cd tmp
ls -l
cat newfile

You will see the file is still there.

So what did we learn from this?

Two important notes

  1. That the data lives on the Docker host. If the host fails, the data is lost.

  2. Containers are meant to be immutable, so writing data inside them is not a good habit.

That is why Docker has volumes, which store data outside the container. We will look into volumes in the upcoming blog.


Stopping containers gracefully

There is a big difference between stopping and force-killing.

  • docker container stop is polite.

    It sends a SIGTERM to the main process (PID 1) and gives it time (usually 10 seconds) to shut down cleanly.

    If it does not stop in time, Docker sends SIGKILL.

  • docker container rm -f is not polite.

    It kills the container right away (no clean shutdown).


Restart policies

It’s often a good idea to run containers with a restart policy. Why do we care? Because in the real world, we might have some container that crashes or stops suddenly, and we want them to restart automatically. This is where Restart policies come into play.

Restart policies enable Docker to automatically restart them after certain events or failures have occurred.

Common policies are:

  • always - If we attach this policy to the container, Docker will always restart the stopped container if it's closed by Docker or fails.

  • unless-stopped

  • on-failed (often written as on-failure)

Example: Let's create a container with the always policy attached.

docker container run --name zoo -it --restart always ubuntu:lastest bash

Now If you type exit, and get out of the container, the container stops, but Docker starts it again because the policy is always. Try docker container ls and see.

See how the container was created 19 seconds ago, but has only been up for 11 seconds. This is because the exit command killed it and Docker restarted it. Be aware that Docker has restarted the same container and not created a new one.

Difference between always and unless-stopped:

  • always: restarts even after Docker daemon restarts

  • unless-stopped: does not restart after daemon restart if it was already in a stopped state

Let's see it in action: Create two container with name always and unless-stopped with respective policies attached

docker container run -d --name always \                                                               
--restart always \
ubuntu:latest sleep 1d
docker container run -d --name unless-stopped \                                                               
--restart always \
ubuntu:latest sleep 1d

Now check with docker container ls

Now lets run, and restart the Docker

docker container stop always unless-stopped

Now run

docker container ls -a

Notice that the “always” container has been restarted but the "unless-stopped" container has not.

The on-failure policy will restart a container if it exits with a non-zero exit code.


Let's clean up everything and remove all the container now.

docker container rm $(docker container ls -aq) -f

Be careful with this command as this command will remove every container running forcefully.


Quick list of useful container commands

  • docker container run — start a new container

  • docker container ls — list running containers

  • docker container ls -a — list all containers (including stopped)

  • docker container exec — run a command inside a running container

  • docker container stop — stop a container

  • docker container start — start a stopped container

  • docker container rm — delete a container

  • docker container inspect — detailed container info

  • Ctrl-PQ — detach without stopping the container


Conclusion

We saw how container is beneficial and works with all the important commands to start, stop, and remove. Also we learned how restart policies plays an important role in Docker ecosystem.

In the next blog, we will implement everything we learned so far by containerizing the application. Untill then...