Is it possible to use my own `/init` ?

I wan´t to start more than one service inside a single machine, and would like to use some kind of supervisor.

I already tried the s6-overlay, but it doesn’t work since I’m using ENTRYPOINT [ "/init" ] on my Dockerfile and it conflicts with the firecracker /init (I suppose).

What are my options?

I already reached s6-overlay about making it work bellow another PID1, but couldn’t.

Also tried runit, and calling like this:

ENTRYPOINT ["runsvdir"]
CMD [ "/etc/services.d/" ]

kind of work, but I miss other s6-overlays features.

2 Likes

Hi!

Short answer: You can’t replace Fly’s init

In addition to to us the location of /init being an issue, and as you noticed, s6 REALLY wants to use pid 1 and refuses to start if it’s not used (in the latest version of s6).

:point_right: I believe if you downgrade s6 to one older major release, you can get around that (s6 might complain but won’t refuse to start).

I personally use supervisor for this, but I do resent that it’s the next best option because it requires the Python run time :confused:

I’ve heard of a thing that might allow a program to run as pid 1 being possible in the future, but I don’t work in that area and can’t say definitely (anything I say would be a total guess!)

1 Like

As a workaround, you can use unshare --fork --pid --mount-proc to create a new PID namespace where your init process will have PID 1:

ENTRYPOINT ["sh", "-c", "if [ $$ -eq 1 ]; then exec /init \"$@\"; else exec unshare --fork --pid --mount-proc /init \"$@\"; fi", "sh"]

(where /init is your init script.)

I don’t know if s6-overlay will work well with this workaround. You might want to post it on the s6-overlay GitHub issue to see what they think. Edit: This workaround doesn’t support kill signals; see below for an improved version.

Here is a minimal sample Dockerfile based on the s6-overlay quickstart:

FROM ubuntu
ARG S6_OVERLAY_VERSION=3.1.4.1

RUN apt-get update && apt-get install -y xz-utils

ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz

CMD ["sh", "-c", "echo CMD begin; sleep 10; echo CMD end"]

ENTRYPOINT ["sh", "-c", "if [ $$ -eq 1 ]; then exec /init \"$@\"; else exec unshare --fork --pid --mount-proc /init \"$@\"; fi", "sh"]

Note that when running the image locally, you’d typically need to use docker run --cap-add=SYS_ADMIN --security-opt apparmor=unconfined (or be lazy and use --privileged) in order to use unshare with --pid and --mount-proc, but this shouldn’t be necessary because the ENTRYPOINT in my workaround only uses unshare if it’s not already running as PID 1, and when you run the image locally it should have PID 1. (You can leave out --mount-proc and then you only need --cap-add=SYS_ADMIN, but then /proc will still show the original PID namespace which is very confusing.)

4 Likes

Update: The workaround I posted above doesn’t forward signals correctly (see documentation of --fork in unshare(1)), so it doesn’t support graceful shutdown. Here is a fancier version that forwards signals.

init-wrapper:

#!/bin/sh
# run /init with PID 1, creating a new PID namespace if necessary
if [ "$$" -eq 1 ]; then
    # we already have PID 1
    exec /init "$@"
else
    # create a new PID namespace
    exec unshare --pid sh -c '
        # set up /proc and start the real init in the background
        unshare --mount-proc /init "$@" &
        child="$!"
        # forward signals to the real init
        trap "kill -INT \$child" INT
        trap "kill -TERM \$child" TERM
        # wait until the real init exits
        # ("wait" returns early on signals; "kill -0" checks if the process exists)
        until wait "$child" || ! kill -0 "$child" 2>/dev/null; do :; done
    ' sh "$@"
fi

Dockerfile:

...

COPY init-wrapper /
ENTRYPOINT ["/init-wrapper"]
5 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.