Fossil

Diff
Login

Diff

Differences From Artifact [9ff2c78d5e]:

To Artifact [3ab584aafa]:


466
467
468
469
470
471
472

473
474
475
476
477
478
479
480
481
482
483
484
485

486
487

488
489

490
491

492
493
494
495
496
497
498
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485

486
487

488
489

490
491

492
493
494
495
496
497
498
499







+












-
+

-
+

-
+

-
+







c=fossil
b=$HOME/containers/$c
r=$b/rootfs
m=/run/containerd/io.containerd.runtime.v2.task/moby

if [ -d "$t" ] && mkdir -p $r
then
    docker container start  $c
    docker container export $c | sudo tar -C $r -xf -
    id=$(docker inspect --format="{{.Id}}" $c)
    sudo cat $m/$id/config.json |
        jq '.root.path = "'$r'"' |
        jq '.linux.cgroupsPath = ""' > $b/config.json
fi
```

----

The first several lines list configurables:

*   **b**: the path of the exported container, called the “bundle” in OCI
*   **`b`**: the path of the exported container, called the “bundle” in OCI
    jargon
*   **c**: the name of the Docker container you’re bundling up for use
*   **`c`**: the name of the Docker container you’re bundling up for use
    with `runc`
*   **m**: the [moby] directory, both because it’s long and because it’s
*   **`m`**: the [moby] directory, both because it’s long and because it’s
    been known to change from one version of Docker to the next
*   **r**: the path of the directory containing the bundle’s root file
*   **`r`**: the path of the directory containing the bundle’s root file
    system.

That last doesn’t have to be called `rootfs/`, and it doesn’t have to
live in the same directory as `config.json`, but it is conventional.
Because some OCI tools use those names as defaults, it’s best to follow
suit.

508
509
510
511
512
513
514






515
516
517
518
519
520
521
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528







+
+
+
+
+
+








2.  To make the Docker-managed machine-readable `config.json` more
    human-readable, in case there are other things you want changed in
    this version of the container.  Exposing the `config.json` file like
    this means you don’t have to rebuild the container merely to change
    a value like a mount point, the kernel capability set, and so forth.

<a id="why-sudo"></a>
We have to do this transformation of `config.json` as the local root
user because it isn’t readable by your normal user. Additionally, that
input file is only available while the container is started, which is
why we ensure that before exporting the container’s rootfs.

With the container exported like this, you can start it as:

```
  $ cd /path/to/bundle
  $ c=any-name-you-like
  $ sudo runc create $c
  $ sudo runc start  $c
542
543
544
545
546
547
548
549
550


551
552
553
554

555
556
557
558
559

560
561

562
563
564
565
566

567

568

569
570
571

572


573
574





575
576
577
578
579
580
581
582
583
584
585































586
587
588
589
590
591
592
549
550
551
552
553
554
555


556
557




558
559
560
561
562

563
564
565
566
567
568

569

570
571
572

573
574
575

576
577
578
579


580
581
582
583
584
585
586
587
588
589






590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627







-
-
+
+
-
-
-
-
+




-
+


+


-

-
+

+
-
+


-
+

+
+
-
-
+
+
+
+
+





-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







everything is working properly. It is. Yay!

The remaining commands show shutting the container down and destroying
it, simply to show how these commands change relative to using the
Docker Engine commands. It’s “kill,” not “stop,” and it’s “delete,” not
“rm.”

Beware that if you’re doing this on a remote host, your bundle export
directory on the build host might not be the same as where it ended up
If you want the bundle to run on a remote host, the local and remote
bundle directories likely will not match, as the shell script above
on the remote host. If so, the shell script above will create a broken
bundle because it’s assuming the `mkdir` command should go to the same
directory as the “`rootfs`” value it set in the `config.json` value.
This is a more realistic shell script for that case:
assumes.  This is a more realistic shell script for that case:

----

```shell
#!/bin/sh
#!/bin/bash -ex
c=fossil
b=/var/lib/machines/$c
h=my-host.example.com
m=/run/containerd/io.containerd.runtime.v2.task/moby
t=$(mktemp -d /tmp/$c-bundle.XXXXXX)
r=$t/rootfs

if [ -d "$t" ] && mkdir -p $r
if [ -d "$t" ]
then
    docker container start  $c
    docker container export $c | sudo tar -C $r -xf -
    docker container export $c > $t/rootfs.tar
    id=$(docker inspect --format="{{.Id}}" $c)
    sudo cat $m/$id/config.json |
        jq '.root.path = "'$r'"' |
        jq '.root.path = "'$b/rootfs'"' |
        jq '.linux.cgroupsPath = ""' > $t/config.json
    scp -r $t $h:tmp
        ssh -t $h "{
    rsync -av $t/* remotehost:$b
    sudo rm -rf $t
                mv ./$t/config.json $b &&
                sudo tar -C $b/rootfs -xf ./$t/rootfs.tar &&
                rm -r ./$t
        }"
    rm -r $t
fi
```

----

We’ve introduced the “`t`” variable, a temporary directory we populate
locally, then `rsync` across to the remote machine, updating a
*different* bundle directory, `$b`. We’re using the convention for
systemd based machines here, which will play into the [`nspawn`][sdnsp]
alternative below. Even if you aren’t using `nspawn`, it’s a reasonable
place to put containers under the [Linux FHS rules][LFHS].
We’ve introduced two new variables:

*   **`h`**: the remote host name
*   **`t`**: a temporary bundle directory we populate locally, then
    `scp` to the remote machine, where it’s unpacked

We dropped the **`r`** variable because now we have two different
“rootfs” types: the tarball and the unpacked version of that tarball.
To avoid confusing ourselves between these cases, we’ve replaced uses of
`$r` with explicit paths.

You need to be aware that this script uses `sudo` for two different purposes:

1. To read the local `config.json` file out of the `containerd` managed
   directory. ([Details above](#why-sudo).)

2. To unpack the bundle onto the remote machine. If you try to get
   clever and unpack it locally, then `rsync` it to the remote host to
   avoid re-copying files that haven’t changed since the last update,
   you’ll find that it fails when it tries to copy device nodes, to
   create files owned only by the remote root user, and so forth. If the
   container bundle is small, it’s simpler to re-copy and unpack it
   fresh each time.

I point that out because it might ask for your password twice: once for
the local sudo command, and once for the remote.

The default for the **`b`** variable is the convention for systemd based
machines, which will play into the [`nspawn`][sdnsp] alternative below.
Even if you aren’t using `nspawn`, it’s a reasonable place to put
containers under the [Linux FHS rules][LFHS].

[ctrd]:  https://containerd.io/
[ecg]:   https://github.com/opencontainers/runc/pull/3131
[LFHS]:  https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[jq]:    https://stedolan.github.io/jq/
[moby]:  https://github.com/moby/moby
[sdnsp]: #nspawn