Correlating `docker ps` with host's `ps` - linux

docker ps does not let me know the pid of the container itself. Doing command string matching between the outputs of docker ps and ps run on the host is not foolproof since I can have the same command run on the host.
Does anyone have a sure way of correlating the two?

To get the container's PID use below
$ CPID=$(docker inspect -f "{{ .State.Pid }}" $containerid)
To get all the child processes of the above process, use
$ pgrep -P $CPID

Related

Get internal docker PID by system PID

After I use exec command inside docker container I can get the PID with exec inspect. The problem is that this ID is not local to the container but a system PID. So I would get something like 22620 while the PID inside docker container is 695.
I know that docker uses process namespaces to isolate its processes. So I have tried to get the internal PID with
cat /proc/22620/status | grep NSpid
. This indeed gave me the PID I was looking for:
NSpid: 22620 695
But I need to parse this string to get the PID.
Is there a proper way to get the PID used by the docker container?
PS.
I need this process ID to kill the process started by other exec call. I cannot kill the system process as it is owned by root and I cannot use sudo.
Och. Use cut to filter a section from a line.
grep NSpid /proc/24918/status | cut -f3
Will give 695 from the example.

Docker container on Alpine Linux 3.7: Strange pid 1 not visible within the container's pid namespace

I am currently tracking a weird issue we are experiencing using dockerd 17.10.0-ce on an Alpine Linux 3.7 host. It seems for all the containers on this host, the process tree initiated as the entrypoint/command of the Docker image is NOT visible within the container itself. In comparison, on an Ubuntu host, the same image will have the process tree visible as PID 1.
Here is an example.
Run a container with an explicit known entrypoint/command:
% docker run -d --name testcontainer --rm busybox /bin/sh -c 'sleep 1000000'
Verify the processes are seen by dockerd properly:
% docker top testcontainer
PID USER TIME COMMAND
6729 root 0:00 /bin/sh -c sleep 1000000
6750 root 0:00 sleep 1000000
Now, start a shell inside that container and check the process list:
% docker exec -t -i testcontainer /bin/sh
/ # ps -ef
PID USER TIME COMMAND
6 root 0:00 /bin/sh
12 root 0:00 ps -ef
As can be observed, our entrypoint command (/bin/sh -c 'sleep 1000000') is not visible inside the container itself. Even running top will yield the same results.
Is there something I am missing here? On an Ubuntu host with the same docker engine version, the results are as I would expect. Could this be related to Alpine's hardened kernel causing an issue with how the container PID space is separated?
Any help appreciated for areas to investigate.
-b
It seems this problem is related to grsecurity module which the Alpine kernel implements. In this specific case, the GRKERNSEC_CHROOT_FINDTASK kernel setting is used to limit what processes can do outside of the chroot environment. This is controlled by the kernel.grsecurity.chroot_findtask sysctl variable.
From the grsecurity docs:
kernel.grsecurity.chroot_findtask
If you say Y here, processes inside a chroot will not be able to kill,
send signals with fcntl, ptrace, capget, getpgid, setpgid, getsid, or
view any process outside of the chroot. If the sysctl option is
enabled, a sysctl option with name "chroot_findtask" is created.
The only workaround I have found for now is to disable this flag as well as the chroot_deny_mknod and chroot_deny_chmod flags in order to get the same behaviour as with a non-grsecurity kernel.
kernel.grsecurity.chroot_deny_mknod=0
kernel.grsecurity.chroot_deny_chmod=0
kernel.grsecurity.chroot_findtask=0
Of course this is less than ideal since it bypasses and disables security features of the system but might be a valid workaround for a development environment.

Connecting to a specific shell instance in a docker container?

Let's say I have a running docker container my_container. I start a new shell session with:
docker exec -it my_container bash
And then I start a process (a Python script for example), and exit the container with cntrl-p then cntrl-q to keep the script running in the background. If I do this a few different times with a few different scripts, how do I reconnect to a specific shell instance so I can see the std out of my scripts? If I use docker attach my_container, I'm always placed into the first shell instance I initiated when I did my docker run command.
What I usually do is to start tmux inside the first shell. And then start any other processes inside a new window.
Although it is theoretically possible to do so, docker exec still has many issues and it is always better to avoid it for now.
This is a trivial mode, but may be it helps. Instead of "echo "..." substitude with your script names.
Run the container, then run your scripts directly with docker exec and redirect their output to different files.
docker exec -ti containerId /bin/bash -c 'echo "Hello script1" > /var/log/1.log'
docker exec -ti containerId /bin/bash -c 'echo "Hello script2" > /var/log/2.log'
Then you can look at the files by docker exec(uting) some other commands like cat, grep, tail or whatever you want:
docker exec -ti containerId /bin/tail -f /var/log/1.log
docker exec -ti containerId /bin/tail -f /var/log/2.log
Remind you could also use
docker logs containerId
to see the output redirect to /dev/stdout from commands running in the container, but, if I understood your need, in this case you would get the output from many scritps mixed in stdout.

Finding Docker container processes? (from host point of view)

I am doing some tests on docker and containers and I was wondering:
Is there a method I can use to find all process associated with a docker container by its name or ID from the host point of view.
After all, at the end of the day a container is a set of virtualized processes.
You can use docker top command.
This command lists all processes running within your container.
For instance this command on a single process container on my box displays:
UID PID PPID C STIME TTY TIME CMD
root 14097 13930 0 23:17 pts/6 00:00:00 /bin/bash
All methods mentioned by others are also possible to use but this one should be easiest.
Update:
To simply get the main process id within the container use this command:
docker inspect -f '{{.State.Pid}}' <container id>
Another way to get an overview of all Docker processes running on a host is using generic cgroup based systemd tools.
systemd-cgls will show all our cgroups and the processes running in them in a tree-view, like this:
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
├─docker
│ ├─070a034d27ed7a0ac0d336d72cc14671584cc05a4b6802b4c06d4051ce3213bd
│ │ └─14043 bash
│ ├─dd952fc28077af16a2a0a6a3231560f76f363359f061c797b5299ad8e2614245
│ │ └─3050 go-cron -s 0 0 * * * * -- automysqlbackup
As every Docker container has its own cgroup, you can also see Docker Containers and their corresponding host processes this way.
Two interesting properties of this method:
It works even if the Docker Daemon(s) are defunct.
It's a pretty quick overview.
You can also use systemd-cgtop to get an overview of the resource usage of Docker Containers, similar to top.
By the way: Since systemd services also correspond to cgroups these methods are also applicable to non-Dockerized systemd services.
I found a similar solution using a bash script in one line:
for i in $(docker container ls --format "{{.ID}}"); do docker inspect -f '{{.State.Pid}} {{.Name}}' $i; done
the process run in a docker container is a child of a process named containerd-shim (in Docker v18.09.4)
First figure out the process IDs of the containerd-shim processes.
For each of them, find their child process.
pgrep containerd-shim
7105
7141
7248
To find the child process of parent process 7105:
pgrep -P 7105
7127
In the end you could get the list with:
for i in $(pgrep containerd-shim); do pgrep -P $i; done
7127
7166
7275
When running this on the host, it will give you a list of processes running in a container with <Container ID>, showing host PIDs instead of container PIDs.
DID=$(docker inspect -f '{{.State.Pid}}' <Container ID>);ps --ppid $DID -o pid,ppid,cmd
docker ps will list docker containers that are running.
docker exec <id|name> ps will tell you the processes it's running.
Since the following command shows only the container's itself process ID (not all child processes):
docker inspect -f '{{.State.Pid}}' <container-name_or_ID>
To find a process that is the child of a container, this process ID must be find in directory /proc. So find "processID" inside it and then find the container hash from file:
/proc/parent_process/task/processID
and then cut container ID from hash (first 12-digits of the container hash) and then find the container itself:
#!/bin/bash
processPath=$(find /proc/ -name $1 2>/dev/null)
containerID=$(cat ${processPath}/cgroup | fgrep 'pids:/docker/' | sed -e 's#.*/docker/##g' | cut -c 1-12)
docker ps | fgrep $containerID
Save above script in a file such as: p2c and run it by:
p2c <PID>
For example:
p2c 85888
Another solution with docker container and docker top
docker ps --format "{{.ID}}" | xargs -I'{}' docker top {} -o pid | awk '!/PID/'
Note: awk '!/PID/' just remove the PID header from the output of docker top
If you want to know the whole process tree of docker container, you can try it
docker ps --format "{{.ID}}" | xargs -I'{}' docker top {} -o pid | awk '!/PID/' | xargs -I'{}' pstree -psa {}
Docker stats "container id"
Shows the resource consumption along with pid or simply Docker ps .
Probably this cheat sheet can be of use.
http://theearlybirdtechnology.com/2017/08/12/docker-cheatsheet/

How to enter bash of an ubuntu docker container?

I want to run an ubuntu container and enter bash:
[root#localhost backup]# docker run ubuntu bash
[root#localhost backup]#
The ubuntu container exits directly. How can I enter the bash?
Use -i and -t options.
Example:
$ docker run -i -t ubuntu /bin/bash
root#9055316d5ae4:/# echo "Hello Ubuntu"
Hello Ubuntu
root#9055316d5ae4:/# exit
See: Docker run Reference
$ docker run --help | egrep "(-i,|-t,)"
-i, --interactive=false Keep STDIN open even if not attached
-t, --tty=false Allocate a pseudo-TTY
Update: The reason this works and keeps the container running (running /bin/bash) is because the -i and -t options (specifically -i) keep STDIN open and so /bin/bash does not immediately terminate thus terminate the container. -- The reason you also need/want -t is because you presumably want to have an interactive terminal-like session so t creates a new pseudo-tty for you. -- Furthermore if you looked at the output of docker ps -a without using the -i/-t options you'd see that your container terminated normally with an exit code of 0.

Resources