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:
- Linux namespace
- Linux control group(cgroup)
- Linux capabilities
- Bind mount / chroot
- Resource limit(rlimit)
- setuid/setgid
- ...
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=0.2.2
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 the file example.haco
:
Haconiwa::Base.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"
- needs
lxc-create
command lxc.project_name
to set PJ name. default to the dirnamelxc.os_type
to set OS type installed to
- needs
strategy = "debootstrap"
- needs
debootstrap
command deb.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'
- needs
strategy = "git"
- needs
git
command :) git.git_url
to set the repository URL for clonegit.git_options
to set extragit
options by Array, if necessary
- needs
strategy = "tarball"
- needs
tar
command ;) tb.archive_path
to set the source archive path on your host machinetb.tar_options
to set extratar
options by Array, if necessary
- needs
strategy = "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(automaticallyset -xe
-ed on run)- We can declare
run_shell
multiple times - Set name by
name:
option, then you can specify provision operation byhaconiwa provision --run-only=...
- We can declare
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, usingsetrlimit
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-fileconfig.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 respected
You 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
- 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 doingexec()
and becoming a new program:before_start_wait
- Hooked before starting towait()
the container process. Hook itself is invoked in the parent process:teardown
- Hooked after the container process has quitted, in the parent process- Every hook can accept one argument
base
, which is Haconiwa::Base object.
config.after_spawn(option, &block)
- Define timer handler. Pass option likemsec: 10 * 60 * 1000
, then after 10 min passed, the defined hook will be invokedconfig.add_signal_handler(signame, &block)
- Define signal handler at supervisor process(not container itself). Available signals areSIGTTIN/SIGTTOU/SIGUSR1/SIGUSR2
. See handler example.
Please look into sample
directory.
If there is a /etc/haconiwa.conf.rb
file like below, as a global config:
Haconiwa.configure do |config|
config.etcd_url = "http://localhost:2379/v2"
end
haconiwa
cli understands this DSL and uses etcd as a container database backend, with enabled clustering. We recommend to set etcd's server name to host's primary LAN IP(such as: ETCD_NAME="192.168.0.100"
).
You can run haconiwa ps
to check container processes (all over the hosts clustered by etcd!).
e.g.:
Namespace.unshare(Namespace::CLONE_NEWNS)
Namespace.unshare(Namespace::CLONE_NEWPID)
m = Mount.new
m.make_private "/"
m.bind_mount "/var/lib/myroot", "/var/lib/haconiwa/root"
Dir.chroot "/var/lib/haconiwa"
Dir.chdir "/"
c = Process.fork {
m.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.- This project is built upon great mruby-cli. Please browse its README.
- Versions whose minor versions are even numbers (
0.6, 0.8, 0.10, 1.0...
): Stable release - Versions whose minor versions are odd numbers (
0.7, 0.9, 0.11, 1.1...
): Unstable release. Features added at this version should be broken - I introduced this policy after version
0.5.x
- We create branches as
0.6.x-dev
for release - PRs can be proposed to
master
branch. Maintainers will pick these to stable/unstable dev branches
Bug reports and pull requests are welcome on GitHub at https://github.com/haconiwa/haconiwa. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
- Haconiwa DSL compiler
- Networking helpers
- P2P containers
Haconiwa core is under the GPL v3 License: See LICENSE file.
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.