@@ -404,7 +404,110 @@
404 404 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Docker volume since the IDs “leak” out into the host environment via
405 405 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
file permissions. You may therefore wish them to mean something on both
406 406 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
sides of the container barrier rather than have “499” appear on the host
407 407 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
in “`ls -l`” output.
408 408 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
409 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
410 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ## <a id="light"></a>Lightweight Alternatives to Docker
411 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
412 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Those afflicted with sticker shock at seeing the size of a [Docker
413 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Desktop][DD] installation — 1.65 GB here — might’ve immediately
414 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ “noped” out of the whole concept of containers. The first thing to
415 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ realize is that when it comes to actually serving simple containers like
416 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ the ones shown above is that [Docker Engine][DE] suffices, at about a
417 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ quarter of the size.
418 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
419 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Yet on a small server — say, a $4/month 10 GiB Digital Ocean droplet —
420 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ that’s still a big chunk of your storage budget. It takes 100:1 overhead
421 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ just to run a 4 MiB Fossil server container? Once again, I wouldn’t
422 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ blame you if you noped right on out of here, but if you will be patient,
423 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ you will find that there are ways to run Fossil inside a container even
424 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ on entry-level cloud VPSes. These are well-suited to running Fossil; you
425 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ don’t have to resort to [raw Fossil service](./server/) to succeed,
426 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ leaving the benefits of containerization to those with bigger budgets.
427 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
428 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ For the sake of simple examples in this section, we’ll assume you’re
429 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ integrating Fossil into a larger web site, such as with our [Debian +
430 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ nginx + TLS][DNT] plan. The Fossil server instance listens on a
431 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ high-numbered port, on localhost only, and the front-end web server
432 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ reverse-proxies this out to the public. Containers are a fine addition
433 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ to such a system, isolating those elements of the site, thus greatly
434 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ reducing the chance that they’ll ever be used to break into the host as
435 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ a whole.
436 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
437 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ (If you wanted to be double-safe, you could put the web server into
438 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ another container, restricting it only to reading from the static web
439 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ site directory and connecting across localhost to back-end dynamic
440 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ content servers such as Fossil. That’s way outside the scope of this
441 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ document, but you can find ready advice for that elsewhere. Seeing how
442 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ we do this with Fossil should help you bridge the gap in extending
443 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ this idea to the rest of your site.)
444 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
445 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [DD]: https://www.docker.com/products/docker-desktop/
446 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [DE]: https://docs.docker.com/engine/
447 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [DNT]: ./server/debian/nginx.md
448 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
449 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
450 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
451 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ### <a id="runc" name="containerd"></a>Stripping Docker Engine Down
452 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
453 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ The core of Docker Engine is its [containerd] daemon and the [runc]
454 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ container runner. It’s possible to run our Fossil container using only
455 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ these tools, leaving out all the rest. Those two pieces come to about a
456 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tenth the size of Docker Engine on the system where I tested this.
457 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
458 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ **TODO:** Work out how to do this and document it.
459 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
460 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [containerd]: https://containerd.io/
461 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [runc]: https://github.com/opencontainers/runc
462 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
463 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
464 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ### <a id="podman"></a>Podman
465 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
466 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ The biggest downside of that method is that you don’t have all of the
467 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ userland tools for managing the containers.
468 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
469 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ A lighter-weight alternative to Docker Engine that doesn’t give up so
470 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ much of its administrator affordances is [Podman], initially created by
471 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Red Hat and thus popular on that family of OSes, although it will run on
472 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ any flavor of Linux. On Ubuntu 22.04, it’s about a quarter the size of
473 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Docker Engine.
474 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
475 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Although Podman [bills itself][whatis] as a drop-in replacement for the
476 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ `docker` command and everything that sits behind it, some of the tool’s
477 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ design decisions affect how our Fossil containers run, as compared to
478 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ using Docker. The most important of these is that, by default, Podman
479 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ wants to run your container “rootless,” meaning that it runs as a
480 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ regular user. This is generally better for security, but [we dealt with
481 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ that risk differently above](#chroot) already. Since neither choice is
482 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ unassailably correct in all conditions, we’ll document both options
483 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ here.
484 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
485 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
486 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ #### <a id="podman-rootless"></a>Fossil in a Rootless Podman Container
487 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
488 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ If you build the stock Fossil container under `podman`, it will fail at
489 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ two key steps:
490 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
491 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ 1. The `mknod` calls in the second stage, which create the `/jail/dev`
492 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ nodes. For a rootless container, we want it to use the “real” `/dev`
493 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tree mounted into the container’s root filesystem instead.
494 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
495 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ 2. Anything that depends on the `/jail` directory and the fact that it
496 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ becomes the root once the Fossil server is up and running.
497 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
498 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [The changes to fix this](/file/containers/Dockerfile-nojail.patch)
499 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ aren’t complicated. Simply apply that patch to our stock `Dockerfile`
500 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ and rebuild.
501 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
502 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Do realize that by doing this, if an attacker ever managed to get shell
503 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ access on your container, they’d have a BusyBox installation to play
504 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ around in. That shouldn’t be enough to let them break out of the
505 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ container entirely, but they’ll have powerful tools like `wget`, and
506 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ they’ll be connected to the network the container runs on. Once the bad
507 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ guy is inside the house, he doesn’t necessarily have to go after the
508 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ residents directly to cause problems for them.
509 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
510 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [Podman]: https://podman.io/
511 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ [whatis]: https://podman.io/whatis.html
409 512 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
410 513 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
411 514 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!