Show HN: Slim – Build and run tiny VMs from Dockerfiles
github.com
github.com
> slim will build a micro-vm from a Dockerfile. Slim works by building and extracting a rootfs from a Dockerfile, and then merging that filesystem with a small minimal kernel that runs in RAM.
> This results in a real VM that can boot instantly, while using very limited resources. If done properly, slim can allow you to design and build immutable unikernels for running services, or build tiny and embedded development environments.
So far so good, for individual/standalone containers. But if you need thightly integrated containers (sharing networks, volumes, ports and so on) things may be a bit more complicated. And not sure about Kubernetes. YMMV
"Containers are less secure" is just FUD. That VM's or containers alike are running on the same CPU is currently a much more real threat.
Kata Containers (https://katacontainers.io) is more along the lines of a "VM replacement", although it is doing so using VMs.
Dockerfile.s must be progressively replaced with Nix recipes then we'd get lockfiles, upgradable dependencies, some day even reproducible builds!
- https://micromind.me/en/posts/from-docker-container-to-boota...
Really like seeing these new usecases for containers -- would have never thought to mix the two technologies in this way.
I'd personally blame marketing-speak on using "virtualization" at all (unless they refer to their windows/mac offerings, which can run a Linux VM as the docker host, on which the containers are run), but I can see how one could also stretch a definition of virtualization in a way that covers container.
Sometimes containers are run in VMs, but they are almost defined as "do not require a full VM running an OS, but instead talk to the host kernel".
> Simply put, containers are just processes, and as such they are governed by the kernel like any other process. Thus any kernel-land vulnerability which yields arbitrary code execution can be exploited to escape a container. To demonstrate this, Capsule8 Labs has created an exploit that removes the process from its confines and gives it root access in the Real World. Let’s take a look at what was involved.
(I don't know much about capsule8 as a company is but that article[0] is pretty informative and seems spot on from what I read)
If you can infiltrate a process (let's say a web server) running in a container and know a kernel exploit that can be used to get past these limitations (a "container escape"), then you can use them and get root on the main system.
If that same process was running in a VM (without a container), you need to:
- Infiltrate the process
- Kernel exploit to gain root (assuming the program wasn't running under it) in the VM
- Escape the VM (i.e. use the kernel or whatever else to actually break past the barriers of the hypervisor which was running the vm -- qemu +/- kvm, hyperv,etc) -- aka a "virtual machine escape"[1]
- Gain root on the host system (assuming the process that spawned the hypervisor wasn't running as root)
Generally, virtual machine security is pretty good these days, by virtue of being around longer and having more exposure and eyes looking for exploits.
[0]: https://capsule8.com/blog/practical-container-escape-exercis...
> A docker container is not a VM, it is a regular process, isolated with the use of cgroups and namespaces, possibly protected (like any other process) with selinux/apparmor/etc.
Where virtual machines will actually virtualize a whole machine (down to having BIOS for your imaginary motherboard and a CPU for this imaginary machine), linux containerization virtualizes the resources & environment available to a single running process via the use of namespaces (pid, user, etc) and cgroups (available cpu, memory, etc).
So basically, there's a bunch of code in the kernel (shared between all containers) that enables the accurate reporting of all the "virtualized" resources/environment (cpu, memory, other pids running) -- that code can be exploited, which would be a "container escape". Dirty Cow[1] is an example of one of these escapes.
Here are my personal recipes: https://github.com/pauldotknopf/darch-recipes
It was a pattern I saw with Hugo and other Go projects.
Tell us a Docker image, a command with arguments to run and a cron schedule - and we will execute the task and send its STDOUT to your preferred endpoint (either an email or webhook). We're in beta and are offering 15$ worth of execution time as free trial and would really appreciate HNers giving it a try.
Our blog post has more details: http://polyglot.network/cloudcron
This is very useful when trying to create a basic datacenter specific distro/deployment, preferably Pixie bootable as well.
Note work at VMware but not on this project.
I'm not sure what the value of this is.
This is a step in that direction. Cool stuff!
[1] - https://github.com/firecracker-microvm/firecracker-container...
``` @sindresorhus/is JSONStream ansi-regex ansi-styles archive-type argparse asn1 async balanced-match base64-js bcrypt-pbkdf bl bluebird brace-expansion buffer buffer-alloc buffer-alloc-unsafe buffer-crc32 buffer-fill buffer-from cacheable-request camelcase caw chalk chownr cliui clone-response color-convert color-name commander concat-map concat-stream config-chain content-disposition core-util-is cross-spawn debug decamelize decode-uri-component decompress decompress-response decompress-tar decompress-tarbz2 decompress-targz decompress-unzip docker-modem dockerode download duplexer3 emoji-regex end-of-stream escape-string-regexp esprima execa ext-list ext-name fd-slicer file-type filename-reserved-regex filenamify find-up from2 fs-constants fs-extra fs-minipass fs.realpath get-caller-file get-proxy get-stream glob got graceful-fs graceful-readlink has-flag has-symbol-support-x has-to-string-tag-x hasbin http-cache-semantics ieee754 inflight inherits ini into-stream invert-kv ip is-fullwidth-code-point is-natural-number is-object is-plain-obj is-port-available is-retry-allowed is-stream isarray isexe isurl js-yaml json-buffer jsonfile jsonparse keyv lcid locate-path lodash lowercase-keys make-dir map-age-cleaner md5-file mem mime-db mimic-fn mimic-response minimatch minimist minipass minizlib mkdirp ms mustache nice-try node-virtualbox normalize-url npm-conf npm-run-path object-assign once os-locale p-cancelable p-defer p-event p-finally p-is-promise p-limit p-locate p-timeout p-try path-exists path-is-absolute path-key pend pify pinkie pinkie-promise prepend-http process-nextick-args progress proto-list pump query-string readable-stream require-directory require-main-filename responselike safe-buffer safer-buffer scp2 seek-bzip semver set-blocking shebang-command shebang-regex signal-exit simple-git sort-keys sort-keys-length split-ca sprintf-js ssh2 ssh2-streams streamsearch strict-uri-encode string-width string_decoder strip-ansi strip-dirs strip-eof strip-outer sudo-prompt supports-color tar tar-fs tar-stream through timed-out to-buffer trim-repeated tunnel-agent tweetnacl typedarray unbzip2-stream universalify url-parse-lax url-to-options util-deprecate uuid which which-module wrap-ansi wrappy xtend y18n yallist yargs yargs-parser yauzl ```
After `left-pad` and `flatmap-stream`, attempts to justify the state of affairs in the JS ecosystem are patent absurdities. They show starkly that the platform vendor needs to offer a reasonably-robust basic toolkit, and that cultures of "every function should be published as a library!" are a massive risk factor.
A good first-party standard library should be considered a security requirement for every application. Dependencies should be brought in with care and attention, not in a massive indiscriminate orgy of nested modules spraying every function into its independent own library and resulting in every node.js application requiring its own 500MB+ folder of libraries to even start.
Think it doesn't get worse? People are now using node.js to distribute "business cards". Arbitrary JavaScript execution on your local user account. Has science gone too far?! Someone at npmjs.com sure has by allowing this kind of thing. [0]
The technical world is crumbling. Who can fix it?
[0] https://blog.bitsrc.io/malicious-npm-development-kit-a02401e...
...which it isn't, given that the "fs" module has a wide variety of features much beyond an equivalent to open().
I half-jokingly said that Node apps are the new ZIP bombs.
Vendoring/copying them is another way to achieve this (and means you don't need to depend on npm or its lockfiles).
Regardless, those libraries are your problem whether you vendor/copy them or not.
Read more: https://research.swtch.com/deps
- Carl Sagan
the npm ecosystem takes this quite literally, for better or worse.
I’ve never understood why they didn’t go with the Maven approach: all dependencies stored in a central location, separated by version.
This can be particularly bad when a popular package has a semver major change (even if, for example, support for an outdated version of node is dropped), many libraries will lag behind in updating to the latest major version and you will have many duplicated copies of a popular package.
chalk: log formatting
dockerode: docker API
download: file download?
fs-extra: functions like mkdirp, emptyDir
hasbin: check if bin exists in PATH
js-yaml": yaml parser
mustache: templating
node-virtualbox: VB API
progress: terminal progress bar
simple-git: Git API
sudo-prompt
tar
uuid
It looks reasonable at first sight. Of all these, fs-extra is the only one you can argue should be part of the standard lib.A lot of the other dependencies are simply cruft, for example, `safe-buffer, `safer-buffer`, `buffer-alloc`, `buffer-alloc-unsafe` all patch the same issue and haven't been necessary since ~2016 / node 6.0. Same for `sort-keys`, object key sort order was baked into the ES2015 spec and has been the default behaviour since the beginning of the decade.
As mentioned by other commenters, this is a result of an extremely easy-to-use packaging system, coupled with a culture of sharing and reusability. The dark side of it is (justified) laziness and reinvention of the wheel - the core functionality of many of these modules can be written in one or two lines of code, but it is indeed faster and safer to just import something that exists and has been tested. The vast number of choices means it's hard to find standard solutions, and this also encourages developers to create their own 'improved' version of everything, in a self-reinforcing loop. The language itself has been in constant change, meaning new flavours of previously stable modules pop up to support new patterns (promises, generators, await, classes, etc etc). Then you get egos, marketing and corporate sponsorship added to the mix :)
The topic has come up, but I'm generally against it; sure, we could spend all the resources on doing all the filtering and analysis and change management that it would take to establish a sane package base that we could officially support for internal development work... But why? We do it for other languages, but Node has a lot of "my first programming language" bs going on in the ecosystem. I strongly suspect that allowing Node development would be a net negative for our company.
No... responsible companies exclude ALL programming languages except those that they can responsibly support -- you don't want the new guy writing some a critical piece of infrastructure in Haskell or Ada or Lisp or something because they feel it's morally superior, and then find out it can't integrate with some critical management system because it doesn't have the right bindings, or that it doesn't run on your upgraded production environment, or whatever. When you have tens of thousands of programmers, it's guaranteed to happen unless you proactively prevent it.
No, we have a handful of programming languages where we can guarantee that everything works, that the important infrastructure is accessible, that every library will remain supported until we replace it, that every vulnerability can be patched within a given timeframe, that code will run correctly on every machine, and so forth. Taking on a new language means dedicating a whole team of engineers to maintaining support for that language, indefinitely.
Some companies may be able to YOLO their way through decisions based on what what's popular at any given moment, but when you operate at any serious scale you have to be a bit more... responsible.
* If the size of the initrd is too large, it cannot properly unpack into vm's RAM --- size of RAM must be increased accordingly. We could also change [boot params](https://www.lightofdawn.org/blog/?viewDetailed=00128), or use shared disks, etc.
* For hyperkit, apple's vmnet requires sudo to create a bridge interface on host. We've played with a version that use's vpnkit and port forwarding (like linuxkit/Docker for Mac), but this adds lots of complexity in image, and opted for the simpler approach.
* We would like a better template mechanism for reusing base images and extending. Right now, we support using base image reuse, with extensions through docker buildargs---ideally, we would want something like %include support in Dockerfiles.
* Finally, we're investigating how to make images work well on multiple providers. For example, ubuntu does not play nice with hyperkit out-of-the-box, but works fine for vbox and kvm.
Cloud-ready images is an important direction, and on the horizon.
Not sure what you mean.. could you give some examples?
In my experience, people prefer Docker over VM's because they _like_ the abstractions and tooling associated with it. It's a lot friendlier to developers and makes immutable infrastructure a much more realistic goal for ops folks, IMO.
https://github.com/weaveworks/footloose
(Disclamer: I'm the author of footloose)
Really excited to play with this tonight
Dockerfile > slim > iso
> `$ slim build images/alpine3.8-simple`
> This will add a bootable iso in the slim registry.
AWS Fargate and AWS Lambda run entirely on micro VMs.
Why not just start with a tiny vm and call it a day?
> Run Linux or other Operating Systems in your browser!
It runs in your browser.
If you clicked the link you would also see demo links that run in your browser.
Such as gaming SaaS thingies.
Getting shell in a new copy of container:
docker run -it --entrypoint=/bin/sh ${container}
Running shell inside a running container:
docker exec -it ${container} /bin/sh
Running sshd inside a container to let you peek inside is bad taste, and bad security, too.
You might be able to add QEMU support to this, and then run it on an Android device if you have root. But it would perform terribly because mobile chips generally don't have virtualization extensions and ARM as a virtualization host is a pretty immature platform.
TL;DR - far too much to be practical.
That browser instance alone can make quite a noticeable difference.
docker run -it --entrypoint /bin/sh -v $PWD:/bla -v /run/docker.sock:/run/docker.sock node:12
apk add git docker cdrkit libvirt-daemon qemu-system-x86_64
npm install https://github.com/ottomatica/slim
cd /bla && /node_modules/.bin/slim
Or, do you only run software hand crafted in assembly?
TBH, I think the code would be a lot simpler if it was just Bash.