
Bocker – Docker implemented in around 100 lines of Bash (2015) - sturza
https://github.com/p8952/bocker/blob/master/README.md
======
tluyben2
Until well into the 2000s we deployed all our services as chroots. I even sold
a server side product successfully which was distributed as chroot so it would
install almost on any Linux distro without having to care about dependencies.
It worked really well and felt quite a bit more accessible and lighter than
docker. We just had a script which basically did:

    
    
        wget https://bla/image.tgz
        tar xzf image.tgz
        rm image.tgz
        chroot image/start
    

and the product would be installed and up & running. A lot of clients thought
it was magic. No Apache install? No MySQL install?? It works on Fedora &
Centos & Debian & Ubuntu & ... ?

I use this currently still a lot to run new software on unsupported
hardware/kernels. For instance, I run a lot of new (Ubuntu) software on my
OpenPandora under the default OS on that device; I have an SD with a chroot
with Ubuntu and things like dotnet core. Runs fine. Gives devices like that a
second youth.

~~~
Riverheart
Any notable downsides to using chroots?

~~~
rotten
1) There were/are sometimes ways to break out of them. 2) The process table is
mixed in with your OS process table - making it hard to tell what is running
chrooted and what isn't. 3) The network stack is shared 4) They share an OS

You can make a "spectrum" of environments where you run code. One one side is
everything running on a single server in a single OS, on the right is
everything having its own machine and OS. In between you have chroot, docker,
blade servers, virtual machines, and other isolation techniques. chroot falls
somewhere between everything running in one system, and everything running in
docker containers on one system.

~~~
seba_dos1
1) should actually be "there are ways to break out of them, period". chroot
isn't a security feature, it doesn't even try to be one.

~~~
crdrost
This. If you want the security features, switch to a BSD (jails) or illumos
(zones). These started spiritually from that same chroot place but were
designed to incarcerate your software in a small subsystem.

The illumos ecosystem in particular got a lot of work from Joyent in this
container vein—like how Windows can now run Linux binaries natively because
they implemented the Linux system call table, illumos has Linux-branded zones
that do the same “our kernel, Linux’s API, no virtualization” approach to
Linux containers.

~~~
ncmncm
Windows runs Linux binaries by running Linux in a VM. Something newish is that
Windows _also_ implements Windows by running NT and a Windows UI in a VM.

Running on a hypervisor originated at IBM, on its 370, and is very mature
technology. Arguably, an OS running on bare metal is practically an embedded
system, these days; There are just so many things that make a hypervisor
useful or essential.

The key insight IBM had was that the hypervisor runs under the control of one
of its VMs. That means the hypervisor doesn't need to provide a full-featured,
comfortable work environment; that is the job of guest OSes. Instead, it
manages resources according to policies implemented in an "executive" guest OS
not used for, or vulnerable to mistakes or malevolence in, regular user
programs.

A modern example of such a system is Qubes, security-oriented OS that hosts
and orchestrates Linux, BSD, and even Windows VMs.

~~~
JonathonW
WSL 2 is virtualization-based (and likely Microsoft’s primary path going
forward), but WSL 1 was _not_ — it actually did implement the Linux ABI on top
of the Windows kernel, allowing Linux processes to coexist alongside Windows
processes (with no actual Linux kernel involved at any point).

It’s actually a pretty neat architecture— I’m on my phone right now and can’t
track down a link, but it’s worth reading about if you’ve got the time. Kind
of a shame that they moved on to the virtualization approach, but
understandable— they’re trying to solve the same sort of problem as Wine,
where you’ve got to mimic _all_ the quirks of a foreign OS and it’s also a
moving target (so you’re never “done”).

~~~
miohtama
File system access is super slow on WSL. This was one the drivers. If I recall
correctly it is because some common Linux syscalls (stat?) are missing/slow on
Windows NT kernels.

~~~
celticmusic
The filesystem in general is known to be much slower on Windows due to it's
extreme flexibility, but Linux design decisions assumed a much more performant
filesystem. Hence why running linux on windows slammed into the performance
problem.

------
soygul
Quoting from the source code:

    
    
       [[ $# -gt 0 ]] && while [ "${1:0:2}" == '--' ]; do OPTION=${1:2}; [[ $OPTION =~ = ]] && declare "BOCKER_${OPTION/=*/}=${OPTION/*=/}" || declare "BOCKER_${OPTION}=x"; shift; done
    

If the ambition is to write lines like this, you can make it into ~1 line of
code.

~~~
bawolff
I dont even read or write bash shell scripts regularly and i can understand
what that line is doing fine. I would not be able to understand if the entire
thing was one line, so i think there is a significant difference.

Just because something doesn't follow general rules for readable code, doesn't
mean it is actually unreadable.

~~~
viraptor
Do you actually know what it's doing, or are you guessing and inferring from
patterns? There's a difference when you actually need to read the source for
details rather than a quick skim.

I can definitely guess the pattern and I do write bash regularly, but I see at
least 2 things I'd need to double-check the man page for the behaviour.

~~~
bawolff
If you are asking if i have memorized bash syntax fully and know that
everything he did was valid, than the answer is no. However the intent of the
code and what each component is supposed to do is clear, which is what i'm
looking for when reading code.

Heck, by this definition i'm not sure any code is really good enough. In my
job i have to write php daily, i still need to regularly look at docs to
figure out order of arguments for various library functions. I wouldn't be
able to tell if explode($a, $b) in php has the right argument order at a
glance without looking it up. But i understand the intent and generally assume
the superficial aspects of the code are right unless that part appears not to
work.

And furthermore, adjusting the number of newlines isn't going to help with the
question of if that piece of code is using bash syntax correctly.

~~~
organsnyder
I don't see anyone claiming that the syntax is incorrect. But it definitely
causes me to have to stop and do some mental processing (mainly thinking about
order of operations) to make sense of it.

------
phinnaeus
I do really like the implementation of help text:

    
    
        function bocker_help() { #HELP Display this message:\nBOCKER help
         sed -n "s/^.*#HELP\\s//p;" < "$1" | sed "s/\\\\n/\n\t/g;s/$/\n/;s!BOCKER!${1/!/\\!}!g"
        }

~~~
t0mek
Initially I thought that bash supports reflection and is able to get the
function contents, including comments. But this function scans its own script
file ($1), looking for the comments starting with #HELP and formatting them.
This way the usage info can live near the functions implementing sub-commands.

~~~
andreineculau
Yup. It is a nice trick that you might find more often in Makefile. I have a
make target that does this consistently in all the makefiles I write:
[https://github.com/andreineculau/core.inc.mk/blob/master/tar...](https://github.com/andreineculau/core.inc.mk/blob/master/target.help.inc.mk)

    
    
      target1: ## Do this
      target2:
      target3: target2 ## Do that
    

would be nicely formatted as the output of `make help` into

    
    
      Available targets:
        target1  Do this
        target2  Do that
    

and if you want to see all targets along with their origin file, even those
without help messages, type `make help-all` to render

    
    
      Available targets:
        target1  path/to/Makefile  Do this
        target2  path/to/Makefile
        target3  path/to/Makefile  Do that

------
sixstringtheory
No doubt this is cool and represents good work! Nice job!

Can we really say it’s a reimplementation of Docker in 100 lines, though, when
it requires other dependencies that probably total in the hundreds of
thousands of lines? That’s still code that has to be audited by people so
inclined. Not to mention the other setup specified in the readme and maybe
having to build one of the dependencies from source. Usage doesn’t sound
necessarily trivial.

Makes me appreciate Docker that much more though. Getting up to speed using it
at my job and it certainly abstracts away many things, simplifying our
workflow and conceptual models.

~~~
brianpgordon
I think the idea is to show how much container functionality is actually
available out-of-the-box from the operating system. It raises questions about
Docker's billion dollar valuation when someone can come along and reproduce a
bunch of it with a short shell script. Next someone needs to take on
orchestration and show how silly it was for IBM to pay $34 billion for
OpenShift. :P

~~~
m0xte
It’s all about creating a brand and selling it these days.

I actually wrote the core of an ansible class tool in 200 lines of Perl 20
years ago. Perhaps I should have been bought by red hat by now :)

~~~
eeZah7Ux
> It’s all about creating a brand and selling it these days.

Yes, and that's a big problem.

Nowadays huge numbers of developers pick choose technologies because they are
hyped up (aka marketed) rather than being wary of them.

~~~
rhacker
meh - I mean, I don't know what language you write in today, but I would wager
it's a language that has had at least a million spent in some kind of
marketing, books, directly or indirectly or through advocacy (that also costs
money as it's a company telling employees to put effort into that instead of
other things). And if you include that, we're probably talking about $1M to
1/2 billion if it's in the top 10 tiobe index.

~~~
eeZah7Ux
I use different languages, none of which is company-driven or had significant
marketing campaigns, starting from Python.

Same for other projects (not programming languages).

------
nickjj
The real value in Docker isn't process isolation at a low level.

It's being a toolset to build and deploy containerized applications.

In other words, being able to docker-compose up --build on any Linux, Windows
and MacOS box is what's useful.

~~~
crdoconnor
docker compose is the tool that winds me up the most.

~~~
gureddio
May I ask why?

~~~
crdoconnor
[https://docs.docker.com/compose/startup-
order/](https://docs.docker.com/compose/startup-order/)

>The problem of waiting for a database (for example) to be ready is really
just a subset of a much larger problem of distributed systems. In production,
your database could become unavailable or move hosts at any time. Your
application needs to be resilient to these types of failures.

absolute bullshit. docker compose thinks that it can excuse its bugs by dint
of the fact that we're supposed to build "more resilient" applications to
accommodate them.

and, their proposed workaround with "wait for" is disgusting. their tool
should be able to handle readiness detection. it's so fucking basic.

it's not only this but this is an example of the bullshit in this shitty tool
excused with shitty reasons.

~~~
nickjj
> my test of "does my application work given that the database is running" is
> explicitly not accommodated.

Are you working with tools where this is a problem in practice?

Most web frameworks I've used will keep trying to connect to the DB in a loop
until it either connects and things start normally, or it times out after X
amount of seconds where X by default is configured to some number that's way
higher than it would normally take for your DB to be available, even if it's
starting from scratch with no existing volume.

No "wait for it" script needed (and I do agree that type of solution is very
hacky). Although to be fair the same page you quoted said the best solution is
to handle this at the app level, which is what most web frameworks do.

~~~
crdoconnor
Yes, I remember it was a problem with Django. It wasn't just the application
server, you might need to run some scripts, after the database is up, before
kicking off the webserver. Any workflow like this is explicitly
unaccommodated.

100% of the solutions ive seen to address this problem have been hacky -
either polling bash scripts or explicit waits.

docker compose is a piece of shit.

------
zantana
This bubbled up the other day which was interesting as well.

[https://blog.alexellis.io/building-containers-without-
docker...](https://blog.alexellis.io/building-containers-without-docker/)

It does seem like Docker will be holding back containers from achieving their
true promise, as it flounders looking for profitability and chasing k8s. Its
sad that we're still moving around tar balls without advancing some of the
tooling around it.

One of my biggest gripes as a non-k8s container user are that we are still
keeping all this versioned cruft with every container. I would like to see an
easier way to just get the latest binaries not dozens of tar hashes with
versions going back to the first iteration of the container. Probably closer
to singularity [https://singularity.lbl.gov/](https://singularity.lbl.gov/)

Another area is the ability to update containers in place. Hass.io
[https://www.home-assistant.io/hassio/](https://www.home-assistant.io/hassio/)
does some of this with the ability to manage the container version from within
the container, but seems like a little bit of a hack from what I've seen.
Watchtower is closer to what I'd like
[https://github.com/containrrr/watchtower](https://github.com/containrrr/watchtower),
but why can't we have a more integrated system built into the default tooling?

~~~
efrecon
I have successfully used code built around my gist at
[https://gist.github.com/efrecon/8ce9c75d518b6eb863f667442d7b...](https://gist.github.com/efrecon/8ce9c75d518b6eb863f667442d7bc679)
to recreate containers that have the identical set of original options, but
with a newer image.

------
adgasf
Docker is designed to push you towards DockerHub, not to be the simplest or
best container implementation.

~~~
vpEfljFL
Why do you think it's not a good practice?

Docker is a good tool and deserves some resources to continue developing the
product and funding marketing team. I wish docker hub to be more competitive
among other rivals.

~~~
adgasf
> Why do you think it's not a good practice?

I didn't say it wasn't. Docker makes sense because everyone uses it.

However, I would prefer a Docker alternative that is purely local and doesn't
require so many permissions.

~~~
my123
podman is one, and it can even work just fine without root permissions.

~~~
MadWombat
Really? How can it run a web server container, for example, without root
permissions? You need root to listen on port 80.

~~~
takeda
Well, isn't that a specific case though? From my experience most containerized
apps use higher port.

In FreeBSD you would be able to also remove such restrictions if needed (not
sure if something is also available on Linux) alternatively you could have
your app listening on a higher port and use iptables to forward port 80 there.

~~~
MadWombat
> From my experience most containerized apps use higher port

Most public images I see on Docker Hub run on default ports. Sure, a lot of
these are configurable, but then you need to reconfigure all the consumer
services to use a non-default port. FreeBSD is not an option, unless you are
willing to run on your own hardware. As for iptables, does podman provide
network isolation where you can define iptable rules per container? I know it
wouldn't work with docker.

------
mirimir
Cute.

For me, the hardest thing about Docker was running my own registries. Or
rather, configuring credentials so Docker would use them. Not to mention the
hassle of doing that through Tor.

So maybe Bocker isn't so picky about registries.

------
thebeardisred
Fun anecdote: Early in the lifespan of CoreOS (early 2014 IIRC) I was meeting
with technology leadership at a Fortune 500 customer. I remember the head of
developer services asking all kinds of Docker questions. Finally, he was cut
off by his boss who said:

"Bob¹*, unless we've solely staffed the organization with folks from coder
camps a lot of the folks here should be able to carve out a couple of
namespaces in the kernel. That's not interesting and that's not why we asked
CoreOS to come in today. Let's talk about the actual problems they're trying
to solve."

<3 <3 <3 <3

That being said, it's great that folks continue to dig in to decompose the
tooling and show what's actually happening behind the scenes.

¹Bob was definitely not that guy's name.

EDIT: Added note of context appreciating the work by the author.

------
zelly
I was thinking about something like this for build systems. Everything in
Docker is regular Linux. I get why Docker is so big for its use case as cloud
deployments, but what I actually want from it is such a small piece of it.
Hermetic, reproducible builds that produce the same binary on the same kernel
release. No dependency hell because the dependencies are all part of the same
build. (I know Bazel has a lot of this already.) The Docker solution of
pulling in an entire distro is overkill, and it doesn't even solve the problem
because dependencies are just downloaded from the package manager.

~~~
adgasf
> it doesn't even solve the problem because dependencies are just downloaded
> from the package manager.

The advantage of Docker is that you can verify the container works locally as
part of the build process rather than finding out it is broken due to some
missing dep after a deployment. If you can verify that the image works then
the mechanism for fetching the deps can be as scrappy as you like. Docker
moves the dependency challenge from deployment-time to build-time.

~~~
crdrost
Does container mean something different to y’all than it does to me?

I ask because I read your comment as saying “the advantage of Docker is that
it uses (explanation of what containers are)” and the parent comment as saying
“all I want from Docker is (explanation of what containers are)” and I am
confused why (a) y’all are not just saying “containers” but rather “the part
of docker that packages up my network of scripts so I can think about it like
a statically linked binary” and (b) why you think this is a competitive
advantage over other things you might have instead recommended here (Buildah,
Makisu, BuildKit, img, Bazel, FTL, Ansible Container, Metaparticle... I am
sure there are at least a dozen) to satisfy the parent comment’s needs.

Is there really any container ecosystem which has write-an-image-but-you-
can’t-run-it-locally semantics? How do you finally run that image?

~~~
zelly
Docker is too general, too much of a Swiss army knife for this particular
problem. The problem I am talking about is where a C++ program has all of its
dependencies vendored into the source tree. When you run Make, everything
including the dependencies build at the same time. All you need is a chroot,
namespaces, cgroups, btrfs, squashfs--plain old Linux APIs--to make sure the
compiler has a consistent view of the system. Assuming the compiler and
filesystem are well behaved (e.g., don't insert timestamps), you should be
able to take a consistent sha256sum of the build. And maybe even ZIP it up
like a JAR and pass around a lightweight, source-only file that can compile
and run (without a network connection) on other computers with the same kernel
version.

Again, Bazel is basically this already. But it would be nice to have something
like OP's tool to integrate in other build systems.

I _could_ just make a Dockerfile and say that's my build system. But then I'm
stuck with Docker. The only way to run my program would be through Docker.
Docker doesn't have a monopoly on the idea of a fully-realized chroot.

~~~
crdrost
You might be interested in LXC if you haven't seen it already. It is also a
big tool, but it is smaller than Docker.

------
gauthamzz
Docker also implemented using 27 lines of python. [https://github.com/Zakaria-
Ben/Pocker/blob/master/Pocker.py](https://github.com/Zakaria-
Ben/Pocker/blob/master/Pocker.py)

------
logophobia
Huh, clever use of btrfs volumes, it does make it a little dependent on the
filesystem though. Quite informative overall, probably implements only a
fraction of docker, but it does do most of what you'd typically need.

------
songzme
I am so interested in this, but there are so many things I don't understand.

I wonder.... is there a service (Maybe a chrome extension) that lets you ask
questions on the page you are in? For example, I want to highlight:

`btrfs-progs` and ask... "What is a quick summary about this package?

`ship a new enough version of util-linux` and ask.... "What features in the
new util-linux allows this to work?"

Then maybe someone who also visits this page with more knowledge can answer my
questions.

This tool would augment my learning 10x and I would be a paying customer. Does
something like this exist?

~~~
tmcb
Let me know if that is what you are looking for:
[https://web.hypothes.is/](https://web.hypothes.is/)

As an example, WikiWikiWeb ([http://wiki.c2.com/](http://wiki.c2.com/)) has
integration with it. I've never used it, but it seems quite powerful.

~~~
songzme
Wow thanks! Set this up smoothly and asked the questions I posted above. Will
reach out to friends and start a community. Thank you for the find!

------
lbj
Well, it definitely got a chuckle out of me. Good job!

------
jerome-jh
"You won't believe line 4"

------
yepthatsreality
This was posted after a recent repost of another implementation in ~500 lines
of code. See other HN discussion here:
[https://news.ycombinator.com/item?id=22232705](https://news.ycombinator.com/item?id=22232705)

------
sub7
Containerization makes sense for a tiny, tiny fraction of all products. It's
just been overblown and overused, creating another point of potential failure
for no great benefit at all.

Just chroot the damn thing if you need to and keep it simple.

------
maitredusoi
I am wondering if the same was done in ruby, what it would like like

------
pantulis
Now I only need someone to write Kubernetes in 500 lines of Bash.

------
dang
Discussed at the time:
[https://news.ycombinator.com/item?id=9925896](https://news.ycombinator.com/item?id=9925896)

------
RocketSyntax
`entrypoint` directory is critical feature

------
killbot5000
just wait until you see how easy it is with bocker_compose

------
ponytech
Shouldn't it be mentioned this is from 2015?

~~~
dang
Yes, and now it is. Thanks!

