Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

We know Docker is a powerful tool for creating, deploying, and running applications easily.

In the images vs containers tutorial, we discussed how Docker images are built using layers. We also discussed that the first layer is usually the operating system.

So, is it possible to connect to the container's operating system? Yes, it is. And now we're going to learn how to do it.

2. Connecting to an Existing Container

If we want to connect to an existing container, we should have any container in running status. For that, we must check the container status in our system with the docker ps command:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
4b9d83040f4a        hello-world         "/hello"            8 days ago          Exited (0) 8 days ago                       dazzling_perlman

As we have no running containers, let's start a RabbitMQ container as an example:

$ docker run -d rabbitmq:3

Once the container is started, we'll see it from another call to docker ps:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
b7a9f5eb6b85        rabbitmq:3          "docker-entrypoint.s…"   25 minutes ago      Up 25 minutes       4369/tcp, 5671-5672/tcp, 25672/tcp   trusting_bose

Now connecting to this container is as easy as executing:

$ docker exec -it b7a9f5eb6b85 sh

At this point, we have an interactive shell inside the container:

  • docker exec tells Docker that we want to execute a command into a running container
  • The -it argument means that it will be executed in an interactive mode – it keeps the STIN open
  • b7a9f5eb6b85 is the container ID
  • sh is the command we want to execute

Let's explore the operating system of our newly created container:

$ cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

It seems to be a Bionic Beaver Ubuntu. If we check the FROM instruction in the RabbitMQ Dockerfile we realize that this image is built using Ubuntu 18.04.

We can disconnect from the container with the exit command or just CTRL+d.

This example was easy because, when we start a RabbitMQ container, it keeps running until we stop it. On the other hand, sometimes we have to deal with containers that don't stay alive, like for example operating system containers. Let's see how to get into them.

3. Running Containers in Interactive Mode

If we try to start a new operating system container, for example, an 18.04 Ubuntu, we'll see that it doesn't stay alive:

$ docker run ubuntu:18.04
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                NAMES
08c26636709f        ubuntu:18.04        "/bin/bash"              10 seconds ago      Exited (0) 7 seconds ago                                        heuristic_dubinsky
b7a9f5eb6b85        rabbitmq:3          "docker-entrypoint.s…"   About an hour ago   Up About an hour           4369/tcp, 5671-5672/tcp, 25672/tcp   trusting_bose

While RabbitMQ container is still running, the Ubuntu one is stopped. Consequently, we can't connect to this container using the docker exec command.

A way to avoid that would be to run this container in an interactive mode:

$ docker run -it ubuntu:18.04

So now that we are inside the container we can check the shell type:

$ echo $0
/bin/bash

Actually, it's handy to use the –rm argument when we start a container in interactive mode. It'll make sure to remove the container when we exit:

$ docker run -it --rm ubuntu:18.04

4. Keep a Container Running

Sometimes we'll run into weird situations where we need to start and connect to a container, but the interactive mode doesn't work.

If we run into one of these situations is probably because something is wrong and it should be corrected.

But, if we need a fast workaround we can run the tail command in the container:

$ docker run -d ubuntu:18.04 tail -f /dev/null

With this command, we are starting a new container in detached/background mode (-d) and executing the tail -f /dev/null command inside the container. As a result, this will force our container to run forever.

Now we just need to connect using the docker exec command in the same way we have seen before:

$ docker exec -it CONTAINER_ID sh

Remember that this is a workaround and it should be only used in development environments.

5. Conclusion

In this tutorial, we have seen how we can connect to a shell of a running container and also how to start containers interactively.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

4
Leave a Reply

avatar
2 Comment threads
2 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
Loredana CrusoveanuSuvenduR. G. Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
R. G.
Guest
R. G.

Another Baeldung article that to me seems a bit rushed, I got lost in the context of when to run the command some of them fail. I don’t have the error at hand.

$ docker exec -it b7a9f5eb6b85 sh with a container id
$ docker run -it ubuntu:18.04 with another value, image name?
$ docker exec -it CONTAINER_ID sh with a generic container id

Loredana Crusoveanu
Guest

Hi R. G.,

Can you please clarify which part exactly isn’t clear for you and what types of errors you get?
Basically, with docker exec command you can use the container’s ID or its name interchangeably.
On the other hand, docker run accepts the image’s name.
You can always execute docker COMMAND –help for more information about a particular command.
Hope that helps.
Cheers.

Suvendu
Guest
Suvendu

I usually use ‘docker exec -it cont_name bash’ or bin/bash to get the bash shell inside container.

Loredana Crusoveanu
Guest

Hi Suvendu,
Yes, you can use the container’s name as well.
Cheers.