Fossil SCM

Documented the runc and crun options for running a container, including the cryptic method for exporting an OCI bundle from Docker, allowing you to use both together: Docker Desktop on your big dev box in the office, then one of the two lightweight runtimes out in the cloud.

wyoung 2022-09-04 04:32 trunk
Commit c9431ef4a3448c3e4528de9e89f9b8a9400a6610613d767a414115071e5ff15e
1 file changed +120 -6
+120 -6
--- www/containers.md
+++ www/containers.md
@@ -444,19 +444,119 @@
444444
445445
[DD]: https://www.docker.com/products/docker-desktop/
446446
[DE]: https://docs.docker.com/engine/
447447
[DNT]: ./server/debian/nginx.md
448448
449
+
450
+### <a id="runc" name="containerd"></a>Stripping Docker Engine Down
451
+
452
+The core of Docker Engine is its [`containerd`][ctrd] daemon and the
453
+[`runc`][runc] container runner. It’s possible to dig into the subtree
454
+managed by `containerd` on the build host and extract what we need to
455
+run our Fossil container elsewhere with `runc`, leaving out all the
456
+rest. `runc` alone is about 18 MiB, and you can do without `containerd`
457
+entirely, if you want.
458
+
459
+The method isn’t complicated, but it *is* cryptic enough to want a shell
460
+script:
461
+
462
+```shell
463
+#!/bin/sh
464
+c=fossil
465
+r=/containers/$c/rootfs
466
+sudo mkdir -p $r
467
+docker container export $c | sudo tar -C $r -xf -
468
+id=$(docker inspect --format="{{.Id}}" $c)
469
+sudo cat /run/containerd/io.containerd.runtime.v2.task/moby/$id/config.json |
470
+ jq '.root.path = "'$r'"' |
471
+ jq '.linux.cgroupsPath = ""' > $r/../config.json
472
+```
473
+
474
+The first two lines set configurables: the name of the Docker container
475
+you’re exporting for use with `runc` and the path where you want its
476
+file system root to live. They can be anything you like.
477
+
478
+The rest is generic, but you’re welcome to freestyle here. For instance,
479
+you could untar the rootfs through SSH in order to transfer the
480
+container to a remote system. Or, you could get really clever: unpack it
481
+in a local temp directory, then `rsync` it to the remote system to avoid
482
+transferring elements of the rootfs that haven’t changed since the last
483
+update.
484
+
485
+We’re using [jq] for two separate purposes:
486
+
487
+1. To change the container configuration for `runc`:
488
+
489
+ * point it where we unpacked the container’s exported rootfs
490
+ * accede to its wish to [manage cgroups by itself][ecg]
491
+
492
+2. To make the Docker-managed machine-readable `config.json` more
493
+ human-readable, in case there are other things you want changed in
494
+ this version of the container. Exposing the `config.json` file like
495
+ this means you don’t have to rebuild the container merely to change
496
+ a value like a mount point, the kernel capability set, and so forth.
497
+
498
+With the container exported like this, you can start it as:
499
+
500
+```
501
+ $ cd /path/to/rootfs
502
+ $ c=any-name-you-like
503
+ $ sudo runc create $c
504
+ $ sudo runc start $c
505
+ $ sudo runc exec $c -t sh -l
506
+ ~ $ ls museum
507
+ repo.fossil
508
+ ~ $ ps -eaf
509
+ PID USER TIME COMMAND
510
+ 1 fossil 0:00 bin/fossil server --create …
511
+ ~ $ exit
512
+ $ sudo runc kill fossil-runc
513
+ $ sudo runc delete fossil-runc
514
+```
515
+
516
+The first command refers to wherever the rootfs ended up on the `runc`
517
+host. If it’s the same as the export host, then this is simply `$r`
518
+from the shell script above. If instead you’re doing something like the
519
+SSH/rsync trickery suggested above, the remote rootfs directory might be
520
+named differently on the `runc` host.
521
+
522
+There’s nothing that says the container name on the build host has to be
523
+the same as that on the runc host, so we’ve defined a separate `c`
524
+variable here to keep the commands short.
525
+
526
+The rest should be straightforward: create and start the container as
527
+root so the `chroot(2)` call inside the container will succeed, then get
528
+into it with a login shell and poke around to prove to ourselves that
529
+everything is working properly. It is. Yay!
530
+
531
+The remaining commands show shutting the container down and destroying
532
+it, simply to show how these commands change relative to using the
533
+Docker Engine commands. It’s “kill,” not “stop,” and it’s “delete,” not
534
+“rm.”
535
+
536
+[ctrd]: https://containerd.io/
537
+[ecg]: https://github.com/opencontainers/runc/pull/3131
538
+[jq]: https://stedolan.github.io/jq/
539
+[runc]: https://github.com/opencontainers/runc
540
+
449541
450542
### <a id="podman"></a>Podman
543
+
544
+Although your humble author claims the `runc` method above is not
545
+complicated, you might be recollecting the carefree commands at the top
546
+of this document, pondering whether you can live without the
547
+abstractions a proper container runtime system provides.
451548
452549
A lighter-weight alternative to Docker Engine that doesn’t give up so
453550
much of its administrator affordances is [Podman], initially created by
454551
Red Hat and thus popular on that family of OSes, although it will run on
455
-any flavor of Linux. On Ubuntu 22.04, it’s about a quarter the size of
456
-Docker Engine. It can even be made to run [on macOS via Homebrew][pmmac]
552
+any flavor of Linux. It can even be made to run [on macOS via Homebrew][pmmac]
457553
or [on Windows via WSL2][pmwin].
554
+
555
+On Ubuntu 22.04, it’s about a quarter the size of Docker Engine. That
556
+isn’t nearly so slim as `runc`, but we may be willing to pay this
557
+overhead to get shorter and fewer commands.
458558
459559
Although Podman [bills itself][whatis] as a drop-in replacement for the
460560
`docker` command and everything that sits behind it, some of the tool’s
461561
design decisions affect how our Fossil containers run, as compared to
462562
using Docker. The most important of these is that, by default, Podman
@@ -464,12 +564,14 @@
464564
regular user. This is generally better for security, but [we dealt with
465565
that risk differently above](#chroot) already. Since neither choice is
466566
unassailably correct in all conditions, we’ll document both options
467567
here.
468568
469
-[pmmac]: https://podman.io/getting-started/installation.html#macos
470
-[pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
569
+[pmmac]: https://podman.io/getting-started/installation.html#macos
570
+[pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
571
+[Podman]: https://podman.io/
572
+[whatis]: https://podman.io/whatis.html
471573
472574
473575
#### <a id="podman-rootless"></a>Fossil in a Rootless Podman Container
474576
475577
If you build the stock Fossil container under `podman`, it will fail at
@@ -512,9 +614,21 @@
512614
container entirely, but they’ll have powerful tools like `wget`, and
513615
they’ll be connected to the network the container runs on. Once the bad
514616
guy is inside the house, he doesn’t necessarily have to go after the
515617
residents directly to cause problems for them.
516618
517
-[Podman]: https://podman.io/
518
-[whatis]: https://podman.io/whatis.html
619
+
620
+#### <a id="crun"></a>`crun`
621
+
622
+In the same way that [Docker Engine is based on `runc`](#runc), Podman’s
623
+engine is based on [`crun`][crun], a lighter-weight alternative to
624
+`runc`. It’s only 1.4 MiB on the system I tested it on, yet it will run
625
+the same container bundles as in my `runc` examples above. This makes it
626
+a great option for tiny remote hosts. Above, we saved more than that by
627
+compressing the container’s Fossil executable with UPX!
628
+
629
+This suggests a method around the problem of rootless Podman containers:
630
+`sudo crun`, following the examples above.
631
+
632
+[crun]: https://github.com/containers/crun
519633
520634
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
521635
--- www/containers.md
+++ www/containers.md
@@ -444,19 +444,119 @@
444
445 [DD]: https://www.docker.com/products/docker-desktop/
446 [DE]: https://docs.docker.com/engine/
447 [DNT]: ./server/debian/nginx.md
448
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
450 ### <a id="podman"></a>Podman
 
 
 
 
 
451
452 A lighter-weight alternative to Docker Engine that doesn’t give up so
453 much of its administrator affordances is [Podman], initially created by
454 Red Hat and thus popular on that family of OSes, although it will run on
455 any flavor of Linux. On Ubuntu 22.04, it’s about a quarter the size of
456 Docker Engine. It can even be made to run [on macOS via Homebrew][pmmac]
457 or [on Windows via WSL2][pmwin].
 
 
 
 
458
459 Although Podman [bills itself][whatis] as a drop-in replacement for the
460 `docker` command and everything that sits behind it, some of the tool’s
461 design decisions affect how our Fossil containers run, as compared to
462 using Docker. The most important of these is that, by default, Podman
@@ -464,12 +564,14 @@
464 regular user. This is generally better for security, but [we dealt with
465 that risk differently above](#chroot) already. Since neither choice is
466 unassailably correct in all conditions, we’ll document both options
467 here.
468
469 [pmmac]: https://podman.io/getting-started/installation.html#macos
470 [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
 
 
471
472
473 #### <a id="podman-rootless"></a>Fossil in a Rootless Podman Container
474
475 If you build the stock Fossil container under `podman`, it will fail at
@@ -512,9 +614,21 @@
512 container entirely, but they’ll have powerful tools like `wget`, and
513 they’ll be connected to the network the container runs on. Once the bad
514 guy is inside the house, he doesn’t necessarily have to go after the
515 residents directly to cause problems for them.
516
517 [Podman]: https://podman.io/
518 [whatis]: https://podman.io/whatis.html
 
 
 
 
 
 
 
 
 
 
 
 
519
520 <div style="height:50em" id="this-space-intentionally-left-blank"></div>
521
--- www/containers.md
+++ www/containers.md
@@ -444,19 +444,119 @@
444
445 [DD]: https://www.docker.com/products/docker-desktop/
446 [DE]: https://docs.docker.com/engine/
447 [DNT]: ./server/debian/nginx.md
448
449
450 ### <a id="runc" name="containerd"></a>Stripping Docker Engine Down
451
452 The core of Docker Engine is its [`containerd`][ctrd] daemon and the
453 [`runc`][runc] container runner. It’s possible to dig into the subtree
454 managed by `containerd` on the build host and extract what we need to
455 run our Fossil container elsewhere with `runc`, leaving out all the
456 rest. `runc` alone is about 18 MiB, and you can do without `containerd`
457 entirely, if you want.
458
459 The method isn’t complicated, but it *is* cryptic enough to want a shell
460 script:
461
462 ```shell
463 #!/bin/sh
464 c=fossil
465 r=/containers/$c/rootfs
466 sudo mkdir -p $r
467 docker container export $c | sudo tar -C $r -xf -
468 id=$(docker inspect --format="{{.Id}}" $c)
469 sudo cat /run/containerd/io.containerd.runtime.v2.task/moby/$id/config.json |
470 jq '.root.path = "'$r'"' |
471 jq '.linux.cgroupsPath = ""' > $r/../config.json
472 ```
473
474 The first two lines set configurables: the name of the Docker container
475 you’re exporting for use with `runc` and the path where you want its
476 file system root to live. They can be anything you like.
477
478 The rest is generic, but you’re welcome to freestyle here. For instance,
479 you could untar the rootfs through SSH in order to transfer the
480 container to a remote system. Or, you could get really clever: unpack it
481 in a local temp directory, then `rsync` it to the remote system to avoid
482 transferring elements of the rootfs that haven’t changed since the last
483 update.
484
485 We’re using [jq] for two separate purposes:
486
487 1. To change the container configuration for `runc`:
488
489 * point it where we unpacked the container’s exported rootfs
490 * accede to its wish to [manage cgroups by itself][ecg]
491
492 2. To make the Docker-managed machine-readable `config.json` more
493 human-readable, in case there are other things you want changed in
494 this version of the container. Exposing the `config.json` file like
495 this means you don’t have to rebuild the container merely to change
496 a value like a mount point, the kernel capability set, and so forth.
497
498 With the container exported like this, you can start it as:
499
500 ```
501 $ cd /path/to/rootfs
502 $ c=any-name-you-like
503 $ sudo runc create $c
504 $ sudo runc start $c
505 $ sudo runc exec $c -t sh -l
506 ~ $ ls museum
507 repo.fossil
508 ~ $ ps -eaf
509 PID USER TIME COMMAND
510 1 fossil 0:00 bin/fossil server --create …
511 ~ $ exit
512 $ sudo runc kill fossil-runc
513 $ sudo runc delete fossil-runc
514 ```
515
516 The first command refers to wherever the rootfs ended up on the `runc`
517 host. If it’s the same as the export host, then this is simply `$r`
518 from the shell script above. If instead you’re doing something like the
519 SSH/rsync trickery suggested above, the remote rootfs directory might be
520 named differently on the `runc` host.
521
522 There’s nothing that says the container name on the build host has to be
523 the same as that on the runc host, so we’ve defined a separate `c`
524 variable here to keep the commands short.
525
526 The rest should be straightforward: create and start the container as
527 root so the `chroot(2)` call inside the container will succeed, then get
528 into it with a login shell and poke around to prove to ourselves that
529 everything is working properly. It is. Yay!
530
531 The remaining commands show shutting the container down and destroying
532 it, simply to show how these commands change relative to using the
533 Docker Engine commands. It’s “kill,” not “stop,” and it’s “delete,” not
534 “rm.”
535
536 [ctrd]: https://containerd.io/
537 [ecg]: https://github.com/opencontainers/runc/pull/3131
538 [jq]: https://stedolan.github.io/jq/
539 [runc]: https://github.com/opencontainers/runc
540
541
542 ### <a id="podman"></a>Podman
543
544 Although your humble author claims the `runc` method above is not
545 complicated, you might be recollecting the carefree commands at the top
546 of this document, pondering whether you can live without the
547 abstractions a proper container runtime system provides.
548
549 A lighter-weight alternative to Docker Engine that doesn’t give up so
550 much of its administrator affordances is [Podman], initially created by
551 Red Hat and thus popular on that family of OSes, although it will run on
552 any flavor of Linux. It can even be made to run [on macOS via Homebrew][pmmac]
 
553 or [on Windows via WSL2][pmwin].
554
555 On Ubuntu 22.04, it’s about a quarter the size of Docker Engine. That
556 isn’t nearly so slim as `runc`, but we may be willing to pay this
557 overhead to get shorter and fewer commands.
558
559 Although Podman [bills itself][whatis] as a drop-in replacement for the
560 `docker` command and everything that sits behind it, some of the tool’s
561 design decisions affect how our Fossil containers run, as compared to
562 using Docker. The most important of these is that, by default, Podman
@@ -464,12 +564,14 @@
564 regular user. This is generally better for security, but [we dealt with
565 that risk differently above](#chroot) already. Since neither choice is
566 unassailably correct in all conditions, we’ll document both options
567 here.
568
569 [pmmac]: https://podman.io/getting-started/installation.html#macos
570 [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
571 [Podman]: https://podman.io/
572 [whatis]: https://podman.io/whatis.html
573
574
575 #### <a id="podman-rootless"></a>Fossil in a Rootless Podman Container
576
577 If you build the stock Fossil container under `podman`, it will fail at
@@ -512,9 +614,21 @@
614 container entirely, but they’ll have powerful tools like `wget`, and
615 they’ll be connected to the network the container runs on. Once the bad
616 guy is inside the house, he doesn’t necessarily have to go after the
617 residents directly to cause problems for them.
618
619
620 #### <a id="crun"></a>`crun`
621
622 In the same way that [Docker Engine is based on `runc`](#runc), Podman’s
623 engine is based on [`crun`][crun], a lighter-weight alternative to
624 `runc`. It’s only 1.4 MiB on the system I tested it on, yet it will run
625 the same container bundles as in my `runc` examples above. This makes it
626 a great option for tiny remote hosts. Above, we saved more than that by
627 compressing the container’s Fossil executable with UPX!
628
629 This suggests a method around the problem of rootless Podman containers:
630 `sudo crun`, following the examples above.
631
632 [crun]: https://github.com/containers/crun
633
634 <div style="height:50em" id="this-space-intentionally-left-blank"></div>
635

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button