├── .gitignore ├── LICENSE ├── README.md ├── bin.js ├── help.txt ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mathias Buus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mini-container 2 | 3 | A minimal container runtime that does very few things 4 | 5 | ``` 6 | npm install mini-container -g 7 | ``` 8 | 9 | ## Notice 10 | 11 | This currently relies on chroot and should be migrated to something like cgroups in the future. 12 | 13 | ## Usage 14 | 15 | A container is just a folder some where on your system that contains a unpacked 16 | linux distro. An easy way to create a container that just has ubuntu 14.04 is to use debootstrap 17 | 18 | ``` 19 | mkdir container 20 | cd container 21 | sudo debootstrap --variant=buildd --arch amd64 trusty . http://archive.ubuntu.com/ubuntu/ 22 | ``` 23 | 24 | This will install a local version of ubuntu in `./container`. To boot a bash process inside 25 | this container just do 26 | 27 | ``` 28 | # assuming you are in ./container 29 | sudo mini-container /bin/bash # runs /bin/bash sandboxed in this container 30 | ``` 31 | 32 | ## Volumes 33 | 34 | mini-container allows you to mount host folders inside your container using the `--volume /host/path=/container/path` flag 35 | 36 | ``` 37 | # mount /home/maf/test from the host on /root/test in the container 38 | sudo mini-container /bin/bash --volume /home/maf/test=/root/test 39 | ``` 40 | 41 | ## Programmatic usage 42 | 43 | ``` js 44 | var mini = require('mini-container') 45 | var child = mini('/bin/bash', { 46 | cwd: './container', 47 | volumes: { 48 | '/home/maf/test': '/root/test' 49 | } 50 | }) 51 | process.stdin.pipe(child.stdin) 52 | child.stdout.pipe(process.stdout) 53 | child.stderr.pipe(process.stderr) 54 | ``` 55 | 56 | ## License 57 | 58 | MIT 59 | -------------------------------------------------------------------------------- /bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var minimist = require('minimist') 4 | var path = require('path') 5 | var boot = require('./') 6 | 7 | var argv = minimist(process.argv.slice(2), { 8 | alias: { 9 | volume: 'v', 10 | cwd: 'c', 11 | print: 'p' 12 | }, 13 | boolean: ['print'] 14 | }) 15 | 16 | var toMap = function (list) { 17 | var result = {} 18 | list = [].concat(list) 19 | list.forEach(function (map) { 20 | var i = map.indexOf('=') 21 | result[path.resolve(map.slice(0, i))] = map.slice(i + 1) 22 | }) 23 | return result 24 | } 25 | 26 | var opts = { 27 | cwd: argv.cwd, 28 | volumes: toMap(argv.volume || []), 29 | stdio: 'inherit' 30 | } 31 | 32 | var command = argv._[0] 33 | 34 | if (!command || argv.help) { 35 | console.log(require('fs').readFileSync(path.join(__dirname, 'help.txt'), 'utf-8')) 36 | return 37 | } 38 | 39 | if (argv.print) console.log(boot.command(command, opts)) 40 | else boot(command, opts) 41 | -------------------------------------------------------------------------------- /help.txt: -------------------------------------------------------------------------------- 1 | Usage: mini-container [command] [options] 2 | 3 | --cwd, -c [/path/to/container] 4 | --volume, -v [/host=/container] 5 | --print, -p (print boot command instead of executing it) 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var execspawn = require('execspawn') 3 | 4 | var boot = function (cmd, opts) { 5 | return execspawn(boot.command(cmd, opts), opts) 6 | } 7 | 8 | boot.command = function (cmd, opts) { 9 | if (typeof cmd !== 'string') throw new Error('Command must be a string') 10 | if (!opts) opts = {} 11 | 12 | var dir = opts.cwd || process.cwd() 13 | var volumes = opts.volumes || {} 14 | var cmds = [] 15 | var cleanup = [] 16 | 17 | var procPath = JSON.stringify(path.resolve(path.join(dir, 'proc'))) 18 | var sysPath = JSON.stringify(path.resolve(path.join(dir, 'sys'))) 19 | var devPath = JSON.stringify(path.resolve(path.join(dir, 'dev'))) 20 | 21 | cmds.push('mount -t proc proc ' + procPath) 22 | cmds.push('mount -t sysfs sys ' + sysPath) 23 | 24 | cleanup.push('umount ' + procPath) 25 | cleanup.push('umount ' + sysPath) 26 | 27 | Object.keys(volumes).forEach(function (host) { 28 | var childPath = JSON.stringify(path.join(dir, volumes[host])) 29 | var hostPath = JSON.stringify(path.resolve(host)) 30 | cmds.push('mkdir -p ' + childPath) 31 | cmds.push('mount --bind ' + hostPath + ' ' + childPath) 32 | }) 33 | 34 | return '/bin/sh -c \'' + cmds.join('; ') + '\'; chroot . ' + cmd + '; ' + cleanup.join('; ') 35 | } 36 | 37 | module.exports = boot 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-container", 3 | "version": "1.1.1", 4 | "description": "A minimal container runtime that does very few things", 5 | "main": "index.js", 6 | "bin": { 7 | "mini-container": "./bin.js" 8 | }, 9 | "dependencies": { 10 | "execspawn": "^0.2.1", 11 | "minimist": "^1.1.1" 12 | }, 13 | "devDependencies": {}, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/mafintosh/mini-container.git" 17 | }, 18 | "author": "Mathias Buus (@mafintosh)", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/mafintosh/mini-container/issues" 22 | }, 23 | "homepage": "https://github.com/mafintosh/mini-container" 24 | } 25 | --------------------------------------------------------------------------------