The apparent contradiction comes from the omission, in the article, of the user namespace hierarchy. Quoting the manpage:
User namespaces can be nested; that is, each user namespace—except
the initial (“root”) namespace—has a parent user namespace, and can
have zero or more child user namespaces. The parent user namespace
is the user namespace of the process that creates the user namespace
via a call to
clone(2) with the
In the article, process D is part of user namespace 2, which is nested inside user namespace 1. A single process belongs to a single user namespace, but that user namespace is nested inside its successive parents, all the way up to the root namespace.
Processes can be visible from multiple user namespaces; in particular, all processes are visible from the top-most user namespace (or if you prefer, from outside all user namespaces). The user ids attached to processes change values depending on the user namespace from which they’re queried, depending on the uid/gid maps used in each user namespace, and this is the point the article is trying to make.
You can see this for example by starting a rootless container running
ps inside the container will then show
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 12024 3196 pts/0 Ss 13:49 0:00 /bin/bash
but the same
bash process will show up as
skitt 23345 0.0 0.0 12024 3208 pts/0 Ss+ 15:49 0:00 /bin/bash
outside the container.
/proc/.../uid_map shows the uid map in use:
$ cat /proc/23345/uid_map
0 1000 1
1 624288 65536
This means that the “range” of uids from 0 to 0 inside the corresponding user namespace maps to 1000 in the user namespace I queried it from, and the range from 1 to 65536 maps to 624288–689823.