Fork me on GitLab

lxinitd

An init system for LXC

The primary goal of lxinitd is simplicity in launching multiple services in a container.

A common use case is to run a process and crond to schedule maintenance.

Configuring services is typically a one-liner in /etc/rc.local

#!/bin/lxinitd

service /var/run/nginx.pid /usr/sbin/nginx

service /run/lxcrond.pid /sbin/lxcrond
If your binary does not fork
reexec /bin/lxcrond
is sufficient.

This configuration will start the services and restart them if they fail.

Compared to system-V, systemd, supervisord, lxinitd is very simple. A single config file /etc/rc.local is read, no .service/.conf files, no symlinks, no start/stop/status scripts.
It is simple enough that no tools are needed to manage it.

For example, to configure sshd
service /var/run/sshd.pid /usr/sbin/sshd -D
to disable it
#service /var/run/sshd.pid /usr/sbin/sshd -D

A secondary goal of lxinitd is to create containers without bash. Often services need some kind of init, env variables or command line args.
lxinitd provides this without adding a shell.

Install

Install the .deb into a debian|ubuntu server that will host LXC containers. This will install the tools to /bin but will not modify the boot of the host server.

Then create lxinitd based containerized instances with...

lxc-create -t lxinitd -n mycontainer
This will copy lxinitd as /sbin/init and minimal tools from the host to the container. This gives you a Linux instance with /lib managed by the distribution (ubuntu|debian) and without systemd.

The resulting container has paractically no tools; not even ls or ps, and specifically does not have bash or any interactive shell or sshd. You can then add just the tools you wish by copying them to the rootfs in /var/lib/lxc/mycontainer/rootfs. This makes it easy to create "full OS" containers that have as little or less attack suface than an Dockerized app.

A base lxinitd container with lxinitd tools, lxmenu, pam, /bin/login and /sbin/getty wieghs in at...

root@mybox:/var/lib/lxc/lxinitd/rootfs# du -sh .
568K	.

More details in the manual

lxinitd is not specific to lxc.
It has no runtime dependencies, (its written in C and compiles to a static binary.) To use it in containers without lxc, just copy it to /sbin/init and provide /etc/rc.local, literally nothing else is needed.

lxinitd can be run outside containers as a userland app to keep a group of services alive.

rosh

Without bash its quite hard to configure the Linux boot process. lxinitd supports rosh syntax (a read only shell) that can exectue commands but has no features to write to the file system. There is no way to redirect output to a file. This enables scripting the boot of servers without adding a full shell into the container. If you need to, say, touch a file, you can copy /bin/touch to /var/lib/lxc/mycontainer/rootfs/bin, there is not too much damage you can do with touch.
You cant pipe commands into rosh so its quite difficult to abuse it.

lxinitd supports a set of shell builtins that can only run when lxinitd is running as process id 1. These are similar to coreutils but are statically compiled into lxinitd. Names are prefixed lx since they are not identical.
Supported builtins: lxmkdir, lxrm, lxmv, lxrmdir, lxtouch, lxchuid, lxln, lxmkfifo, lxmksock, lxmknod.

Download

Ubuntu|Debian installers are published here download .deb files

Launchpad install

sudo add-apt-repository ppa:teknopaul/lxinitd
sudo apt-get update
sudo apt-get install lxinitd

Apt install

Add the following to your /etc/apt/sources.list to use this repository.

deb http://download.tp23.org/download/deb/ ./
And run this to import the key
wget -q http://download.tp23.org/download/deb/public.gpg -O - | sudo apt-key add -