Dead simple process supervision for containers based on s6.
Inspired by s6-overlay
- Low memory overhead
- Simple lifecycle management
- Fast startup
- Reliable supervision
- Allow high inheritance
- We needed a way manage multiples processes within a single container.
- The solution should be memory efficient.
- The solution should be reliable and allow fast startup.
The following steps will ensure your project is cloned properly.
git clone https://github.com/amannocci/ignity
cd ignity && task setup
- To test you have to use the workflow script.
task test
- It will test project code with the current environment.
- To package you have to use the workflow script.
task package
- It will create a tar archive containing ignity.
- We use
s6
as supervision suite. ignity
is a wrapper arounds6
.- There are three different stage.
- The first stage is responsible of set up container environment.
- It will create
ignity
runtime directories. - Load & merge defined variables.
- The second stage will then run
perms
&init
scripts. - If everything is alright then it will start all services.
- If a command is defined, it will run after a defined delay and then exit.
- If a command isn't defined, it will run forever until a explicit signal or a crash.
- The third stage is responsible to bringing down the container.
- It will stop services and in parallel will run
finalize
scripts. - It will then kill everything and exit.
Parameter | Description | Value (Current) |
---|---|---|
IGNITY_CMD_WAIT_FOR_SERVICES_MAXTIME |
The maximum time (in milliseconds) the services could take to bring up before proceding to CMD executing | 5000 |
IGNITY_CMD_WAIT_FOR_SERVICES |
In order to proceed executing CMD overlay will wait until services are up | 0 |
IGNITY_KILL_FINALIZE_MAXTIME |
The maximum time (in milliseconds) a script in /etc/ignity/finalize could take before sending a KILL signal to it |
5000 |
IGNITY_KILL_GRACETIME |
How long (in milliseconds) ignity should wait to reap zombies before sending a KILL signal |
3000 |
IGNITY_SERVICES_GRACETIME |
How long (in milliseconds) ignity should wait services down before sending a down signal |
5000 |
USER |
User name to map with uid and gid | root |
USERMAP_GID |
User gid to map on files | 0 |
USERMAP_UID |
User uid to map on files | 0 |
- You can simply
git clone
the project in the scope of the dockerfile. - And then build your image as usual.
# Install ignity from source
COPY ignity/src /
RUN bash /usr/src/install-ignity.sh \
- By default,
ignity
isn't set as entrypoint. - If you want to use it to handle services and all specifics stuff you have to explicitly define it as entrypoint.
ENTRYPOINT [ "/init" ]
- Using
CMD
is a really convenient way to take advantage ofignity
. - Your
CMD
can be given at build-time in the Dockerfile, or at runtime on the command line, either way is fine. - It will be run under the s6 supervisor, and when it fails or exits, the container will exit. You can even run interactive programs under the s6 supervisor !
- Sometimes it's interesting to load env files to define default variables.
- You can simply put any env files in
/etc/ignity/envs
and they will be loaded during runtime in order. - They will be overrided by container environments variables.
- Creating a supervised service cannot be easier
- Just create a service directory with the name of your service into
/etc/ignity/services
- Put a
run
file into it, this is the file in which you'll put your long-lived process execution - You're done! If you want to know more about s6 supervision of servicedirs take a look to
servicedir
documentation.
- By default, services created in
/etc/ignity/services
will automatically restart. - If a service should bring the container down, you'll need to write a
finish
script that does that.
/etc/ignity/services/myapp/finish
:
#!/bin/execlineb -S0
s6-svscanctl -t /run/ignity/services-state
- It's possible to do more advanced operations.
/etc/ignity/services/myapp/finish
:
#!/bin/execlineb -S1
if { eltest ${1} -ne 0 }
if { eltest ${1} -ne 256 }
s6-svscanctl -t /run/ignity/services-state
- By default, all services are started at runtime.
- You can delay or disable automatic start by creating a
down
file in the service directory. - This file can be created at build time in
/etc/ignity/services/myapp/down
. - Or at runtime by creating the file in
/run/ignity/services/myapp/down
using init scripts. - Note that after first services start the service directory is
/run/ignity/services-state
instead of/run/ignity/services
. - Then you can start it manually by removing the file in
/run/ignity/services-state/myapp/down
and by callings6-svc -u /run/ignity/services-state/myapp
.
- Just before starting user provided services.
ignity
will execute in order all scripts present in/etc/ignity/init
.- And in parallel of bringing down user provided services.
ignity
will execute in order all scripts present in/etc/ignity/finalize
.- You can use this mecanism to setup the container or validate everything or clean some resources before container exit.
- If you want your custom script to have container environments available just make use of
with-env
helper, which will push all of those into your execution environment, for example:
/etc/ignity/init/01-example
:
#!/usr/bin/with-env sh
echo $MYENV
- This script will output whatever the
MYENV
enviroment variable contains. - This helper is only here for custom environments variables pushed in
/run/ignity/envs
directory.
- To run a container with a non root user, you have to define files and directories permissions in
perms
and then define the following in the Dockerfile
ENV \
USERMAP_UID="1000" \
USERMAP_GID="1000" \
USER="exploit"
RUN preboot
USER ${USERMAP_UID}:${USERMAP_GID}
- This will correct permissions at build time instead of runtime and will let the container start properly with a non root user.
- To run the container in read-only mode, you will have to mount a tmpfs at
/run/ingity
. - If you want to run it with a non root user, you will also need to match uid able to write, execute and read on this location.
tmpfs:
- "/run/ignity:exec,mode=1777,uid=<uid>"
- Sometimes it's interesting to fix ownership & permissions before proceeding because, for example, you have mounted/mapped a host folder inside your container.
- Ignity provides a way to tackle this issue using files in
/etc/ignity/perms
. - The pattern format followed by fix-perms files:
path recurse account fmode dmode
> /var/lib/mysql 1000:1000 0600 0700
-
path
: File or dir path. -
account
: Target accountuid:gid
. -
fmode
: Target file mode. For example,0644
. -
dmode
: Target dir/folder mode. For example,0755
. -
You can use variables
{{USERMAP_UID}}
and{{USERMAP_GID}}
in those files. -
They will be replaced at runtime or build time based on case.
-
You can also skip the permission phase by using
IGNITY_SKIP_PERMS=1
- When it comes to executing a service, no matter it's a service or a logging service, a very good practice is to drop privileges before executing it.
s6
already includes utilities to do exactly these kind of things:
In execline
:
#!/bin/execlineb -P
s6-setuidgid daemon
myapp
In sh
:
#!/usr/bin/env sh
exec s6-setuidgid daemon myservice
- If you want to know more about these utilities, please take a look to:
s6-setuidgid
,s6-envuidgid
ands6-applyuidgid
.
- It's convenient to prefix every scripts in
envs
,perms
,init
andfinalize
by number (two chars) to ensure execution order. - A common pattern is to dedicated 10 number by docker image layer to allow logic evolution.
It is possible somehow to tweak ignity
behaviour by providing an already predefined set of environment variables to the execution context:
IGNITY_CMD_WAIT_FOR_SERVICES_MAXTIME
(default = 5000): The maximum time (in milliseconds) the services could take to bring up before proceding to CMD executing.IGNITY_CMD_WAIT_FOR_SERVICES
(default = 0): In order to proceed executing CMD overlay will wait until services are up. Be aware that up doesn't mean ready. Depending ifnotification-fd
was found inside the servicedir overlay will uses6-svwait -U
ors6-svwait -u
as the waiting statement.IGNITY_KILL_FINALIZE_MAXTIME
(default = 5000): The maximum time (in milliseconds) a script in/etc/ignity/finalize
could take before sending aKILL
signal to it. Take into account that this parameter will be used per each script execution, it's not a max time for the whole set of scripts.IGNITY_KILL_GRACETIME
(default = 3000): How long (in milliseconds)ignity
should wait to reap zombies before sending aKILL
signal.IGNITY_SERVICES_GRACETIME
(default = 5000): How long (in milliseconds)ignity
should wait to reap zombies before sending a down signal.
If you find this project useful here's how you can help, please click the ποΈ Watch button to avoid missing notifications about new versions, and give it a π GitHub Star!
You can also contribute by:
- Sending a Pull Request with your awesome new features and bug fixed.
- Be part of the community and help resolve Issues.
The ignity
project is free and open-source software licensed under the Apache-2.0 license.