Right now if one passes a mount propagation flag in spec file, it
does not take effect. For example, try following in spec json file.
{
"type": "bind",
"source": "/root/mnt-source",
"destination": "/root/mnt-dest",
"options": "rbind,shared"
}
One would expect that /root/mnt-dest will be shared inside the container
but that's not the case.
#findmnt -o TARGET,PROPAGATION
`-/root/mnt-dest private
Reason being that propagation flags can't be passed in along with other
regular flags. They need to be passed in a separate call to mount syscall.
That too, one propagation flag at a time. (from mount man page).
Hence, store propagation flags separately in a slice and apply these
in that order after the mount call wherever appropriate. This allows
user to control the propagation property of mount point inside
the container.
Storing them separately also solves another problem where recursive flag
(syscall.MS_REC) can get mixed up. For example, options "rbind,private"
and "bind,rprivate" will be same and there will be no way to differentiate
between these if all the flags are stored in a single integer.
This patch would allow one to pass propagation flags "[r]shared,[r]slave,
[r]private,[r]unbindable" in spec file as per mount property.
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
runc
runc is a CLI tool for spawning and running containers according to the OCF specification.
State of the project
Currently runc is an implementation of the OCI specification. We are currently sprinting
to have a v1 of the spec out within a quick timeframe of a few weeks, ~July 2015,
so the runc config format will be constantly changing until
the spec is finalized. However, we encourage you to try out the tool and give feedback.
OCF
How does runc integrate with the Open Container Initiative Specification?
runc depends on the types specified in the
specs repository. Whenever the
specification is updated and ready to be versioned runc will update its dependency
on the specs repository and support the update spec.
Building:
At the time of writing, runc only builds on the Linux platform.
# create a 'github.com/opencontainers' in your GOPATH/src
cd github.com/opencontainers
git clone https://github.com/opencontainers/runc
cd runc
make
sudo make install
In order to enable seccomp support you will need to install libseccomp on your platform.
If you do not with to build runc with seccomp support you can add BUILDTAGS="" when running make.
Build Tags
runc supports optional build tags for compiling in support for various features.
| Build Tag | Feature | Dependency |
|---|---|---|
| seccomp | Syscall filtering | libseccomp |
| selinux | selinux process and mount labeling | |
| apparmor | apparmor profile support | libapparmor |
Testing:
You can run tests for runC by using command:
# make test
Note that test cases are run in Docker container, so you need to install
docker first. And test requires mounting cgroups inside container, it's
done by docker now, so you need a docker version newer than 1.8.0-rc2.
You can also run specific test cases by:
# make test TESTFLAGS="-run=SomeTestFunction"
Using:
To run a container, execute runc start in the bundle's root directory:
runc start
/ $ ps
PID USER COMMAND
1 daemon sh
5 daemon sh
/ $
OCI Container JSON Format:
Below are sample config.json and runtime.json configuration files. It assumes that
the file-system is found in a directory called rootfs and there is a
user with uid and gid of 0 defined within that file-system.
config.json:
{
"version": "pre-draft",
"platform": {
"os": "linux",
"arch": "amd64"
},
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0,
"additionalGids": null
},
"args": [
"sh"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": ""
},
"root": {
"path": "rootfs",
"readonly": true
},
"hostname": "shell",
"mounts": [
{
"name": "proc",
"path": "/proc"
},
{
"name": "dev",
"path": "/dev"
},
{
"name": "devpts",
"path": "/dev/pts"
},
{
"name": "shm",
"path": "/dev/shm"
},
{
"name": "mqueue",
"path": "/dev/mqueue"
},
{
"name": "sysfs",
"path": "/sys"
},
{
"name": "cgroup",
"path": "/sys/fs/cgroup"
}
],
"linux": {
"capabilities": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"rootfsPropagation": ""
}
}
runtime.json:
{
"mounts": {
"proc": {
"type": "proc",
"source": "proc",
"options": null
},
"dev": {
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
"devpts": {
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
"shm": {
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
"mqueue": {
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
"sysfs": {
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
"cgroup": {
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
},
"hooks": {
"prestart": null,
"poststop": null
},
"linux": {
"uidMappings": null,
"gidMappings": null,
"rlimits": [
{
"type": 7,
"hard": 1024,
"soft": 1024
}
],
"sysctl": null,
"resources": {
"disableOOMKiller": false,
"memory": {
"limit": 0,
"reservation": 0,
"swap": 0,
"kernel": 0,
"swappiness": -1
},
"cpu": {
"shares": 0,
"quota": 0,
"period": 0,
"realtimeRuntime": 0,
"realtimePeriod": 0,
"cpus": "",
"mems": ""
},
"blockIO": {
"blkioWeight": 0,
"blkioWeightDevice": "",
"blkioThrottleReadBpsDevice": "",
"blkioThrottleWriteBpsDevice": "",
"blkioThrottleReadIopsDevice": "",
"blkioThrottleWriteIopsDevice": ""
},
"hugepageLimits": null,
"network": {
"classId": "",
"priorities": null
}
},
"namespaces": [
{
"type": "pid",
"path": ""
},
{
"type": "network",
"path": ""
},
{
"type": "ipc",
"path": ""
},
{
"type": "uts",
"path": ""
},
{
"type": "mount",
"path": ""
}
],
"devices": [
{
"path": "/dev/null",
"type": 99,
"major": 1,
"minor": 3,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
},
{
"path": "/dev/random",
"type": 99,
"major": 1,
"minor": 8,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
},
{
"path": "/dev/full",
"type": 99,
"major": 1,
"minor": 7,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
},
{
"path": "/dev/tty",
"type": 99,
"major": 5,
"minor": 0,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
},
{
"path": "/dev/zero",
"type": 99,
"major": 1,
"minor": 5,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
},
{
"path": "/dev/urandom",
"type": 99,
"major": 1,
"minor": 9,
"permissions": "rwm",
"fileMode": 438,
"uid": 0,
"gid": 0
}
],
"apparmorProfile": "",
"selinuxProcessLabel": "",
"seccomp": {
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": []
},
"rootfsPropagation": ""
}
}
Examples:
Using a Docker image (requires version 1.3 or later)
To test using Docker's busybox image follow these steps:
- Install
dockerand download thebusyboximage:docker pull busybox - Create a container from that image and export its contents to a tar file:
docker export $(docker create busybox) > busybox.tar - Untar the contents to create your filesystem directory:
mkdir rootfs
tar -C rootfs -xf busybox.tar
- Create
config.jsonandruntime.jsonusing the example from above. You can also generate a spec usingrunc spec, which will create those files for you. - Execute
runc startand you should be placed into a shell where you can runps:
$ runc start
/ # ps
PID USER COMMAND
1 root sh
9 root ps
Using runc with systemd
[Unit]
Description=Minecraft Build Server
Documentation=http://minecraft.net
After=network.target
[Service]
CPUQuota=200%
MemoryLimit=1536M
ExecStart=/usr/local/bin/runc
Restart=on-failure
WorkingDirectory=/containers/minecraftbuild
[Install]
WantedBy=multi-user.target