Link to video: https://www.youtube.com/watch?v=ifvrfriMDaA
Learn how a Container works based on its Lifecycle state and the Docker cli commands to manage them effectively
Have you ever felt overwhelmed by the multitude of docker
cli commands?
Have you ever been confused about what's actually happening with your Docker Containers?
If you have, don't worry... you're not alone. đ¤
How a Container behaves depends on which state it is in.
Luckily, once you understand how a Container works based on its Lifecycle state, you will be WAY more confident with Docker.
It will also be much easier for you to switch to more advanced Container management solutions like Docker Compose, Docker Swarm, Kubernetes, or OpenShift, etc.
So, let's learn about the Container Lifecycle, once and for all!
Introduction
In this blog, we will:
- learn about the different states a container can be in
- learn how to manage them using the
docker
cli - clear confusions regarding the differences between
-
docker pause
anddocker stop
-
docker stop
anddocker kill
-
- end with a detailed view of the container lifecycle
We'll also discuss POSIX signals briefly.
If you haven't read the first two blogs on the 'Docker made easy' series, I highly recommend you do so.
If you can't access Medium, try these:
Alright, let's begin by looking at...
The Container Lifecycle
The following diagram shows the states of a simplified Container Lifecycle, which determines how a Container behaves.
simplified container lifecycle state diagram
The text on the arrows corresponds to the docker
commands which allow that state transition.
As shown above, a container can be in the following states:
- Created
- Running
- Paused
- Stopped
- Deleted
Before we dive into each state, we need to know a tiny bit about POSIX signals.
Quick Overview of POSIX signals
Simply put, signals as a standard way that an Operating System (OS) tells a child process how to behave.
There are several signals, each having different purposes. But for us, we'll just focus on the following 2:
-
SIGTERM
: this signal is sent to a process to request its termination. It can be caught and interpreted or ignored by the process. This allows the process to perform graceful termination releasing resources and saving state if appropriate. -
SIGKILL
: this signal is sent to a process to cause it to terminate immediately. UnlikeSIGTERM
, this signal cannot be caught or ignored, and the receiving process cannot perform any clean-up upon receiving this signal (excluding few exceptions).
SIGTERM
is usually preferred over SIGKILL
since it provides a chance for graceful/safe termination of a process.
If interested, learn more about signals here.
Now let's discuss each state of the container lifecycle one by one...
Created state
This is the first state of the container lifecycle which comes after acquiring or building an Image.
Read the last blog to learn more about how Docker Images work.
Using the docker create
command, a thin writeable layer is created over the specified Image and prepared to run the main process command (CMD
and/or ENTRYPOINT
).
NOTE: On this state, the container is created but not started.
Here's an example of creating a container using the nginx:alpine
Image and naming it app1
.
docker create --name app1 nginx:alpine
The id of the new container is printed if successfully created.
Running state
As the name suggests, this is the state where the container is actively running. Meaning, the main process has started execution.
For a container that is created (using docker create
) or stopped, it can be started using docker start
.
So, to run app1 we can use -
docker start app1
If you don't want to explicitly create
and then start
a container, you can do both steps at once using the docker run
.
For example -
docker run -d --name app2 nginx:alpine
The command above creates and starts a container named app2
in the background (as specified by -d
).
Paused state
A running container can be paused using the docker pause
command. This has the effect of suspending (or freezing) all processes in the specified container.
When paused, the state of the container stays intact - both the disk (file-system) portion and the memory (RAM) portion.
NOTE: A container that is paused is unaware that it has been paused.
So, if we wanted to pause app1, we'd simply do -
docker pause app1
Similarly, to get the paused container back to running, we'd use unpause
-
docker unpause app1
Implementation detail (beyond scope): to implement pause
, the freezer cgroup
is used instead of POSIX signals.
Stopped state
A container that is stopped doesn't have its main processes actively running (I know, Duh đ¤ˇââī¸).
When stopped, the disk portion of the state is persisted i.e. saved.
But unlike when paused, the memory portion of the state is cleared when a container is stopped. This is the main difference between the paused and stopped states.
A container can be stopped in 4 primary ways:
- Using the
docker stop
command - Using the
docker kill
command - When the main container process has exited/completed
- When 'Out Of Memory Exception' (OOME) is encountered
Let's discuss each individually -
1. Using the docker stop
command
This command is as simple as -
docker stop app1
When executed, the main container process receives a SIGTERM
signal (by default) and after a grace period (default 10s as of writing), it receives a SIGKILL
signal.
2. Using the docker kill
command
When you run -
docker kill app2
the SIGKILL
signal is directly sent to the main container process (default behavior).
This means the difference between docker stop
and docker kill
is that - stop
can allow safe termination (within the grace period) while kill
terminates immediately.
For this reason, stop
is preferred over kill
. Review 'Quick Overview of POSIX signals' above if you're confused.
It's important to note that, docker kill
can also be used to issue any signal to the container process using the âsignal
/-s
argument, not just SIGKILL
.
Here's an example of issuing the SIGINT
signal -
docker kill -s SIGINT app1
3. When the main process has exited/completed
A container can stop automatically if its main process has exited/completed.
This can happen if
- the main process runs into an exception/interrupt
- or if the task completes after a certain point in time (instead of running in an infinite loop like a server)
Here's a very simple example -
docker run alpine echo "hi"
This command runs the echo "hi"
command inside an alpine container, prints "hi" to the console, and exits immediately after the echo
command is done.
4. When 'Out Of Memory Exception' (OOME) is encountered
If your containers attempt to use more memory than the system has available, you may experience an Out Of Memory Exception (OOME). As a result, some containers or even the Docker daemon might be killed by the kernel OOM killer.
Therefore, you should ensure that your application runs on hosts with adequate memory in production.
The simplest way of managing memory is by limiting the maximum amount of memory a container can use using the -m
option -
docker run -m 50m redis:alpine
This runs a container from the redis:alpine
Image with a memory limit of 50MB.
For learning more about managing memory and mitigating risks associated with OOME, refer to the official documentation.
Deleted state
A container that is in the created state or stopped can be removed with docker rm
. This will result in the removal of all data associated with the container like the processes, file system, volume & network mappings, etc.
If app1 is stopped, for example, you can remove it like -
docker rm app1
If however the container is running or paused and you attempt to remove it with docker rm
, you will get an error response from the daemon saying the container needs to be stopped.
If you are sure that your running container doesn't have any associated data which needs proper cleanup, then you can perform force removal using -f
-
docker rm -f app1
But it is recommended not to do this, especially if the data integrity of the container is important - like the case for databases.
Advanced Container Lifecycle
Here is a detailed diagram of the Container Lifecycle we just discussed including events in rectangles, courtesy of Docker Saigon.
This should be easier to understand if you have read the preceding discussion.
Or do you think I should have started with this instead of the simplified one? Interested to hear what you think.
Conclusion
Today we learnt about the different states a Container can be in - the Container Lifecycle, as well as how to use the docker
cli to maneuver through those states.
Once we know the basics of Containers, we can do really powerful stuff with more advanced tools like Docker Compose, Docker Swarm, Kubernetes, or OpenShift, etc.
Containers are awesome, and we're just getting started!
On the next docker blog, we'll discuss how Volumes work on Docker.
Till then, be bold and keep learning.
But most importantly...
Tech Care! đ
Top comments (0)