diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b6c6f67..f10594f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -2,7 +2,8 @@ name: Build and release Systemd sysext images on: push: tags: - - '*' + - 'latest' + - '[0-9]+' jobs: build: runs-on: ubuntu-22.04 @@ -11,37 +12,63 @@ jobs: contents: write steps: # checkout the sources - - uses: actions/checkout@v3 - # build the images and generate a manifest - - name: build + - uses: actions/checkout@v4 + with: + path: bakery + + # prepare build host + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: install prerequisites run: | - set -euo pipefail + set -euxo pipefail sudo apt update -qq && sudo apt install -yqq \ curl \ jq \ squashfs-tools \ - xz-utils - - images=( - "kubernetes-v1.27.4" - "docker-24.0.5" - "docker_compose-2.17.2" - "wasmtime-12.0.1" - ) - - for image in ${images[@]}; do - component="${image%-*}" - version="${image#*-}" - "./create_${component}_sysext.sh" "${version}" "${component}" - mv "${component}.raw" "${image}.raw" - done - - sha256sum *.raw > SHA256SUMS - # create a Github release with the generated artifacts - - name: release - uses: softprops/action-gh-release@v1 + xz-utils \ + gawk + + - name: build release artifacts + run: | + pushd bakery + REPO=${{ github.repository }} ./release_build.sh + + - name: create a new latest release with some artifacts + uses: softprops/action-gh-release@v2 + with: + make_latest: true + body_path: bakery/Release.md + files: | + bakery/SHA256SUMS + bakery/!(kubernetes|crio|ollama)*.raw + bakery/*.conf + + - name: upload kubernetes x86-64 artifacts + uses: softprops/action-gh-release@v2 + with: + files: | + bakery/kubernetes*-x86-64.raw + + - name: upload kubernetes arm64 artifacts + uses: softprops/action-gh-release@v2 + with: + files: | + bakery/kubernetes*-arm64.raw + + - name: upload crio artifacts + uses: softprops/action-gh-release@v2 + with: + files: | + bakery/crio*.raw + + - name: upload ollama artifacts + uses: softprops/action-gh-release@v2 with: files: | - SHA256SUMS - *.raw + bakery/ollama*.raw diff --git a/README.md b/README.md index ae5af3c..9bb71a8 100644 --- a/README.md +++ b/README.md @@ -4,23 +4,21 @@ Flatcar Container Linux as an OS without a package manager is a good fit for extension through systemd-sysext. The tools in this repository help you to create your own sysext images bundeling software to extend your base OS. The current focus is on Docker and containerd, contributions are welcome for other software. +See the section at the end on how to bundle any software with the Flix and Flatwrap tools. ## Systemd-sysext The `NAME.raw` sysext images (or `NAME` sysext directories) can be placed under `/etc/extensions/` or `/var/lib/extensions` to be activated on boot by `systemd-sysext.service`. -While systemd-sysext images are not really meant to also include the systemd service, Flatcar ships `ensure-sysext.service` as workaround to automatically load the image's services. -This helper service is bound to `systemd-sysext.service` which activates the sysext images on boot. -Currently it reloads the unit files from disk and reevaluates `multi-user.target`, `sockets.target`, and `timers.target`, making sure your enabled systemd units run. -In the future `systemd-sysext` will only reload the unit files when this is upstream behavior (the current upstream behavior is to do nothing and leave it to the user). -That means you need to use `Upholds=` drop-ins for the target units to start your units. -At runtime executing `systemctl restart systemd-sysext ensure-sysext` will reload the sysext images and start the services. -A manual `systemd-sysext refresh` is not recommended. +Images can specify to require systemd to do a daemon reload (needs systemd 255, Flatcar ships `ensure-sysext.service` as workaround to automatically load the image's services). + +A current limitation of `systemd-sysext` is that you need to use `TARGET.upholds` symlinks (supported from systemd 254, similar to `.wants`) or `Upholds=` drop-ins for the target units to start your units. +For current versions of Flatcar (systemd 252) you need to use `systemctl restart systemd-sysext ensure-sysext` to reload the sysext images and start the services and a manual `systemd-sysext refresh` is not recommended. The compatibility mechanism of sysext images requires a metadata file in the image under `usr/lib/extension-release.d/extension-release.NAME`. -It needs to contain a matching OS `ID`, and either a matching `VERSION_ID` or `SYSEXT_LEVEL`. +It needs to contain a matching OS `ID`, and either a matching `VERSION_ID` or `SYSEXT_LEVEL`. Here you can also set `EXTENSION_RELOAD_MANAGER=1` for a systemd daemon reload. Since the rapid release cycle and automatic updates of Flatcar Container Linux make it hard to rely on particular OS libraries by specifying a dependency of the sysext image to the OS version, it is not recommended to match by `VERSION_ID`. Instead, Flatcar defined the `SYSEXT_LEVEL` value `1.0` to match for. -With systemd 252 you can also use `ID=_any` and then neither `SYSEXT_LEVEL` nor `VERSION_ID` are needed. +You can also use `ID=_any` and then neither `SYSEXT_LEVEL` nor `VERSION_ID` are needed. The sysext image should only include static binaries. Inside the image, binaries should be placed under `usr/bin/` and systemd units under `usr/lib/systemd/system/`. @@ -61,23 +59,44 @@ storage: ## Systemd-sysext on other distributions -The tools here will by default build for Flatcar and create the metadata file `usr/lib/extension-release.d/extension-release.NAME` as follows: +The tools here will by default build for any OS and create the metadata file `usr/lib/extension-release.d/extension-release.NAME` as follows: ``` -ID=flatcar -SYSEXT_LEVEL=1.0 +ID=_any +# Depending on the image, e.g., for Docker systemd units, there is also: +# EXTENSION_RELOAD_MANAGER=1 ``` -This means other distributions will reject to load the sysext image by default. Use the configuration parameters in the tools to build for your distribution (pass `OS=` to be the OS ID from `/etc/os-release`) or to build for any distribution (pass `OS=_any`). You can also set the architecture to be arm64 to fetch the right binaries and encode this information in the sysext image metadata. -To add the automatic systemd unit loading to your distribution, store [`ensure-sysext.service`](https://raw.githubusercontent.com/flatcar/init/ccade77b6d568094fb4e4d4cf71b867819551798/systemd/system/ensure-sysext.service) in your systemd folder (e.g., `/etc/systemd/system/`) and enable the units: `systemctl enable --now ensure-sysext.service systemd-sysext.service`. - ## Recipes in this repository The tools normally generate squashfs images not only because of the compression benefits but also because it doesn't need root permissions and loop device mounts. +### Available Extensions + +The following table shows which build recipes exist and for which the GitHub Release publishes updatable images. +While the goal is to automate the release pipeline to detect latest versions and have weekly releases, currently the release trigger is manual and all version updates except Kubernetes are also manual. +For extensions that are not part of the GitHub Release or which you want to customize, you can build your own images and host them elsewhere - the easiest is to fork this repo and modify the `release_build_versions.txt` file and create a new `latest` tag. + +| Extension | Availability | +| --- | --- | +| `kubernetes` | released | +| `docker` | released (includes containerd) | +| `docker_compose` | released | +| `falco` | released | +| `nvidia-runtime` | released | +| `wasmtime` | released | +| `wasmcloud` | released | +| `tailscale` | released | +| `crio` | released | +| `k3s` | released | +| `rke2` | released | +| `keepalived` | build script | +| `ollama` | released | + + ### Consuming the published images There is a Github Action to build current recipes and to publish the built images as release artifacts. It's possible to directly consume the latest release from a Butane/Ignition configuration, example: @@ -88,19 +107,28 @@ variant: flatcar version: 1.0.0 storage: files: - - path: /opt/extensions/docker/docker-24.0.5.raw + - path: /opt/extensions/wasmtime/wasmtime-24.0.0-x86-64.raw contents: - source: https://github.com/flatcar/sysext-bakery/releases/download/20230803/docker-24.0.5.raw - - path: /opt/extensions/kubernetes/kubernetes-v1.27.4.raw + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmtime-24.0.0-x86-64.raw + - path: /opt/extensions/docker/docker-24.0.9-x86-64.raw contents: - source: https://github.com/flatcar/sysext-bakery/releases/download/20230803/kubernetes-v1.27.4.raw + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/docker-24.0.9-x86-64.raw - path: /etc/systemd/system-generators/torcx-generator + - path: /etc/sysupdate.d/noop.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf + - path: /etc/sysupdate.wasmtime.d/wasmtime.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmtime.conf + - path: /etc/sysupdate.docker.d/docker.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/docker.conf links: - - target: /opt/extensions/docker/docker-24.0.5.raw - path: /etc/extensions/docker.raw + - target: /opt/extensions/wasmtime/wasmtime-24.0.0-x86-64.raw + path: /etc/extensions/wasmtime.raw hard: false - - target: /opt/extensions/kubernetes/kubernetes-v1.27.4.raw - path: /etc/extensions/kubernetes.raw + - target: /opt/extensions/docker/docker-24.0.9-x86-64.raw + path: /etc/extensions/docker.raw hard: false - path: /etc/extensions/docker-flatcar.raw target: /dev/null @@ -108,9 +136,31 @@ storage: - path: /etc/extensions/containerd-flatcar.raw target: /dev/null overwrite: true +systemd: + units: + - name: systemd-sysupdate.timer + enabled: true + - name: systemd-sysupdate.service + dropins: + - name: wasmtime.conf + contents: | + [Service] + ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C wasmtime update + - name: docker.conf + contents: | + [Service] + ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C docker update + - name: sysext.conf + contents: | + [Service] + ExecStartPost=systemctl restart systemd-sysext ``` -In the generated artifacts, there is a `SHA256SUMS` holding the list of built images with their respective SHA256 digest. It allows to use `https://github.com/flatcar/sysext-bakery/releases/latest/download/` in a [`systemd-sysupdate`](https://www.freedesktop.org/software/systemd/man/sysupdate.d.html) configuration file, example: +This also configures systemd-sysupdate for auto-updates. The `noop.conf` is a workaround for systemd-sysupdate to run without error messages. +Since the configuration sets up a custom Docker version, it also disables Torcx and the future `docker-flatcar` and `containerd-flatcar` extensions to prevent conflicts. + +Here a template for a single extension where you have to replace `NAME`, `VERSION`, and `ARCH`: + ```yaml # butane < config.yaml > config.json # ./flatcar_production_qemu.sh -i ./config.json @@ -118,82 +168,328 @@ variant: flatcar version: 1.0.0 storage: files: + - path: /opt/extensions/NAME/NAME-VERSION-ARCH.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/NAME-VERSION-ARCH.raw - path: /etc/sysupdate.d/noop.conf contents: - inline: | - [Source] - Type=regular-file - Path=/ - MatchPattern=invalid@v.raw - [Target] - Type=regular-file - Path=/ - - path: /etc/sysupdate.kubernetes.d/kubernetes.conf + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf + - path: /etc/sysupdate.NAME.d/NAME.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/NAME.conf + links: + - target: /opt/extensions/NAME/NAME-VERSION-ARCH.raw + path: /etc/extensions/NAME.raw + hard: false +systemd: + units: + - name: systemd-sysupdate.timer + enabled: true + - name: systemd-sysupdate.service + dropins: + - name: NAME.conf + contents: | + [Service] + ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C NAME update + - name: sysext.conf + contents: | + [Service] + ExecStartPost=systemctl restart systemd-sysext +``` + +In the [Flatcar docs](https://www.flatcar.org/docs/latest/provisioning/sysext/) you can find an Ignition configuration that explicitly sets the update configurations instead of downloading them. + +The updates works by [`systemd-sysupdate`](https://www.freedesktop.org/software/systemd/man/sysupdate.d.html) fetching the `SHA256SUMS` file of the generated artifacts, which holds the list of built images with their respective SHA256 digest. + +#### Falco + +To setup [Falco](https://falco.org/docs/getting-started/) we need the sysext plus the configuration files and the systemd unit. + +By default, the falcon daemon systemd unit shipped is the [Falco Modern EBPF](https://github.com/falcosecurity/falco/blob/master/scripts/systemd/falco-modern-bpf.service). Create systemd drop-ins or replace the service to suit your needs if necessary. + +The default falco config and rules files are shipped, but you can overwrite it. The example bellow shows how to override the default files: + +```yaml +storage: + files: + - path: /etc/falco/falco_rules.local.yaml + contents: + source: "https://raw.githubusercontent.com/sysdiglabs/falco-workshop/refs/heads/master/falco_rules.local.yaml" + - path: /etc/extensions/falco.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/falco-0.39.1-x86-64.raw +``` + +Of course its also possible to use the +[artifact-follower](https://falco.org/blog/falcoctl-install-manage-rules-plugins/#follow-artifacts) to download falco artifacts automatically. + +#### Kubernetes + +The [Flatcar Kubernetes docs](https://www.flatcar.org/docs/latest/container-runtimes/getting-started-with-kubernetes/) show how to use the extension provided here for controllers and workers. + +#### wasmcloud + +For another example of how you can further customize the recipes provided in this repository, the following recipe uses the image built with `create_wasmcloud_sysext.sh`: +```yaml +variant: flatcar +version: 1.0.0 +storage: + files: + - path: /opt/extensions/wasmcloud/wasmcloud-1.2.1-x86-64.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmcloud-1.2.1-x86-64.raw + - path: /etc/sysupdate.d/noop.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf + - path: /etc/sysupdate.wasmcloud.d/wasmcloud.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmcloud.conf + - path: /etc/nats-server.conf contents: inline: | - [Transfer] - Verify=false - - [Source] - Type=url-file - Path=https://github.com/flatcar/sysext-bakery/releases/latest/download/ - MatchPattern=kubernetes-@v.raw - - [Target] - InstancesMax=3 - Type=regular-file - Path=/opt/extensions/kubernetes - CurrentSymlink=/etc/extensions/kubernetes.raw - - path: /etc/sysupdate.docker.d/docker.conf + jetstream { + domain: default + } + leafnodes { + remotes = [ + { + url: "tls://connect.cosmonic.sh" + credentials: "/etc/nats.creds" + } + ] + } + - path: /etc/nats.creds contents: inline: | - [Transfer] - Verify=false - - [Source] - Type=url-file - Path=https://github.com/flatcar/sysext-bakery/releases/latest/download/ - MatchPattern=docker-@v.raw - - [Target] - InstancesMax=3 - Type=regular-file - Path=/opt/extensions/docker - CurrentSymlink=/etc/extensions/docker.raw + + links: + - target: /opt/extensions/wasmcloud/wasmcloud-1.2.1-x86-64.raw + path: /etc/extensions/wasmcloud.raw + hard: false systemd: units: - - name: systemd-sysupdate.timer + - name: nats.service enabled: true - - name: systemd-sysupdate.service dropins: - - name: docker.conf + - name: 10-nats-env-override.conf contents: | [Service] - ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C docker update - - name: kubernetes.conf + Environment=NATS_CONFIG=/etc/nats-server.conf + - name: wasmcloud.service + enabled: true + dropins: + - name: 10-wasmcloud-env-override.conf contents: | [Service] - ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C kubernetes update + Environment=WASMCLOUD_LATTICE= + - name: systemd-sysupdate.timer + enabled: true + - name: systemd-sysupdate.service + dropins: + - name: wasmcloud.conf + contents: | + [Service] + ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C wasmcloud update - name: sysext.conf contents: | [Service] ExecStartPost=systemctl restart systemd-sysext ``` +This example uses Butane/Ignition configuration do the following customizations beyond simply including the image: + +1. Provide a different configuration to setup the nats-server to act as a leaf node to a pre-existing wasmCloud deployment (`/etc/nats-server.conf`). +2. Provide a set of credentials for the nats-server leaf node to connect with (`/etc/nats.creds`). +3. Override the bundled `NATS_CONFIG` environment variable to point it to the newly created configuration (`NATS_CONFIG=/etc/nats-server.conf`). +4. Override the lattice the wasmCloud host is configured to connect (`WASMCLOUD_LATTICE=`). + +#### k3s + +The k3s sysext can be configured by using the following snippet, in case you +want this to be a k3s server (controlplane): + +```yaml +variant: flatcar +version: 1.0.0 +storage: + files: + # filename needs to be k3s.raw + - path: /etc/extensions/k3s.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/k3s-v1.31.1+k3s1-x86-64.raw + links: + - path: /etc/systemd/system/multi-user.target.wants/k3s.service + target: /usr/local/lib/systemd/system/k3s.service + overwrite: true +``` + +Please note that this way you will not get automatic updates via +`systemd-sysupdate`. + +For a k3s agent (worker node) you would use something like this snippet: + +```yaml +variant: flatcar +version: 1.0.0 +storage: + files: + # filename needs to be k3s.raw + - path: /etc/extensions/k3s.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/k3s-v1.31.1+k3s1-x86-64.raw + links: + - path: /etc/systemd/system/multi-user.target.wants/k3s-agent.service + target: /usr/local/lib/systemd/system/k3s-agent.service + overwrite: true +``` + +Of course, any configuration you need should be prepared before starting the +services, like providing a token for an agent or server to join or creating a +`config.yaml` file. + +#### rke2 + +The rke2 sysext can be configured by using the following snippet, in case you +want this to be a rke2 server (controlplane): + +```yaml +variant: flatcar +version: 1.0.0 +storage: + links: + # filename needs to be rke2.raw + - path: /etc/extensions/rke2.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/rke2-v1.31.1+rke2r1-x86-64.raw + - path: /etc/systemd/system/multi-user.target.wants/rke2-server.service + target: /usr/local/lib/systemd/system/rke2-server.service + overwrite: true +``` + +Please note that this way you will not get automatic updates via +`systemd-sysupdate`. + +For a rke2 agent (worker node) you would use something like this snippet: + +```yaml +variant: flatcar +version: 1.0.0 +storage: + links: + # filename needs to be rke2.raw + - path: /etc/extensions/rke2.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/rke2-v1.31.1+rke2r1-x86-64.raw + - path: /etc/systemd/system/multi-user.target.wants/rke2-agent.service + target: /usr/local/lib/systemd/system/rke2-agent.service + overwrite: true +``` + +Of course, any configuration you need should be prepared before starting the +services, like providing a token for an agent or server to join or creating a +`config.yaml` file. + +#### Tailscale + +The Tailscale sysext ships a service unit but doesn't pre-enable it. +You can use this Butane snippet to enable it: + +``` +variant: flatcar +version: 1.0.0 +storage: + links: + - path: /etc/systemd/system/multi-user.target.wants/tailscaled.service + target: /usr/local/lib/systemd/system/tailscaled.service + overwrite: true +``` + +#### Ollama + +The ollama sysext can be configured by using the following snippet: + +``` +variant: flatcar +version: 1.0.0 +storage: + files: + - path: /opt/extensions/ollama/ollama-0.3.9-x86-64.raw + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/ollama-0.3.9-x86-64.raw + - path: /etc/sysupdate.ollama.d/ollama.conf + contents: + source: https://github.com/flatcar/sysext-bakery/releases/download/latest/ollama.conf + links: + - target: /opt/extensions/ollama/ollama-0.3.9-x86-64.raw + path: /etc/extensions/ollama.raw + hard: false +systemd: + units: + - name: ollama.service + enabled: true + dropins: + - name: 10-ollama-env-override.conf + contents: | + [Service] + Environment=HOME="/var/lib/ollama" + Environment=OLLAMA_MODELS="/var/lib/ollama/models" + Environment=OLLAMA_RUNNERS_DIR="/var/lib/ollama/runners" +``` + +Note that this configuration can be customized in terms of where Ollama is configured to store its models, configuration and runtime libraries by changing the `HOME`, `OLLAMA_MODELS` and `OLLAMA_RUNNERS_DIR`. + +Please refer to the [Ollama documentation for further details](https://github.com/ollama/ollama/tree/main/docs). + +### Building sysext images + +To use the build scripts in this repository, the following packages are required: + +- `curl` +- `jq` +- `squashfs-tools` +- `xz-utils` +- `gawk` +- [`yq`](https://github.com/mikefarah/yq/releases/latest/) + + +#### Build individual sysext image + +To build the Kubernetes sysext for example, use: + +```sh +./create_kubernetes_sysext.sh v1.29.8 kubernetes +``` + +Afterwards, you can test the sysext image with: + +```sh +sudo cp kubernetes.raw /etc/extensions/kubernetes.raw +sudo systemd-sysext refresh +kubeadm version +``` + +#### Build all sysext images in this repository + +This builds `x86-64` and `arm64` versions of **all** sysext images listed in `release_build_versions.txt`. This takes some time. + +```sh +./release_build.sh +``` + ### Creating a custom Docker sysext image The Docker releases publish static binaries including containerd and the only missing piece are the systemd units. To ease the process, the `create_docker_sysext.sh` helper script takes care of downloading the release binaries and adding the systemd unit files, and creates a combined Docker+containerd sysext image: ``` -./create_docker_sysext.sh 20.10.13 mydocker +./create_docker_sysext.sh 24.0.9 mydocker [… writes mydocker.raw into current directory …] ``` Pass the `OS` or `ARCH` environment variables to build for another target than Flatcar amd64, e.g., for any distro with arm64: ``` -OS=_any ARCH=aarch64 ./create_docker_sysext.sh 20.10.13 mydocker +OS=_any ARCH=arm64 ./create_docker_sysext.sh 24.0.9 mydocker [… writes mydocker.raw into current directory …] ``` @@ -202,6 +498,103 @@ See the above intro section on how to use the resulting sysext image. You can also limit the sysext image to only Docker (without containerd and runc) or only containerd (no Docker but runc) by passing the environment variables `ONLY_DOCKER=1` or `ONLY_CONTAINERD=1`. If you build both sysext images that way, you can load both combined and, e.g., only load the Docker sysext image for debugging while using the containerd sysext image by default for Kubernetes. +### Baking sysexts into Flatcar OS images + +Using the `bake_flatcar_image.sh` script, custom Flatcar OS images can be created which include one or more sysexts. +The script will download a Flatcar OS release image, insert the desired sysexts, and optionally create a vendor (public / private cloud or bare metal) image. + +By default, the script operates with local sysexts (and optionally sysupdate configurations if present). +However, the `--fetch` option may be specified to fetch the sysext `.raw` file and sysupdate config from the latest Bakery release. + +Sysexts can be added to the root partition or the OEM partition of the OS image (root is preferred). +Read more about Flatcar's OS image disk layout here: https://www.flatcar.org/docs/latest/reference/developer-guides/sdk-disk-partitions/ + +The script requires sudo access at certain points to manage loopback mounts for the OS image partitions and will then prompt for a password. + +Refer to `./bake_flatcar_image.sh --help` for more information. + +Example usage: +``` +./bake_flatcar_image.sh --fetch --vendor qemu_uefi wasmtime:wasmtime-24.0.0-x86-64.raw +``` + +Example usage with local sysext: +``` +ls -1 + myext-1.0.1-x86-64.raw + myext.conf +./bake_flatcar_image.sh --fetch --vendor qemu_uefi myext:myext-1.0.1-x86-64.raw +``` + +The script supports all vendors and clouds natively supported by Flatcar. + +### Flix and Flatwrap + +The Flix and Flatwrap tools both convert a given chroot folder into a systemd-sysext image. +You have to specify which files should be made available to the host. + +The Flix tool rewrites specified binaries to use a custom library path. +You also have to specify needed resource folders and you can specify systemd units, too. + +Here examples with Flix: + +``` +CMD="apk -U add b3sum" ./oci-rootfs.sh alpine:latest /var/tmp/alpine-b3sum +./flix.sh /var/tmp/alpine-b3sum/ b3sum /usr/bin/b3sum /bin/busybox:/usr/bin/busybox +# got b3sum.raw + +CMD="apt-get update && apt install -y nginx" ./oci-rootfs.sh debian /var/tmp/debian-nginx +./flix.sh /var/tmp/debian-nginx/ nginx /usr/sbin/nginx /usr/sbin/start-stop-daemon /usr/lib/systemd/system/nginx.service +# got nginx.raw + +# Note: Enablement of nginx.service with Butane would happen as in the k3s example +# but you can also pre-enable the service inside the extension. +# Here a non-production nginx test config if you want to try the above: +$ cat /etc/nginx/nginx.conf +user root; +pid /run/nginx.pid; + +events { +} + +http { + access_log /dev/null; + proxy_temp_path /tmp; + client_body_temp_path /tmp; + fastcgi_temp_path /tmp; + uwsgi_temp_path /tmp; + scgi_temp_path /tmp; + server { + server_name localhost; + listen 127.0.0.1:80; + } +} +``` + +The Flatwrap tool generates entry point wrappers for a chroot with `unshare` or `bwrap`. +You can specify systemd units, too. By default `/etc`, `/var`, and `/home` are mapped from the host but that is configurable (see `--help`). + +Here examples with Flatwrap: + +``` +CMD="apk -U add b3sum" ./oci-rootfs.sh alpine:latest /var/tmp/alpine-b3sum +./flatwrap.sh /var/tmp/alpine-b3sum b3sum /usr/bin/b3sum /bin/busybox:/usr/bin/busybox +# got b3sum.raw + +CMD="apk -U add htop" ./oci-rootfs.sh alpine:latest /var/tmp/alpine-htop +# Use ETCMAP=chroot because alpine's htop needs alpine's /etc/terminfo +ETCMAP=chroot ./flatwrap.sh /var/tmp/alpine-htop htop /usr/bin/htop +# got htop.raw + +CMD="apt-get update && apt install -y nginx" ./oci-rootfs.sh debian /var/tmp/debian-nginx +./flatwrap.sh /var/tmp/debian-nginx/ nginx /usr/sbin/nginx /usr/sbin/start-stop-daemon /usr/lib/systemd/system/nginx.service +# got nginx.raw + +# Note: Enablement of nginx.service with Butane would happen as in the k3s example +# but you can also pre-enable the service inside the extension. +# (The "non-production" nginx test config above can be used here, too, stored on the host's /etc.) +``` + ### Converting a Torcx image Torcx was a solution for switching between different Docker versions on Flatcar. @@ -213,3 +606,14 @@ In case you have an existing Torcx image you can convert it with the `convert_to ``` Please make also sure that your don't have a `containerd.service` drop in file under `/etc` that uses Torcx paths. + +## For maintainers: how to release? + +CI can be kicked-off by overriding the `latest` tag. The `latest` release artifacts will be updated consequently here: https://github.com/flatcar/sysext-bakery/releases/tag/latest +``` +git checkout main +git pull --ff-only +git tag -d latest +git tag -as latest +git push origin --force latest +``` diff --git a/bake.sh b/bake.sh index 8d42126..2a71e88 100755 --- a/bake.sh +++ b/bake.sh @@ -1,9 +1,12 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail -OS="${OS-flatcar}" +OS="${OS-_any}" FORMAT="${FORMAT:-squashfs}" ARCH="${ARCH-}" +RELOAD="${RELOAD-}" +SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH-0}" +export SOURCE_DATE_EPOCH # This script is to be called as helper by other scripts but can also be used standalone if [ $# -lt 1 ]; then @@ -12,9 +15,11 @@ if [ $# -lt 1 ]; then exit 1 elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then echo "If ARCH is specified as environment variable the sysext image will be required to run on the given architecture." - echo "To build for another OS than Flatcar, pass 'OS=myosid' as environment variable (current value is '${OS}'), e.g., 'fedora' as found in 'ID' under '/etc/os-release', or pass 'OS=_any' for any OS." + echo "To build for a specific OS, pass 'OS=myosid' as environment variable (current value is '${OS}'), e.g., 'fedora' as found in 'ID' under '/etc/os-release', or pass 'OS=_any' for any OS." echo "The '/etc/os-release' file of your OS has to include 'SYSEXT_LEVEL=1.0' as done in Flatcar (not needed for 'OS=_any')." + echo "To specify that systemd should do a daemon reload for the system when the extension is loaded/unloaded, set RELOAD=1 (current value is '${RELOAD}')." echo "If the mksquashfs tool is missing you can pass FORMAT=btrfs, FORMAT=ext4, or FORMAT=ext2 as environment variable (current value is '${FORMAT}') but the script won't change the ownership of the files in the SYSEXTNAME directory, so make sure that they are owned by root before creating the sysext image to avoid any problems." + echo "To make builds reproducible the SOURCE_DATE_EPOCH environment variable will be set to 0 if not defined." echo exit 1 fi @@ -33,6 +38,10 @@ elif [ "${ARCH}" = "aarch64" ]; then ARCH="arm64" fi +function version_ge() { + test "$(printf '%s\n' "$@" | sort -rV | head -n 1)" == "$1"; +} + mkdir -p "${SYSEXTNAME}/usr/lib/extension-release.d" { echo "ID=${OS}" @@ -42,6 +51,9 @@ mkdir -p "${SYSEXTNAME}/usr/lib/extension-release.d" if [ "${ARCH}" != "" ]; then echo "ARCHITECTURE=${ARCH}" fi + if [ "${RELOAD}" = 1 ]; then + echo "EXTENSION_RELOAD_MANAGER=1" + fi } > "${SYSEXTNAME}/usr/lib/extension-release.d/extension-release.${SYSEXTNAME}" rm -f "${SYSEXTNAME}".raw if [ "${FORMAT}" = "btrfs" ]; then @@ -55,6 +67,12 @@ elif [ "${FORMAT}" = "ext4" ] || [ "${FORMAT}" = "ext2" ]; then mkfs."${FORMAT}" -E root_owner=0:0 -d "${SYSEXTNAME}" "${SYSEXTNAME}".raw resize2fs -M "${SYSEXTNAME}".raw else - mksquashfs "${SYSEXTNAME}" "${SYSEXTNAME}".raw -all-root + VER=$({ mksquashfs -version || true ; } | head -n1 | cut -d " " -f 3) + ARG=(-all-root -noappend) + # use sort semver to check if current version is >= 4.6.1 + if version_ge "$VER" "4.6.1"; then + ARG+=('-xattrs-exclude' '^btrfs.') + fi + mksquashfs "${SYSEXTNAME}" "${SYSEXTNAME}".raw "${ARG[@]}" fi echo "Created ${SYSEXTNAME}.raw" diff --git a/bake_flatcar_image.sh b/bake_flatcar_image.sh new file mode 100755 index 0000000..189a920 --- /dev/null +++ b/bake_flatcar_image.sh @@ -0,0 +1,337 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 The Flatcar Maintainers. +# Use of this source code is governed by the Apache 2.0 license. +# +# Embed one or more sysexts into a Flatcar generic OS image. +# Optionally, build a vendor image (requires the Flatcar SDK). + +fetch="no" +vendor="generic" +release="stable" + +# From https://www.freedesktop.org/software/systemd/man/os-release.html#ARCHITECTURE= +arch="x86-64" +install_to="root:/opt/extensions/" + +set -euo pipefail +workdir="$(pwd)/flatcar-os-image" +bakery_base_url="https://github.com/flatcar/sysext-bakery/releases/latest/download" + +# ./run_sdk_container ./image_to_vm.sh --help 2>&1 | grep '\--format' +supported_vendors=( "ami" "ami_vmdk" "azure" "cloudsigma" "cloudstack" "cloudstack_vhd" "digitalocean" "exoscale" "gce" "hyperv" "iso" "openstack" "openstack_mini" "packet" "parallels" "pxe" "qemu" "qemu_uefi" "qemu_uefi_secure" "rackspace" "rackspace_onmetal" "rackspace_vhd" "vagrant" "vagrant_parallels" "vagrant_virtualbox" "vagrant_vmware_fusion" "virtualbox" "vmware" "vmware_insecure" "vmware_ova" "vmware_raw" "xen" ) + +function print_help() { + echo + echo "Usage: $0 [--fetch|--vendor|--arch|--release|--install_to