I have had it a couple of times already that I am running a container and quickly want to see the contents of some of the files that are in the container (e.g. verify some settings file or quickly view/edit the source of the scripts in the container). Just like in the above image, I only want to cut a hole or quickly open a window into the container contents :)
The first thing that comes to mind is to use a command like
docker exec -it <CONTAINER_NAME> /bin/bash
to get a bash shell in the running container and use this bash shell to move around in the container.
Simple access/viewing works this way, but when I need to go through some of the source files, my editor of choice is, of course, the best editor there is: ViM (Don't worry, the rest of this post will also hold if you have another favorite :) ).
Normally we should NOT be able to use ViM in the container because it is good practice to keep your container images to the minimum needed. Typically, additional editors like ViM do not need to be part of the container image, meaning that they will not be available in the running containers.
Of course, the action might be anything, instead of just using an editor, you might want to run any other program on the contents of the running container.
One way you can solve this is by using the shell in the running container to install the additionally required applications within the running container. However, if you have to do this more often, this approach becomes quite cumbersome.
Fortunately, there is another way to solve this issue and that is using the functionality of Docker to share the PID namespace between containers. In the case of our goal to see the contents of a container RunningContainer, you can achieve this by starting a new container ContainerB in the PID namespace of the original container RunningContainer. This is done by using the
--pid argument for the docker executable as follows:
docker run -it --rm --name ContainerB --pid container:RunningContainer alpine /bin/ash
By adding the additional argument, the processes are shared between the two containers. You can easily check this by running the
ps command in the shell of the new container. This in itself is already very useful, for example for debugging purposes. By giving ContainerB access to the processes of RunningContainer, you can effectively use a debugger on the process(es) running in RunningContainer.
One very cool side-effect of this process sharing that is extremely helpful for the goal I want to achieve is the fact that the process(es) that are running in RunningContainer also have a directory entry in the
/proc directory in the container ContainerB because they share the PID namespace. Within the subdirectory for each process under
/proc, there is a symlink called
root that is pointing to the root of the filesystem for that running process. By following this symlink for any of the processes running in the container RunningContainer, we end up in the root of the filesystem of the original container!
You can easily see this cool feature in action by starting the ash shell in a new container based on the alpine image as follows:
docker run -it --rm --name RunningContainer alpine /bin/ash
After the container is started, you can check that the
/tmp directory is empty by using the command
In a second terminal, you can now start another container that is sharing the namespace of the container we just created:
docker run -it --rm --pid container:RunningContainer --name ContainerB alpine /bin/ash
The ash process in RunningContainer will have pid 1 (it was started before all other processes). Using this information, we can now use the shell in ContainerB to create a new file in the
/tmp/ directory corresponding to the tmp directory of the process with pid 1 with the following command:
If you now go back to the terminal of the original RunningContainer container, you can verify that this new file
hello_RunningContainer.txt is now available under
/tmp by running the command