diff --git a/doc/container.md b/doc/container.md
index 29ac7451..f29e81aa 100644
--- a/doc/container.md
+++ b/doc/container.md
@@ -2,302 +2,372 @@ Containers in Infix
===================
* [Introduction](#introduction)
-* [Docker Containers with Podman](#docker-containers-with-podman)
- * [Multiple Networks](#multiple-networks)
- * [Hybrid Mode](#hybrid-mode)
-* [Enabling Container Support](#enabling-container-support)
-* [Debugging Containers](#debugging-containers)
+* [Caution](#caution)
+* [Getting Started](#getting-started)
+ * [Examples](#examples)
+* [Networking and Containers](#networking-and-containers)
+ * [CNI Bridge](#cni-bridge)
+ * [CNI Host](#cni-host)
+ * [Host Networking](#host-networking)
+* [Example Containers](#example-containers)
+ * [System Container](#system-container)
+ * [Application Container: nftables](#application-container--nftables)
+ * [Application Container: ntpd](#application-container--ntpd)
+* [Upgrading a Container Image](#upgradeing-a-container-image)
Introduction
------------
-Default builds of Infix do not enable any container support. See below
-section, [Enabling Container Support](#enabling-container-support), for
-details on how to enable it using Podman.
+Infix comes with native support for Docker containers using [podman][].
+The [YANG model][1] describes the current level of support, complete
+enough to run both system and application containers.
-Networking in containers is provided by both Infix and the Container
-Network Interface ([CNI](https://www.cni.dev/)) that Podman supports.
+Key design features, like using Linux switchdev, allow users to assign
+switch ports directly to containers, not just bridged VETH pairs, this
+is a rare and in many cases *unique* feature of Infix.
-> A convenience alias `docker=podman` is available in Infix, remember,
-> not all features or syntax of docker is available in podman.
+All network specific settings are done using the IETF interfaces YANG
+model, with augments for containers to ensure smooth integration with
+the Container Network Interface ([CNI][]) that podman supports.
-Docker Containers with Podman
------------------------------
+Caution
+-------
-We assume you've booted into Infix and start with a familiar example.
-This downloads the `hello-world` example container image and runs it:
+A word of warning. Containers run on your system in privileged mode, as
+`root`. Even though they are fenced with Linux namespaces, and resource
+limited using Linux cgroups, which scope container applications from
+seeing and accessing the complete system. There is no guarantee that an
+application cannot ever break out of this confinement.
- podman run -it --rm docker://hello-world
+ - If the system is compromised, containers can be used to easily
+ install malicious software in your system and over the network
+ - Your system is as secure as anything you run in the container
+ - If you run containers, there is no security guarantee of any kind
+ - Running 3rd party container images on your system could open a
+ security hole/attack vector/attack surface
+ - An expert with knowledge how to build exploits will be able to
+ jailbreak/elevate to root
-We can also set up a port forward to a little web server:
+This being said, a system suspected of being compromised can always be
+restored to a safe state with a factory reset. Provided, of course,
+that it has secure boot enabled.
- podman run -d --rm -p 80:80 docker://nginx:alpine
-In detached (`-d`) state you can check the status using `podman ps` and
-try to connect to the web server:
+Getting Started
+---------------
- curl http://localhost
+In the CLI, containers can be run in one of two ways:
+
+ 1. `container run IMAGE [COMMAND]`, and
+ 2. enter `configure` context, then `edit container NAME`
+
+The first is useful mostly for testing, or running single commands in an
+image. It is a wrapper for `podman run -it --rm ...`, while the latter
+is a wrapper and adaptation of `podman create ...`.
+
+The second create a container with a semi-persistent writable layer that
+survives container restarts and host system restarts. However, if you
+change the container configuration or upgrade the image (see below), the
+container will be recreated and the writable layer is lost. This is why
+it is recommended to set up a named volume for directories, or use file
+mounts, in your container you want truly persistent content.
+
+In fact, in many cases the best way is to create a `read-only` container
+and use file mounts and volumes only for the critical parts. Podman
+ensures (using tmpfs) `read-only` containers still have writable
+directories for certain critical file system paths: `/dev`, `/dev/shm`,
+`/run`, `/tmp`, and `/var/tmp`. Meaning, what you most often need is
+writable volumes for `/var/lib` and `/etc`, or only file mounts for a
+few files in `/etc`. The actual needs depend on the container image and
+application to run.
+
+> **Note:** when running containers from public registries, double-check
+> that they support the CPU architecture of your host system. Remember,
+> unlike virtualization, containers reuse the host's CPU and kernel.
+
+
+### Examples
+
+Classic Hello World:
+
+ admin@example-c0-ff-ee:/> container run docker://hello-world
+
+Persistent web server using nginx, sharing the host's network:
+
+ admin@example-c0-ff-ee:/> configure
+ admin@example-c0-ff-ee:/config> edit container web
+ admin@example-c0-ff-ee:/config/container/web> set image docker://nginx:alpine
+ admin@example-c0-ff-ee:/config/container/web> set publish 80:80
+ admin@example-c0-ff-ee:/config/container/web> set host-network
+ admin@example-c0-ff-ee:/config/container/web> leave
+ admin@example-c0-ff-ee:/> show container
+
+Exit to the shell and verify the service with curl, or try to attach
+to your device's IP address using your browser:
+
+ admin@example-c0-ff-ee:~$ curl http://localhost
or connect to port 80 of your running Infix system with a browser. See
-the following sections for how to add more interfaces and start/stop the
-container at boot/reboot.
-
-> To add your own content to web server, place the HTML files in, e.g.,
-> `/cfg/www/*.html` and add `-v /cfg/www:/usr/share/nginx/html:ro` to
-> the command line (above).
+the following sections for how to add more interfaces and manage your
+container at runtime.
-### Multiple Networks
+Networking and Containers
+-------------------------
-It is also possible to start a container with multiple networks. The
-approach shown here uses CNI profiles, which means the interfaces names
-inside the container will always be: `eth0`, `eth1`, etc.
+By default, unlike other systems, persistent[^1] containers have no
+networking enabled. All network access has to be set up explicitly.
+Currently two types of of [CNI][] networks are supported:
-A common setup is to use a VETH pair, with one end in the container and
-the other end routed, or bridged, to the rest of the world. The Infix
-[CLI Guide](cli/introduction.md) provides examples of both. In either
-case you need to create a matching CNI profile for one end of the VETH
-pair before starting the container, here we use two network profiles,
-the default podman bridge and the VETH profile:
+ - `cni-host`: one end of a VETH pair, or a physical Ethernet port
+ - `cni-bridge`: an IP masquerading bridge
- cni create host net1 veth0a 192.168.0.42/24
- podman run -d --rm --net=podman,net1 --entrypoint "/linuxrc" \
- --privileged docker://troglobit/buildroot:latest
-The first profile (`podman`) is a the default bridged profile. When a
-container is started with that (default behavior), podman dynamically
-creates a VETH pair which has one end attached as a bridge port in the
-`cni-podman0` bridge managed by podman, and the other end is brought up
-as `eth0` inside the container.
+### CNI Bridge
-The second profile is the one we created, it uses the `host-device`
-profile and does not create anything, it simply lifts the peer end of
-the pair into the container as `eth1`. This CNI profile can also be
-used to hand over control of physical ports to a container.
+All interface configuration is done in configure context. Let's start
+by creating an IP masquerading bridge, a common default for containers:
-> **Note:** here we start the container in `--privileged` mode. This
-> allows the container guest unfiltered access to the host system and it
-> might not be what you want for a production system. For that at least
-> SECCOMP is recommended, which is out of scope for this tutorial.
+ admin@example-c0-ff-ee:/> configure
+ admin@example-c0-ff-ee:/config> edit interface docker0
+ admin@example-c0-ff-ee:/config/interface/docker0/> set type bridge
+ admin@example-c0-ff-ee:/config/interface/docker0/> set container-network type cni-bridge
+ admin@example-c0-ff-ee:/config/interface/docker0/> leave
-### Real Example
+We have to declare the interface type, and then also declare it as a
+container network, ensuring the interface cannot be used by the system
+for any other purpose. E.g., a `cni-host` interface is supposed to be
+used by a container, by declaring it as such we can guarantee that it
+would never accidentally be added as a bridge or lag port. Hence, to
+move an interface currently set as a `bridge-port` it must be removed
+from the bridge before being given to a container.
-To be able to preserve state in containers between reboots we need a
-writable layer, this is done with `podman create`, after which we can
-use `podman start`. We build on the previous example:
+The default subnet for a `cni-bridge` is 172.17.0.0/16, the bridge will
+take the `.1` address and hand out the rest of the range to containers
+in a round-robin like fashion. A container with this `network` get an
+automatically created VETH pair connection to the bridge and a lot of
+other networking parameters (DNS, default route) are set up.
- cni create host net1 veth0a 192.168.0.42/24
- podman create --name system --conmon-pidfile=/run/pod:system.pid \
- --restart=no --systemd=false --tz=local --privileged \
- --net=podman,net1 --entrypoint "/linuxrc" -p 222:22 \
- docker://troglobit/buildroot:latest
+Some of the defaults of a `cni-bridge` can be changed, e.g., instead of
+`set container-network type cni-bridge`, above, do:
-Here we map the host port 222 to the SSH port of the container, but one
-can just as easily map the host's port 22 (SSH). Just make sure to
-first disable the host's SSH service.
+ admin@example-c0-ff-ee:/config/interface/docker0/> edit container-network
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/> set type cni-bridge
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/> edit subnet 192.168.0.0/16
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/subnet/192.168.0.0/16/> set gateway 192.168.255.254
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/subnet/192.168.0.0/16/> end
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/> edit route 10.0.10.0/24
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/route/10.0.10.0/24/> set gateway 192.168.10.254
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/route/10.0.10.0/24/> end
+ admin@example-c0-ff-ee:/config/interface/docker0/container-network/> end
+ admin@example-c0-ff-ee:/config/interface/docker0/> leave
-> **Note:** the new options used here are required for enabling
-> monitoring and automate start/stop of containers at boot/reboot.
+Other network settings, like DNS and domain, use built-in defaults in
+CNI, but can be overridden from each container. Other common settings
+per container is the IP address and name of the network interface inside
+the container. The default, after each stop/start cycle, or reboot of
+the host, is to name the interfaces `eth0`, `eth1`, in the order they
+are given in the `network` list, and to give the container the next
+address in a `cni-bridge`. Below an example of a system container calls
+`set network docker0`, here we show how to set options for that network:
-This creates the named container `system` which we can now start:
-
- podman start system
-
-and stop:
-
- podman stop system
-
-For this particular image[^1] we need to modify its defaults a bit,
-because it is set up to run a DHCP client on the first Ethernet
-interface, which in our case is the `podman` default CNI bridge. In
-fact, we don't want the container to set up any networking since that is
-handled by Infix and podman.
-
- root@infix-12-34-56:~$ podman start system
- root@infix-12-34-56:~$ podman exec -it system sh
- / # rm -rf /etc/network/interfaces
- / # exit
- root@infix-12-34-56:~$ podman stop system
-
-The change is now saved in the writable layer and the next time the
-container is started it will look like this:
-
- root@infix-12-34-56:~$ podman start system
- root@infix-12-34-56:~$ podman exec -it system sh
- / # ifconfig
- eth0 Link encap:Ethernet HWaddr A2:32:4C:2B:5E:51
- inet addr:10.88.0.11 Bcast:10.88.255.255 Mask:255.255.0.0
- inet6 addr: fe80::a032:4cff:fe2b:5e51/64 Scope:Link
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
- RX packets:204 errors:0 dropped:107 overruns:0 frame:0
- TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
- collisions:0 txqueuelen:0
- RX bytes:48240 (47.1 KiB) TX bytes:1102 (1.0 KiB)
+ admin@example-c0-ff-ee:/config/container/ntpd/> edit network docker0
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/>
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/> set option
+ Options for CNI bridges.
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/> help option
+ NAME
+ option
- eth1 Link encap:Ethernet HWaddr 56:B5:4E:D1:9C:E5
- inet addr:192.168.0.42 Bcast:192.168.0.255 Mask:255.255.255.0
- inet6 addr: fe80::54b5:4eff:fed1:9ce5/64 Scope:Link
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
- RX packets:274 errors:0 dropped:213 overruns:0 frame:0
- TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
- collisions:0 txqueuelen:1000
- RX bytes:60926 (59.4 KiB) TX bytes:1377 (1.3 KiB)
-
-Automating start/stop at boot/reboot is documented in the next section.
-
-[^1]: A common task one has to do for many other standard images, e.g.,
- Alpine Linux and BusyBox available on Docker Hub.
-
-### Hybrid Mode
-
-Since container setup and configuration is not modeled in YANG yet, we
-use the Infix *Hybrid mode*, described in [Infix Variants](variant.md).
-
-To start containers in *Hybrid Mode*, provided the images have been
-downloaded with `podman pull docker://troglobit/buildroot:latest` and
-a container created (above):
-
-```
-root@infix:/cfg/start.d$ cat <20-enable-container.sh
-#!/bin/sh
-# Remember to create the veth0a <--> vet0b pair in the CLI first!
-cni create host net1 veth0a 192.168.0.42/24
-cat < /etc/finit.d/available/pod:system.conf
-service name:pod :system pid:!/run/pod:system.pid podman --syslog start system -- System container
-EOF
-initctl enable pod:system
-exit 0
-HERE
-root@infix:/cfg/start.d$ chmod +x 20-enable-container.sh
-```
-
-Reboot to activate the changes. To activate the changes without
-rebooting, run the script and call `initctl reload`.
-
-> **Note:** the `/etc` directory is a `tmpfs` ramdisk and contents will
-> be lost on reboot, so to retain custom CNI profiles after reboot you
-> need to either save them and restore in the script above, or recreate
-> them on every boot.
+ DESCRIPTION
+ Options for CNI bridges.
+ Example: ip=1.2.3.4 to request a specific IP, both IPv4 and IPv6.
+ interface_name=foo0 name to set interface name inside container.
+
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/> set option ip=172.17.0.2
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/> set option interface_name=wan
+ admin@example-c0-ff-ee:/config/container/ntpd/network/docker0/> leave
-Enabling Container Support
---------------------------
+### CNI Host
-Container support is not enabled by default because it is not a common
-customer feature, it also prolongs build times a lot due to bringing in
-a build-time dependency on Go.
+Another common use-case is to move a network interface into the network
+namespace of a container. Which the CNI bridge network does behind the
+scenes with one end of the automatically created VETH pair. This works
+with regular Ethernet interfaces as well, but here we will use a VETH
+pair as an example along with a regular bridge (where other Ethernet
+interfaces may live as well).
-However, customer specific builds may have it, and you can also roll
-your own based on any of the available `defconfigs`. For example:
+ admin@example-c0-ff-ee:/config/> edit interface veth0
+ admin@example-c0-ff-ee:/config/interface/veth0a/> set veth peer ntpd
+ admin@example-c0-ff-ee:/config/interface/veth0a/> set ipv4 address 192.168.0.1 prefix-length 24
+ admin@example-c0-ff-ee:/config/interface/veth0a/> end
+ admin@example-c0-ff-ee:/config/> edit interface ntpd
+ admin@example-c0-ff-ee:/config/interface/ntpd/> set ipv4 address 192.168.0.2 prefix-length 24
+ admin@example-c0-ff-ee:/config/interface/ntpd/> set container-network
+ admin@example-c0-ff-ee:/config/interface/ntpd/container-network/> set
- cd infix/
- make x86_64_defconfig
-
-Run menuconfig, search for `podman` using `/`, enable it and build:
-
- make menuconfig
- ...
- make
-
-Enabling [podman][] select `crun`, `conmon`, and all other dependencies.
-The build will take a while, but eventually you can:
-
- make run
+This is a routed setup, where we reserve 192.168.0.0/24 for the network
+between the host and the `ntpd` container. A perhaps more common case
+is to put `veth0` as a port in a bridge with other physical ports. The
+point of the routed case is that port forwarding from the container in
+this case is limited to a single interface, not *all interfaces* as is
+the default in the CNI Bridge setup.
-Debugging Containers
---------------------
+### Host Networking
-If the host system is not powered down or rebooted properly, containers
-may not start up as they should on the following boot. Below is a very
-common problem and solution shown.
+The third use-case is host networking, this is where a container share
+the network namespace of the host. An example here could be a nftables
+or ntpd container -- single applications which add core functionality to
+the host operating system.
-```
-root@infix-12-34-56:~$ podman ps
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-root@infix-12-34-56:~$ grep nginx /var/log/syslog
-Jun 25 10:15:48 infix-12-34-56 finit[1]: Service pod:nginx[2376] died, restarting in 5000 msec (10/10)
-Jun 25 10:15:48 infix-12-34-56 finit[1]: Starting pod:nginx[2408]
-Jun 25 10:15:53 infix-12-34-56 finit[1]: Service pod:nginx keeps crashing, not restarting.
-```
+The host networking setup cannot be combined with any other network.
-If this the system is isolated from remote network access, start by
-verifying the image is downloaded:
-
-```
-root@infix-12-34-56:/cfg/start.d$ podman images
-REPOSITORY TAG IMAGE ID CREATED SIZE
-docker.io/library/nginx alpine 4937520ae206 10 days ago 43.2 MB
-docker.io/troglobit/buildroot latest 68faf6b20f1a 6 weeks ago 41.4 MB
-```
-
-OK, let's see what the `podman-service` step (above) created:
-
-```
-root@infix-12-34-56:/cfg/start.d$ initctl show pod-nginx.conf
-service name:pod :nginx podman run --name nginx --rm -p 80:80 nginx:alpine -- Nginx container
-```
-
-Try starting the container manually. Remember to add the `-d` flag to
-emulate detached/background operation:
-
-```
-root@infix-12-34-56:/cfg/start.d$ podman run --name nginx --rm -d -p 8080:80 nginx:alpine
-Error: creating container storage: the container name "nginx" is already in use by 9c73bd8d505b1585d241595bfadede361b87f6c1be9a5656253b5a4d73da57e0. You have to remove that container to be able to reuse that name: that name is already in use
-```
-
-Aha, a lingering image with the same name! Where is it?
-
-```
-root@infix-12-34-56:/cfg/start.d$ podman ps --all
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-f3386ae9517f docker.io/troglobit/buildroot:latest About an hour ago Exited (0) About an hour ago ecstatic_panini
-bf0c6178ea26 docker.io/troglobit/buildroot:latest About an hour ago Exited (0) About an hour ago determined_brown
-385155f479c0 docker.io/troglobit/buildroot:latest About an hour ago Exited (0) About an hour ago vibrant_engelbart
-99a1b3319d9e docker.io/troglobit/buildroot:latest About an hour ago Exited (0) About an hour ago dreamy_tesla
-9c73bd8d505b docker.io/library/nginx:alpine nginx -g daemon o... 11 minutes ago Created 0.0.0.0:80->80/tcp nginx
-8a5290504ebc docker.io/troglobit/buildroot:latest 10 minutes ago Created mystifying_liskov
-```
-
-Oh, we have two lingering containers that were created but did not stop
-correctly. Let's remove them:
-
-```
-root@infix-12-34-56:/cfg/start.d$ docker rm -f 9c73bd8d505b
-9c73bd8d505b
-root@infix-12-34-56:/cfg/start.d$ docker rm -f 8a5290504ebc
-8a5290504ebc
-```
-
-Now we can manually restart the (supervised) container:
-
-```
-root@infix-12-34-56:/cfg/start.d$ initctl restart pod:nginx
-root@infix-12-34-56:/cfg/start.d$ initctl status pod:nginx
- Status : running
- Identity : pod:nginx
-Description : Nginx container
- Origin : /etc/finit.d/enabled/pod-nginx.conf
- Command : podman run --name nginx --rm -p 80:80 nginx:alpine
- PID file : none
- PID : 2669
- User : root
- Group : root
- Uptime : 15 sec
- Restarts : 11 (0/10)
- Runlevels : [---234-----]
- Memory : 63.8M
- CGroup : /system/pod-nginx cpu 0 [100, max] mem [0, max]
- ├─ 2669 podman run --name nginx --rm -p 80:80 nginx:alpine
- └─ 2816 conmon --api-version 1 -c 44d24aa7e98b67ff811596984462b902af3b09a04b4f9bef86e11d246b8cc2ff -u 44d24aa7e98b67ff8
-
-Jun 25 10:15:48 infix-12-34-56 finit[1]: Service pod:nginx[2376] died, restarting in 5000 msec (10/10)
-Jun 25 10:15:48 infix-12-34-56 finit[1]: Starting pod:nginx[2408]
-Jun 25 10:15:53 infix-12-34-56 finit[1]: Service pod:nginx keeps crashing, not restarting.
-Jun 25 10:47:55 infix-12-34-56 finit[1]: Starting pod:nginx[2669]
-```
+For an example, see below.
+Example Containers
+------------------
+
+### System Container
+
+Let's try out what we've learned by setting up a system container, a
+container providing multiple services, using the `docker0` interface
+we created previously:
+
+ admin@example-c0-ff-ee:/> configure
+ admin@example-c0-ff-ee:/config> edit container system
+ admin@example-c0-ff-ee:/config/container/system/> set image ghcr.io/kernelkit/curios:edge
+ admin@example-c0-ff-ee:/config/container/system/> set network docker0
+ admin@example-c0-ff-ee:/config/container/system/> set publish 222:22
+ admin@example-c0-ff-ee:/config/container/system/> leave
+
+> **Note:** ensure you have a network connection to the registry.
+> If the image cannot be pulled, creation of the container will be
+> put in a queue and be retried every time there is a change in the
+> routing table, e.g., default route is added.
+
+Provided the image is downloaded successfully, a new `system` container
+now runs behind the docker0 interface, forwarding container port 22 to
+port 222 on all of the host's interfaces. (See `help publish` in the
+container configuration context for the full syntax.)
+
+Available containers can be accessed from admin-exec:
+
+ admin@example-c0-ff-ee:/> show container
+ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+ 439af2917b44 ghcr.io/kernelkit/curios:edge 41 hours ago Up 16 hours 0.0.0.0:222->222/tcp system
+
+This is a system container, so you can "attach" to it by starting a
+shell (or logging in with SSH):
+
+ admin@example-c0-ff-ee:/> container shell system
+ root@439af2917b44:/#
+
+Notice how the hostname inside the container changes. By default the
+container ID (hash) is used, but this can be easily changed:
+
+ root@439af2917b44:/# exit
+ admin@infix-00-00-00:/> configure
+ admin@infix-00-00-00:/config/> edit container system
+ admin@infix-00-00-00:/config/container/system/> set hostname system1
+ admin@infix-00-00-00:/config/container/system/> leave
+ admin@infix-00-00-00:/> container shell system
+ root@system1:/#
+
+[^1]: this does not apply to the admin-exec command `container run`.
+ This command is intended to be used for testing and evaluating
+ container images. Such containers are given a private network
+ behind an IP masquerading bridge.
+
+
+### Application Container: nftables
+
+Infix currently does not have a native firewall configuration, and even
+when it does it will never expose the full capabilities of `nftables`.
+For really advanced setups, the following will be the only alternative:
+
+ admin@example-c0-ff-ee:/> configure
+ admin@example-c0-ff-ee:/config> edit container nftables
+ admin@example-c0-ff-ee:/config/container/system/> set image ghcr.io/kernelkit/curios-nftables:edge
+ admin@example-c0-ff-ee:/config/container/system/> set host-network
+ admin@example-c0-ff-ee:/config/container/system/> edit file nftables.conf
+ admin@example-c0-ff-ee:/config/container/system/file/nftables.conf/> set path /etc/nftables.conf
+ admin@example-c0-ff-ee:/config/container/system/file/nftables.conf/> set content
+ ... interactive editor starts up where you can paste your rules ...
+ admin@example-c0-ff-ee:/config/container/system/file/nftables.conf/> leave
+
+
+### Application Container: ntpd
+
+The default NTP server/client in Infix is Chrony, a fully working and
+capable workhorse for most use-cases. However, it does not support a
+feature like multicasting, for that you need ISC ntpd.
+
+As we did with `nftables`, previously, we can use host networking and
+set up a read-only config file that is bind-mounted into the container's
+file system and store in the host's `startup-config`. However, `ntpd`
+also saves clock drift information in `/var/lib/ntpd`, so we will also
+use volumes in this example.
+
+> Infix support named volumes (only), and it is not possible to share a
+> volume between containers. All the tricks possible with volumes may
+> be added in a later release.
+
+A volume is an automatically created read-writable area that follows the
+life of your container. They survive reboots and upgrading of the base
+image, unlike the persistent writable layer you get by default, which
+does not survive upgrades. The volume is created by podman when the
+container first starts up, unlike a regular bind mount it synchronizes
+with the contents of the underlying container image's path on the first
+start. I.e., "bind-mount, if empty: then rsync".
+
+ admin@example-c0-ff-ee:/> configure
+ admin@example-c0-ff-ee:/config> edit container ntpd
+ admin@example-c0-ff-ee:/config/container/ntpd/> set image ghcr.io/kernelkit/curios-ntpd:edge
+ admin@example-c0-ff-ee:/config/container/ntpd/> set network ntpd # From veth0 above
+ admin@example-c0-ff-ee:/config/container/ntpd/> edit file ntp.conf
+ admin@example-c0-ff-ee:/config/container/ntpd/file/ntp.conf/> set path /etc/ntp.conf
+ admin@example-c0-ff-ee:/config/container/ntpd/file/ntp.conf/> set content
+ ... interactive editor starts up where you can paste your rules ...
+ admin@example-c0-ff-ee:/config/container/ntpd/file/ntp.conf/> end
+ admin@example-c0-ff-ee:/config/container/ntpd/> edit volume varlib
+ admin@example-c0-ff-ee:/config/container/ntpd/volume/varlib/> set path /var/lib
+ admin@example-c0-ff-ee:/config/container/ntpd/volume/varlib/> leave
+ admin@example-c0-ff-ee:/> copy running-config startup-config
+
+The `ntp.conf` file is stored in the host's `startup-config` and any
+state data in the container's `/var/lib` is retained between reboots
+and across image upgrades.
+
+
+Upgrading a Container Image
+---------------------------
+
+All container configurations are locked to the image hash at the time of
+first download, not just ones that use an `:edge` or `:latest` tag. An
+upgrade of containers using versioned images is more obvious -- update
+the configuration -- but the latter is a bit trickier. Either remove
+the configuration and recreate it (leave/apply the changes between), or
+use the admin-exec level command:
+
+ admin@example-c0-ff-ee:/> container upgrade NAME
+
+Where `NAME` is the name of your container. This command stops your
+container, does a `container pull IMAGE`, and then recreates the
+container with the new image. Upgraded containers are not automatically
+restarted.
+
+ admin@example-c0-ff-ee:/> container start NAME
+
+> **Note:** the default writable layer is lost when upgrading the image
+> Use named volumes for directories with writable content you wish to
+> keep over an upgrade.
+
+
+[1]: https://github.com/kernelkit/infix/blob/main/src/confd/yang/infix-containers%402023-12-14.yang
+[CNI]: https://www.cni.dev/
[podman]: https://podman.io