Docker Containers
Last updated
Last updated
An image is a read-only template with instructions for creating a Docker container. Often, an image is based on another image, with some additional customization. For example, you may build an image which is based on the ubuntu
image, but installs the Apache web server and your application, as well as the configuration details needed to make your application run.
A Docker registry stores Docker images. Docker Hub is a public registry that anyone can use, and Docker is configured to look for images on Docker Hub by default. You can even run your own private registry.
When you use the docker pull
or docker run
commands, the required images are pulled from your configured registry. When you use the docker push
command, your image is pushed to your configured registry.
Now that you're familiar with the architecture, images, containers, and registries, you're ready to understand what happened when we executed the docker run hello-world
command.
The hello-world image is an example of minimal containerization with Docker. It has a single hello.c file responsible for printing out the message you're seeing on your terminal. Almost every image contains a default command. In case of the hello-world image, the default command is to execute the hello binary compiled from the previously mentioned C code.
A graphical representation of the process is as follows:
The entire process happens in five steps:
We execute the docker run hello-world command.
Docker client tells the daemon that we want to run a container using the hello-world image.
Docker daemon pulls the latest version of the image from the registry.
Creates a container from the image. Runs the newly created container.
It's the default behavior of Docker daemon to look for images in the hub, that are not present locally. But once an image has been fetched, it'll stay in the local cache. So if you execute the command again, you won't see the following lines in the output:
If there is a newer version of the image available, the daemon will fetch the image again. That :latest is a tag. Images usually have meaningful tags to indicate versions or builds. You'll learn about this in more detail in a later section.
In the previous section, we've had an introduction about Docker client. As we mentioned, It is the command-line interface program that takes our commands to the Docker daemon.Now , you'll learn about more advanced ways of manipulating containers in Docker.
In the previous section, we've used docker run to create and run a container using the hello-world image. The generic syntax for this command is:
Here image name
can be any image from Docker Hub or our local machine. I hope that you've noticed that I've been saying create and run and not just run, the reason behind that is the docker run command actually does the job of two separate docker commands. They are:
docker create <image name>
creates a container from given image and returns the container id.
docker start <image name>
starts a container by given id of a already created command.
To create a container from the hello-world image execute the following command:
The command should output a long string like this is the container id. c41d97e867380b372f56d4801e9e83b2b528da17792c390b4825bbb2289f9bcf
This id can be used to start the built container.
The first 3 or 4 characters of the container id are enough for identifying the container. Instead of using the whole string, using c41d97e867
should be fine.
To start this container execute the following command:
What happened here is we didn't attach our terminal to the output stream of the container. UNIX and LINUX commands usually open three I/O streams when run, namely STDIN, STDOUT, and STDERR.
If you want to learn more, read this article about this topic:https://borosan.gitbook.io/lpic1-exam-guide/1034-use-streams-pipes-and-redirects
To attach your terminal to the output stream of the container you have to use the -a
or --attach
option:
To see list of the running containers use docker ps
command :
you'll see that the container has run and exited successfully ! why ?
Unlike virtualmachines containers are not meant to host an Operating System, containers are meant to run specific task or process.(such as running an application server or web server or simply doing some computing tasks). Once the task is completed the container exits.
"A container only lives as long as the process inside it alive"
in our hello-world container example, container exits as soon as hello.c file printing out the message.
The -a
or --all
option indicates that we want to see not only the running containers but also the stopped ones. Executing ps without the -a option will list out the running containers only.
We've already used the start
command to run a container. There is another command for starting containers called restart
. Though the commands seem to serve the same purpose on the surface, they have a slight difference.
The start
command starts containers that are not running. The restart
command, however, kills a running container and starts that again. If we use restart with a stopped container then it'll function just as same as the start command.
Containers that have exited already, remain in the system. These dangling or unnecessary containers take up space and can even create issues at later times.
There are a few ways of cleaning up containers. If we want to remove a container specifically, we can use the rm
command. Generic syntax for this command is as follows:
So far we've only run containers built from the hello-world image. The default command for hello-world image is to execute the single hello.c program that comes with the image.
All images are not that simple. Images can encapsulate an entire operating system inside them. Linux distributions such as Ubuntu, Fedora, Debian all have official Docker images available in the hub.
We can run Ubuntu inside a container using the official ubuntu image. If we try to run an Ubuntu container by executing docker run ubuntu
command, we'll see nothing happens. But if we execute the command with -it
option as follows:
We should land directly on bash inside the Ubuntu container. In this bash window, we'll be able to do tasks, that we usually do in a regular Ubuntu terminal:
The reason behind the necessity of this -it
option is that the Ubuntu image is configured to start bash upon startup. Bash is an interactive program – that means if we do not type in any commands, bash won't do anything.
To interact with a program that is inside a container, we have to let the container know explicitly that we want an interactive session.
The -it
option sets the stage for us to interact with any interactive program inside a container. This option is actually two separate options mashed together.
The -i
option connects us to the input stream of the container, so that we can send inputs to bash.
The -t
option makes sure that we get some good formatting and a native terminal like experience.
We need to use the -it option whenever we want to run a container in interactive mode.
We can not run any random container in interactive mode. To be eligible for running in interactive mode, the container has to be configured to start an interactive program on startup. Shells, REPLs, CLIs, and so on are examples of some interactive programs.
To exit use ctrl+c or close the terminal and the container will be stopped.
Sometimes we need to run a container and meanwhile append a command inside that, for example To see a list of all directories inside the Ubuntu container, you can pass the ls command as an argument:
Notice that we're not using the -it option, because we don't want to interact with bash, we just want the output. We can pass any valid bash command as arguments. Like passing the pwd command as an argument will return the present working directory.
The list of valid arguments usually depends on the entry-point program itself. If the container uses the shell as entry-point, any valid shell command can be passed as arguments. If the container uses some other program as the entry-point then the arguments valid for that particular program can be passed to the container.
To keep the container running, you have to keep your terminal window open (which is meaningless).
You can run these kind of containers in detached mode. Containers running in detach mode run in the background like a service. To detach a container, we can use the -d
or --detach
option. To run the container in detached mode, execute the following command:
You should get the container id as output.
Now that you have a Redis server running in the background, assume that you want to perform some operations using the redis-cli tool. You can not just go ahead and execute docker run redis redis-cli. The container is already running.
For situations like this, there is a command for executing other commands inside a running container called exec, and the generic syntax for this command is as follows:
If the id for the Redis container is 970f1a18714a then the command should be as follows:
Notice we're using the -it option as this is going to be an interactive session. Now you can run any valid Redis command in this window and the data will be persisted in the server.
You can exit simply by pressing ctrl+p + ctrl+q key combination or closing the terminal window. Keep in mind however, the server will keep running in the background even if you exit out of the CLI program.
Starting Shell Inside a Running Container
If you want to use the shell inside a running container for some reason. You can do that by just using the exec
command with sh
being the executable like the following command:
Containers running in the foreground can be stopped by simply closing the terminal window or hitting ctrl + c key combination. Containers running in the background, however, can not be stopped in the same way.
There are two commands for stopping a running container:
docker stop <container id>
attempts to stop the container gracefully by sending a SIGTERM signal to the container. If the container doesn't stop within a grace period, a SIGKILL signal is sent.
docker kill <container id>
stops the container immediately by sending a SIGKILL signal. A SIGKILL signal can not be ignored by a recipient.
If you want to learn more, read this article about this topic: https://borosan.gitbook.io/lpic1-exam-guide/1035-create-monitor-and-kill-processes
To stop a container with id bb7fadc33178
execute docker stop bb7fadc33178
command. Using docker kill bb7fadc33178
will terminate the container immediately without giving a chance to clean up.
if you want to exit from a container without killing that Type Ctrl + p then Ctrl + q.
We can also use the logs
command to retrieve logs from a running container. The generic syntax for the command is as follows:
for example our redis container id is 970f1a18714a ,
in order to access the logs from the container:
This is just a portion from the log output. We can get the logs in real-time by using the -f
or --follow
option and Any later log will show up instantly in the terminal. We can exit by pressing ctrl+c
key combination or simply closing the window. The container will keep running even if you exit out of the log window.
For ease of transport, we'll be exporting the containers into a gzipped file. The command to export the containers is:
In similar fashion to the export, we're going to import the container with a single command. Obviously, before you do this, you must first move the exported file to the new server. the import can be handled with the following command:
okey lets go to the next section!
.
--------------------
https://www.freecodecamp.org/news/the-docker-handbook/ by Farhan Hasin Chowdhury
.