MRuby on Container / A Linux container runtime using mruby DSL for configuration, control and hooks
mRuby on Container / helper tools with DSL for your handmade linux containers.
Haconiwa (箱庭
- a miniature garden) is a container builder DSL, by which you can choose any container-related technologies as you like:
Haconiwa is written in mruby, so you can utilize Ruby DSL for creating your own container.
haconiwa
packages are provided via packagecloud.
Available for: CentOS >= 7 / CentOS ~> 6(Experimental, maybe kernel update required) / Fedora >= 23 / Ubuntu Trusty / Ubuntu Xenial / Debian jessie
(which are supported by best effort...)
(PR: We are welcoming package maintainers for other distro!!!)
Other linuxes users can just download binaries from latest:
VERSION=<specify version>
wget https://github.com/haconiwa/haconiwa/releases/download/v${VERSION}/haconiwa-v${VERSION}.x86_64-pc-linux-gnu.tgz
tar xzf haconiwa-v${VERSION}.x86_64-pc-linux-gnu.tgz
sudo install hacorb hacoirb haconiwa /usr/local/bin
haconiwa
# haconiwa - The MRuby on Container
# commands:
# run - run the container
# attach - attach to existing container
# ...
NOTE: If you'd like using cgroup-related features, install cgroup package such as cgroup-lite
(Ubuntu) or cgroup-bin
(Debian).
If you would not, these installation are not required.
Create mount points:
$ mkdir -p /var/another/root/etc
$ mkdir -p /var/another/root/home
Create the file example.haco
:
Haconiwa.define do |config|
config.name = "new-haconiwa001" # to be hostname
config.bootstrap do |b|
b.strategy = "lxc"
b.os_type = "centos"
end
config.provision do |p|
p.run_shell "yum -y install git"
end
config.cgroup["cpu.shares"] = 2048
config.cgroup["memory.limit_in_bytes"] = 256 * 1024 * 1024
config.cgroup["pids.max"] = 1024
config.add_mount_point "/var/another/root/etc", to: "/var/your_rootfs/etc", readonly: true
config.add_mount_point "/var/another/root/home", to: "/var/your_rootfs/home"
config.mount_independent "procfs"
config.mount_independent "sysfs"
config.chroot_to "/var/your_rootfs"
config.namespace.unshare "ipc"
config.namespace.unshare "uts"
config.namespace.unshare "mount"
config.namespace.unshare "pid"
config.capabilities.allow :all
config.capabilities.drop "cap_sys_admin"
end
Then run the haconiwa create
command to set up container base root filesystem.
$ haconiwa create example.haco
Start bootstrapping rootfs with lxc-create...
...
To re-run provisioning, you can use haconiwa provision
.
Then use haconiwa run
command to make container up.
$ haconiwa run example.haco
When you want to attach existing container:
$ haconiwa attach example.haco
Note: attach
subcommand allows to set PID(--target
) or container name(--name
) for dynamic configuration.
And attach
is not concerned with capabilities which is granted to container. So you can drop or allow specific caps with --drop/--allow
.
config.bootstrap
block support 6 strategies now.
strategy = "lxc"
lxc-create
commandlxc.project_name
to set PJ name. default to the dirnamelxc.os_type
to set OS type installed tostrategy = "debootstrap"
debootstrap
commanddeb.variant
to set Debian variant param to pass debootstrapdeb.debian_release
to set Debian's release name squeeze/jessie/sid and so on...deb.mirror_url
to set mirror URL debootstrap usesdeb.components
to set components installed. eg, 'base'
strategy = "git"
git
command :)git.git_url
to set the repository URL for clonegit.git_options
to set extra git
options by Array, if necessarystrategy = "tarball"
tar
command ;)tb.archive_path
to set the source archive path on your host machinetb.tar_options
to set extra tar
options by Array, if necessarystrategy = "shell" / "mruby"
shell.code
to set a shell or mruby code by string(heredoc is OK). You can pass the mruby code block for "mruby"
config.provision
block support some operations(in the future. now run_shell
only).
run_shell
to set plane shell script(automatically set -xe
-ed on run)
run_shell
multiple timesname:
option, then you can specify provision operation by haconiwa provision --run-only=...
config.environ
- A hash to pass environment variables to a created container. e.g. config.environ = {"FOO_KEY" => "value", ...}
config.workdir
- The working directory of haconiwa's init commandconfig.command.set_stdout/set_stderr
- Emit command's stdout/err to specified files. This is active only on daemon modeconfig.resource.set_limit
- Set the resource limit of container, using setrlimit
config.cgroup
- Assign cgroup parameters via []=
config.namespace.unshare
- Unshare the namespaces like "mount"
, "ipc"
or "pid" ...
. persist_in
option make the specified namespace persist in a bind-moounted-file
config.network
- Specify networking config. Network#namespace
and #container_ip
must be set. Other attributes are #bridge_name
, #bridge_ip
, #veth_host
, #veth_guest
config.capabilities.reset_to_privileged!
- Haconiwa has default capability whitelist to use. If you want to use customized black/whitelist, declare this firstconfig.capabilities.allow
- Allow capabilities on container root. Setting parameters other than :all
should make this acts as whitelistconfig.capabilities.drop
- Drop capabilities of container root. Default to act as blacklistconfig.add_mount_point
- Add the mount point of container. Source directory is resolved from the directory where a user run haconiwaconfig.mount_independent
- Mount the independent filesystems: "procfs", "sysfs", "devtmpfs", "devpts" and "shm"
in the newborn container. Useful if "pid"
or "net"
are unsharedconfig.chroot_to
- The new chroot rootconfig.uid=/config.gid=
- The new container's running uid/gid. groups=
is also respectedconfig.support_reload
- Specify reloadable parameters when invoked haconiwa reload
command. Only :cgroup
and :resource
are available for now and it is active only when they are defined following configuration blocks. See test cases and examplesconfig.wait_interval
- Specify the sleep interval in wait
and watchdog
loops by milli secondsconfig.metadata
- Add container's metadata(tagging) by ruby Hashconfig.lxcfs_root
- Set your host's lxcfs
mount point to cooperate with containersYou can pick your own parameters for your use case of container.
e.g. just using mount
namespace unshared, container with common filesystem, limit the cgroups for big resource job and so on.
config.add_general_hook(hookpoint, &block)
- Define hook codes that are invoked through the Haconiwa's spawning process. Hook points are below:
:before_fork
- Hooked just before the container process is forked:after_fork
- Hooked just after the container process is forked, in forked process:before_chroot
- Hooked just after container settins are applied (e.g. namespace, cgroup, caps, fs mounting) and just before do chroot in forked process:after_chroot
- Hooked just after the chroot is successful, in forked process. This is the last timing before doing exec()
and becoming a new program:before_start_wait
- Hooked before starting to wait()
the container process. Hook itself is invoked in the parent process:teardown_container
- Hooked after the container process has quitted, in the parent process. base.exit_status
is set:after_reload
- Hooked just after haconiwa reload
is invoked and successful:after_failure
- Hooked just after tha container process is exited with failure. base.exit_status
is setbase
, which is Haconiwa::Base object.:setup
- Hooked just before the supervisor processes are going to be forked:teardown
- Hooked after the supervisor processes have quitted all:system_failure
- Hooked just after tha container process is exited with failure
barn.exit_status
or barn.system_exception
will be availablebarn
, which is Haconiwa::Barn object.config.add_async_hook(option, &block)
- Define timer handler. Supported options:
:msec/:sec/:min/:hour
- First timeout to invoke hook.:interval_msec
- Define the interval timeout hooks, if this paramete exists.config.add_signal_handler(signame, &block)
- Define signal handler at supervisor process(not container itself). Available signals are SIGTTIN/SIGTTOU/SIGUSR1/SIGUSR2
. See handler example.config.validate_real_id(&block{|ruid, rgid| ... })
- Validates the Real UID/GID who invoked haconiwa command. return true if OK, false/nil to mark invalid. This is useful when haconiwa command is set-user-ID rootPlease check out sample
directory.
e.g.:
Namespace.unshare(Namespace::CLONE_NEWNS)
Namespace.unshare(Namespace::CLONE_NEWPID)
Mount.make_private "/"
Mount.bind_mount "/var/lib/myroot", "/var/lib/haconiwa/root"
Dir.chroot "/var/lib/haconiwa"
Dir.chdir "/"
c = Process.fork {
Mount.mount "proc", "/proc", :type => "proc"
Exec.exec "/bin/sh"
}
pid, ret = Process.waitpid2 c
puts "Container exited with: #{ret.inspect}"
See dependent gem's READMEs.
rake compile
will create binaries.rake
won't be passed unless you are not on Linux.0.6, 0.8, 0.10, 1.0...
): Stable release0.7, 0.9, 0.11, 1.1...
): Unstable release. Features added at this version should be broken0.5.x
0.6.x-dev
for releasemaster
branch. Maintainers will pick these to stable/unstable dev branchesHaconiwa core is under the GPL v3 License: See LICENSE file.
Haconinwa's logo is originally created by @takeshige, and is under Creative Commons License BY-NC-ND 4.0.
Bundled libraries (libcap, libcgroup, libargtable and mruby) are licensed by each authors. See LICENSE_*
file.
For other mgems' licenses, especially ones which are not bundled by mruby-core, please refer their github.com
repository.