Manage container process from host

Manage container process from host

A running Docker container is just a process, isolated from the host and other containers using Linux kernel features, such as namespaces and cgroups. This is one of the main differentiators between VMs and containers.

When you start a Docker container, Docker creates a new process in the host system’s process tree. Then it will apply the container’s configuration such as its file system, network settings and so on to this process.

This makes the host OS consider a Docker container as just another process running on the system. Since the container is running as a process, we can actually use standard process monitoring tools, such as ps and top, to view the running container.

This post will examine how to find and access a container’s process ID (PID) and root filesystem directly from the host.

Spin up an Nginx container

docker run -d --name nginx nginx:latest

Access container PID

Docker stores information about the container, including its image, configuration, volume, process ID, and network, in a low-level JSON object. You can use the docker inspect to view this object. One way to do it is to pipe the output to jq and parse the JSON object as you wish, or query a scalar element by its name using Go lang template syntax, as follows:

# SYNTAX: docker inspect -f '{{.State.Pid}}' <CONTAINER_ID|CONTAINER_NAME>
docker inspect -f '{{.State.Pid}}' nginx

Check the /proc directory

In Linux, the /proc directory is a virtual file system that provides a view of the system’s running processes. It contains files and directories that are dynamically generated by the kernel to provide information about the processes.

Each process running on the system has its own subdirectory under /proc, identified by its process ID (PID). For example, if you have a process id = 12345, you’d find its subdirectory in this path: /proc/12345. Inside this subdirectory, you can find various files that provide information about the process, such as its memory usage, file descriptors, and more.

So, since the Nginx container that we spun up previously is just a process, we should see a directory named after its PID in /proc.

Let’s re-run the above command and assign the output to a variable, and check its proc directory:

PID=$(docker inspect -f '{{.State.Pid}}' nginx)
ls /proc/$PID

Now let’s inspect the container’s “root” filesystem /proc/$PID/root:

ls /proc/$PID/root
bin   dev                  docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   media  opt  root  sbin  sys  usr

If we exec into the container, we can see the same content from inside the container:

docker exec -it nginx 
root@ed08325bda2d:/# ls
bin   dev		   docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc			 lib   media  opt  root  sbin  sys  usr

Manipulate the container process

Like any process on the host, you can control it, but with some limitations. You can see below how the container was terminated using the kill command without interacting with the Docker daemon:

ps aux | grep $PID
root        8929  0.0  0.0   8936  5872 ?        Ss   11:30   0:00 nginx: master process nginx -g daemon off;
root        9053  0.0  0.0  17864  2408 pts/4    S+   11:31   0:00 grep --color=auto 8929

List the containers:

docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS     NAMES
522e39dfc08e   nginx     "/docker-entrypoint.…"   10 minutes ago   Up 7 minutes   80/tcp    nginx

Kill the container PID without using Docker daemon:

kill -9 $PID

Check again:

docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES