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.
In this tutorial, we have seen how we can connect to a shell of a running container and also how to start containers interactively.