Random Musings

O for a muse of fire, that would ascend the brightest heaven of invention!


Creating custom OCI containers with buildah

Wednesday, 15 Jan 2025 Tags: freebsdoci

So far, this blog has touched on running and using existing containers, which is all well and good, but it’s a bit like eating raw oats for breakfast, sometimes you want to have something a little more interesting.

Also, we have largely been ignoring the internals of containers, but it’s time to change that. In this post, we’ll look at how to create custom containers using buildah. It will be helpful to have your own registry already set up and running, but it’s not strictly necessary.

Overall, the standard container world comprises:

  • configuration file formats (the Image Format specification)
  • a set of standard operations (the Runtime specification)
  • an execution environment (jails on FreeBSD, using podman or buildah)

We’ll refer to two different specifications in this post:

Currently these are at v1.1.0 and v1.2.0 respectively.

Getting Started

The first thing you need to understand is that containers have a different way of starting up compared to the rc-based init system as used on typical FreeBSD systems and jails.

Containers are started by running a command, and when that command exits, the container stops. While it’s possible to run a full rc in containers, it’s going against the grain, and you’re better off using a more container-native approach.

This also means that many existing FreeBSD ports, that expect a fully functional FreeBSD system, including cron, syslog, and other common services, will need a few changes, and possibly some custom scripts to set things up the OCI way, including user accounts, and environment variables too, that would normally be available by default, through ports and packages.

Commands and Entry Points

Effectively, the entry point for a container is the command that is run when the container starts. This can be set in the container configuration, or overridden at runtime. Often, the command is a shell script that sets up the environment and then runs the main application. If there is no explicit entry point, then the default command is run.

As an example, let’s look at the freebsd14-minimal container that was shipped as the first officially released container. After you have loaded the container, it will be present locally, and we can use podman inspect to see what settings it has.

If you’ve not already done so, see the previous post and use podman load ... to fetch the signed container image.

# podman images
podman images
REPOSITORY                         TAG                   IMAGE ID      CREATED      SIZE
localhost/freebsd14-minimal        14.2-RELEASE-amd64    c5f3e77557a9  6 weeks ago  35.1 MB
..

# podman inspect c5f3e77557a9
[
     {
          "Id": "c5f3e77557a916c124bfb74bdd982efe0a5749aaba9de0d282703d4634b28839",
          "Digest": "sha256:b98b8f5438a07e000a156ecb216529d8dfa191448ac3dc1f6add9848b4461d05",
          "RepoTags": [
               "localhost/freebsd14-minimal:14.2-RELEASE-amd64"
          ],
          "RepoDigests": [
               "localhost/freebsd14-minimal@sha256:b98b8f5438a07e000a156ecb216529d8dfa191448ac3dc1f6add9848b4461d05"
          ],
          "Parent": "ebf7538b22f43206d308fecc12bfebc72beb6d1f0e89ce9d95ed1979583010ee",
          "Comment": "",
          "Created": "2024-11-29T10:34:57.587490327Z",
          "Config": {
               "Labels": {
                    "io.buildah.version": "1.36.0"
               }
          },
          "Version": "",
          "Author": "",
          "Architecture": "amd64",
          "Os": "freebsd",
          "Size": 35067392,
          "VirtualSize": 35067392,
          "GraphDriver": {
               "Name": "zfs",
               "Data": {
                    "Dataset": "zroot/containers/36b0c80ca1f71afdd5813c5fbd5b55fe686ec6361df1ff36286f2176be67a3fe",
                    "Mountpoint": "/var/db/containers/storage/zfs/graph/36b0c80ca1f71afdd5813c5fbd5b55fe686ec6361df1ff36286f2176be67a3fe"
               }
          },
          "RootFS": {
               "Type": "layers",
               "Layers": [
                    "sha256:cd53fb07fb66f2c92709cbc407af686fa53276397762dfb27c040a2f64508000",
                    "sha256:f709c8f6cb8695415033da5819b83262c51cd9512bddb64e0681c48a61b8723f",
                    "sha256:357c210f8575c70360e88cfcf3d0c241f7e3fa21669ec55bb935dce361a90585"
               ]
          },
          "Labels": {
               "io.buildah.version": "1.36.0"
          },
          "Annotations": {
               "org.opencontainers.image.base.digest": "sha256:7c1c45d99ffe8344021227ad651f675ac22eeb39b96c8c6abfe2d0612f4c2ccc",
               "org.opencontainers.image.base.name": "localhost/freebsd14-dynamic:latest"
          },
          "ManifestType": "application/vnd.oci.image.manifest.v1+json",
          "User": "",
          "History": [
               {
                    "created": "2024-11-29T09:55:25.405122405Z",
                    "created_by": "/bin/sh"
               },
               {
                    "created": "2024-11-29T10:34:08.010623771Z",
                    "created_by": "/bin/sh",
                    "comment": "FROM localhost/freebsd14-static:latest"
               },
               {
                    "created": "2024-11-29T10:34:58.10725353Z",
                    "created_by": "/bin/sh",
                    "comment": "FROM localhost/freebsd14-dynamic:latest"
               }
          ],
          "NamesHistory": [
               "localhost/freebsd14-minimal:14.2-RELEASE-amd64"
          ]
     }
]