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