Understanding pid 1 in an OCI container

I am trying to understand the OCI container runtime: in particular, where pid 1 comes from.

If I launch the “ubuntu” image, it keeps running:

nsrc@brian-kit:~$ incus launch oci-docker:ubuntu foo2
nsrc@brian-kit:~$ incus list | grep foo2
| foo2            | RUNNING | 10.11.12.72 (eth0)   |      | CONTAINER (APP) | 0         |

Docker has Entrypoint and/or Cmd: I can see only Entrypoint here though.

nsrc@brian-kit:~$ incus config show foo2 | grep oci
  image.type: oci
  oci.cwd: /
  oci.entrypoint: /bin/bash
  oci.gid: "0"
  oci.uid: "0"
  volatile.container.oci: "true"

Does that imply there is a long-running “bash” process in this container?

nsrc@brian-kit:~$ incus shell foo2
root@foo2:~# ps auxwww
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0 6346000 19100 ?       Ss   16:43   0:00 init
root          21  0.0  0.0   4588  3984 pts/0    Ss+  16:43   0:00 /bin/bash
root          25  0.0  0.0   4780  2992 pts/1    Ss   16:45   0:00 su -l
root          26  0.0  0.0   5016  4124 pts/1    S    16:45   0:00 -bash
root          31  0.0  0.0   8272  3896 pts/1    R+   16:45   0:00 ps auxwww

Looks like pid 21 is that process: if I exit and re-run incus shell, it’s still there. What is its stdin connected to? Then I remembered “incus console”:

nsrc@brian-kit:~$ incus console foo2
To detach from the console, press: <ctrl>+a q

root@foo2:/# echo $$
21
root@foo2:/#

OK, then this Entrypoint shell is what incus console connects to. And indeed, if I hit ctrl-D to exit this shell, the whole container exits. That’s good: I understand the persistence part now.

But the ps listing also begs the question, what is the init process in pid 1?

In a regular incus container, pid 1 is what you expect:

root@unifi:~# ps auxwww
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0  21228  9060 ?        Ss   17:10   0:00 /sbin/init
...
root@unifi:~# ls -l /sbin/init
lrwxrwxrwx 1 root root 22 Jul 11  2025 /sbin/init -> ../lib/systemd/systemd

The incus documentation says:

Incus assumes that any image it uses to create a new container comes with at least the following root-level directories:

  • /sbin/init (executable)


Incus spawns whatever is located at /sbin/init as the initial process of the container (PID 1)

However, the Ubuntu docker image is heavily cut down; it has no systemd, and there is no /sbin/init (although sysvinit-utils is installed, providing directory /usr/lib/init/)

root@foo2:~# ls -l /sbin/init
ls: cannot access '/sbin/init': No such file or directory
root@foo2:~# ls -l /proc/1/exe
lrwxrwxrwx 1 root root 0 Feb 23 16:49 /proc/1/exe -> /opt/incus/bin/incusd
root@foo2:~# cat /proc/1/cmdline; echo
init
root@foo2:~# ls /opt/incus/bin/incusd
ls: cannot access '/opt/incus/bin/incusd': No such file or directory

So it looks like incusd (or its child) on the host is acting as the init inside the container. Possibly this one:

1000000   563731  0.0  0.0 6272004 19204 ?       Ss   16:49   0:00 init

root@brian-kit:/home/nsrc# ls -l /proc/563731/exe
lrwxrwxrwx 1 1000000 1000000 0 Feb 23 17:00 /proc/563731/exe -> /opt/incus/bin/incusd
root@brian-kit:/home/nsrc# ls -l /proc/563731/cmdline
-r--r--r-- 1 1000000 1000000 0 Feb 23 16:50 /proc/563731/cmdline
root@brian-kit:/home/nsrc# cat /proc/563731/cmdline; echo
init

However, I’m having difficulty locating the init process in the incus source. Is it in a separate library, like lxc perhaps?

If the OCI image did contain /sbin/init, would incus run that instead? I think that’s worth documenting.

(Aside: with docker engine, whatever you give as your entrypoint is pid 1, unless you do docker run --init in which case you get tini as your pid 1. I’m just trying to understand what the key differences are between running a container in incus versus docker engine)