├── .gitignore ├── Justfile ├── LICENSE ├── README.md ├── build_devtools_sysext.sh ├── build_docker_sysext.sh ├── build_incus_sysext.sh ├── build_neovim_sysext.sh ├── build_vscode_sysext.sh ├── builders ├── caddy │ └── Containerfile.caddy ├── docker │ ├── Containerfile.docker │ └── files │ │ └── usr │ │ ├── lib │ │ └── systemd │ │ │ ├── system-preset │ │ │ └── 30-ublue.preset │ │ │ └── system │ │ │ ├── containerd.service │ │ │ ├── docker.service │ │ │ ├── docker.socket │ │ │ ├── multi-user.target.d │ │ │ └── 10-containerd-service.conf │ │ │ └── sockets.target.d │ │ │ └── 10-docker-socket.conf │ │ └── share │ │ └── containerd │ │ ├── config-cgroupfs.toml │ │ └── config.toml ├── go │ └── Containerfile.go ├── incus │ ├── Containerfile.incus │ └── env.sh ├── meta │ ├── Containerfile.meta │ ├── env.sh │ └── files │ │ ├── etc │ │ └── profile.d │ │ │ └── 99-ublue.sh │ │ └── usr │ │ └── bluefin │ │ └── share │ │ └── applications │ │ └── code.desktop ├── neovim │ └── Containerfile.neovim ├── nix │ └── Containerfile.nix ├── vscode │ └── Containerfile.vscode └── wasmtime │ └── Containerfile.wasmtime ├── confext.sh ├── create_caddy_sysext.sh ├── create_docker_sysext.sh ├── create_go_sysext.sh ├── create_incus_sysext.sh ├── create_meta_sysext.sh ├── create_wasmtime_sysext.sh ├── finalize.sh ├── nix_bundle_sysext.sh ├── result └── .gitkeep ├── sysext.sh ├── systemd └── ensure-sysext.service └── withmkosi ├── .gitignore ├── README.md ├── mkosi.conf └── mkosi.images ├── base └── mkosi.conf └── tools ├── mkosi.conf └── mkosi.extra.sysext └── usr └── lib └── extension-release.d └── extension-release.tools /.gitignore: -------------------------------------------------------------------------------- 1 | *.raw 2 | *.tgz 3 | *.tar.gz 4 | /result/*.raw -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | wasmtimeversion := "13.0.0" 2 | neovimversion := "0.9.5" 3 | goversion := "1.21.6" 4 | 5 | _default: 6 | @just --list 7 | 8 | [private] 9 | build-wasmtime: (container "wasmtime") 10 | @echo "Building wasmtime sysext" 11 | @podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/wasmtime:latest /bakery/create_wasmtime_sysext.sh {{wasmtimeversion}} wasmtime >/dev/null 12 | 13 | # install wasmtime 14 | wasmtime: build-wasmtime systemd-sysext 15 | #!/usr/bin/env bash 16 | echo "Installing wasmtime extension, requires elevated permissions" 17 | sudo cp result/wasmtime.raw /var/lib/extensions/wasmtime.raw 18 | echo "Reloading system extensions, requires elevated permissions" 19 | sudo systemd-sysext refresh 20 | systemd-sysext 21 | 22 | # install neovim 23 | neovim: build-neovim systemd-sysext 24 | #!/usr/bin/env bash 25 | echo "Installing neovim extension, requires elevated permissions" 26 | sudo cp result/neovim.raw /var/lib/extensions/neovim.raw 27 | echo "Reloading system extensions, requires elevated permissions" 28 | sudo systemd-sysext refresh 29 | systemd-sysext 30 | 31 | # install vscode 32 | vscode: build-vscode systemd-sysext 33 | #!/usr/bin/env bash 34 | echo "Installing vscode extension, requires elevated permissions" 35 | sudo cp result/vscode.raw /var/lib/extensions/vscode.raw 36 | echo "Reloading system extensions, requires elevated permissions" 37 | sudo systemd-sysext refresh 38 | systemd-sysext 39 | 40 | 41 | # install go 42 | go: build-go systemd-sysext 43 | #!/usr/bin/env bash 44 | echo "Installing go extension, requires elevated permissions" 45 | sudo cp result/go.raw /var/lib/extensions/go.raw 46 | echo "Reloading system extensions, requires elevated permissions" 47 | echo "Add /usr/local/go/bin to your PATH to use go" 48 | sudo systemd-sysext refresh 49 | systemd-sysext 50 | 51 | # install caddy 52 | caddy: build-caddy systemd-sysext 53 | #!/usr/bin/env bash 54 | echo "Installing caddy extension, requires elevated permissions" 55 | sudo cp result/caddy.raw /var/lib/extensions/caddy.raw 56 | echo "Reloading system extensions, requires elevated permissions" 57 | sudo systemd-sysext refresh 58 | systemd-sysext 59 | 60 | # install albafetch from flakehub reference 61 | albafetch: (container "nix") (build-nix "https://flakehub.com/f/alba4k/albafetch/0.1.570.tar.gz" "albafetch") systemd-sysext 62 | #!/usr/bin/env bash 63 | echo "Installing albafetch extension, requires elevated permissions" 64 | sudo cp result/albafetch.raw /var/lib/extensions/albafetch.raw 65 | echo "Reloading system extensions, requires elevated permissions" 66 | sudo systemd-sysext refresh 67 | systemd-sysext 68 | 69 | [private] 70 | build-neovim: (container "neovim") 71 | @echo "Building neovim sysext" 72 | @podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/neovim:latest /bakery/create_neovim_sysext.sh {{neovimversion}} neovim >/dev/null 73 | 74 | [private] 75 | build-caddy: (container "caddy") 76 | @echo "Building caddy sysext" 77 | podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/caddy:latest /bakery/create_caddy_sysext.sh 0.4.0 incus 78 | 79 | [private] 80 | build-incus: (container "incus") 81 | @echo "Building incus sysext" 82 | podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/incus:latest /bakery/create_incus_sysext.sh 0.4.0 incus 83 | 84 | [private] 85 | build-docker: (container "docker") 86 | @echo "Building docker sysext" 87 | podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/docker:latest /bakery/create_docker_sysext.sh 24.0.6 docker 88 | 89 | 90 | [private] 91 | build-go: (container "go") 92 | @echo "Building go sysext" 93 | @podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/go:latest /bakery/create_go_sysext.sh {{goversion}} go >/dev/null 94 | 95 | [private] 96 | build-meta: (container "meta") 97 | @echo "Building meta sysext" 98 | @podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/meta:latest /bakery/create_meta_sysext.sh latest meta 99 | 100 | [private] 101 | build-vscode: (container "vscode") 102 | @echo "Building vscode sysext" 103 | @podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/vscode:latest /bakery/create_vscode_sysext.sh latest vscode >/dev/null 104 | 105 | # remove an installed extension by name `just remove vscode` 106 | remove NAME: 107 | @echo "Removing {{NAME}} extension, requires elevated permissions" 108 | sudo rm -f /var/lib/extensions/{{NAME}}.raw 109 | sudo systemd-sysext refresh 110 | systemd-sysext 111 | 112 | [private] 113 | build-nix FLAKEREF PACKAGE: (container "nix") 114 | podman run --rm -e OS=_any -v `pwd`/result:/bakery/result ${USER}/nix:latest /bakery/nix_bundle_sysext.sh {{FLAKEREF}} {{PACKAGE}} 115 | 116 | 117 | [private] 118 | container NAME: 119 | @echo "Building {{NAME}} container" 120 | @podman build -t ${USER}/{{NAME}}:latest -f builders/{{NAME}}/Containerfile.{{NAME}} . >/dev/null 121 | 122 | [private] 123 | local NAME VERSION: 124 | @echo "Building {{NAME}} locally" 125 | export OS=_any; ./create_{{NAME}}_sysext.sh {{VERSION}} {{NAME}} 126 | 127 | [private] 128 | clean: 129 | @rm -rf result/*.raw 130 | 131 | [private] 132 | build-wasmtime-local: 133 | export OS=_any; ./create_wasmtime_sysext.sh 13.0.0 wasmtime 134 | 135 | [private] 136 | systemd-sysext: 137 | #!/usr/bin/env bash 138 | systemctl --quiet is-enabled systemd-sysext || { echo "enabling systemd-sysext"; sudo systemctl enable --now systemd-sysext.service; } 139 | test -d /var/lib/extensions || { echo "creating /var/lib/extensions"; sudo mkdir -p /var/lib/extensions; } 140 | systemctl --quiet is-enabled systemd-confext || { echo "enabling systemd-confext"; sudo systemctl enable --now systemd-confext.service; } 141 | test -d /var/lib/confexts || { echo "creating /var/lib/confexts"; sudo mkdir -p /var/lib/confexts; } 142 | [private] 143 | sync: 144 | @echo "Syncing to remote" 145 | rsync -av result/ bjk@blue.home.arpa:~/extensions -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ublue systemd-sysext 2 | 3 | Forked from and inspired by [flatcar](https://github.com/flatcar/sysext-bakery) which is licensed Apache 2.0. 4 | 5 | ## Why? 6 | 7 | Installing tools can be too complicated, especially on an immutable distribution like Silverblue or [Bluefin](https://projectbluefin.io). This experiment (ab)uses systemd-sysext to create squashfs filesystems that are mounted at /var/lib/extensions/ that overlay the host's filesystem. Therefore binaries in the extension become available on the host as if they were natively installed. 8 | 9 | Initial experiments include `wasmtime`, `go`, `Visual Studio Code` and `neovim`. It would appear that nearly anything is possible. We intend to explore this as a means to add optional development and quality-of-life tools to immutable Linux distributions, although the concept works anywhere with systemd. 10 | 11 | Do NOT use the `ensure-sysext` system unit recommended below, it blocks the display manager from starting on desktop linux. 12 | 13 | SystemD 255 will fix this limitation. 14 | 15 | ## Prior Art 16 | [Image-Based Linux Summit](https://lwn.net/Articles/946526/) 17 | 18 | 19 | ------- 20 | Original README Follows 21 | 22 | # sysext-bakery: Recipes for baking systemd-sysext images 23 | 24 | [Systemd-sysext images](https://www.freedesktop.org/software/systemd/man/systemd-sysext.html) are overlay images for `/usr`, allowing to extend the base OS with custom (static) binaries. 25 | Flatcar Container Linux as an OS without a package manager is a good fit for extension through systemd-sysext. 26 | The tools in this repository help you to create your own sysext images bundeling software to extend your base OS. 27 | The current focus is on Docker and containerd, contributions are welcome for other software. 28 | 29 | ## Systemd-sysext 30 | 31 | 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`. 32 | 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. 33 | This helper service is bound to `systemd-sysext.service` which activates the sysext images on boot. 34 | 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. 35 | 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). 36 | That means you need to use `Upholds=` drop-ins for the target units to start your units. 37 | At runtime executing `systemctl restart systemd-sysext ensure-sysext` will reload the sysext images and start the services. 38 | A manual `systemd-sysext refresh` is not recommended. 39 | 40 | The compatibility mechanism of sysext images requires a metadata file in the image under `usr/lib/extension-release.d/extension-release.NAME`. 41 | It needs to contain a matching OS `ID`, and either a matching `VERSION_ID` or `SYSEXT_LEVEL`. 42 | 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`. 43 | Instead, Flatcar defined the `SYSEXT_LEVEL` value `1.0` to match for. 44 | With systemd 252 you can also use `ID=_any` and then neither `SYSEXT_LEVEL` nor `VERSION_ID` are needed. 45 | The sysext image should only include static binaries. 46 | 47 | Inside the image, binaries should be placed under `usr/bin/` and systemd units under `usr/lib/systemd/system/`. 48 | While placing symlinks in the image itself to enable the units in the same way as systemd would normally do (like `sockets.target.wants/my.socket` → `../my.socket`) is still currently supported, this is not a recommended practice. 49 | The recommended way is to ship drop-ins for the target units that start your unit. 50 | The drop-in file should use the `Upholds=` property in the `[Unit]` section. 51 | For example, for starting `docker.socket` we would use a drop-in for `sockets.target` placed in `usr/lib/systemd/system/sockets.target.d/10-docker-socket.conf` with the following contents: 52 | 53 | ``` 54 | [Unit] 55 | Upholds=docker.socket 56 | ``` 57 | 58 | This can be done also for services, so for `docker.service` started by `multi-user.target`, the drop-in would reside in `usr/lib/systemd/system/multi-user.target.d/10-docker-service.conf` and it would have a `Upholds=docker.service` line instead. 59 | 60 | 61 | The following Butane Config (YAML) can be be transpiled to Ignition JSON and will download a custom Docker+containerd sysext image on first boot. 62 | It also takes care of disabling Torcx and future inbuild Docker and containerd sysext images we plan to ship in Flatcar. 63 | If your sysext image doesn't replace Flatcar's inbuilt Docker/containerd, omit the two `links` entries and the `torcx-generator` entry. 64 | 65 | ``` 66 | variant: flatcar 67 | version: 1.0.0 68 | storage: 69 | files: 70 | - path: /etc/extensions/mydocker.raw 71 | contents: 72 | source: https://myserver.net/mydocker.raw 73 | - path: /etc/systemd/system-generators/torcx-generator 74 | links: 75 | - path: /etc/extensions/docker-flatcar.raw 76 | target: /dev/null 77 | overwrite: true 78 | - path: /etc/extensions/containerd-flatcar.raw 79 | target: /dev/null 80 | overwrite: true 81 | ``` 82 | 83 | ## Systemd-sysext on other distributions 84 | 85 | The tools here will by default build for Flatcar and create the metadata file `usr/lib/extension-release.d/extension-release.NAME` as follows: 86 | 87 | ``` 88 | ID=flatcar 89 | SYSEXT_LEVEL=1.0 90 | ``` 91 | 92 | This means other distributions will reject to load the sysext image by default. 93 | 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`). 94 | You can also set the architecture to be arm64 to fetch the right binaries and encode this information in the sysext image metadata. 95 | 96 | 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`. 97 | 98 | ## Recipes in this repository 99 | 100 | 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. 101 | 102 | ### Consuming the published images 103 | 104 | 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: 105 | ```yaml 106 | # butane < config.yaml > config.json 107 | # ./flatcar_production_qemu.sh -i ./config.json 108 | variant: flatcar 109 | version: 1.0.0 110 | storage: 111 | files: 112 | - path: /opt/extensions/wasmtime/wasmtime-13.0.0-x86-64.raw 113 | contents: 114 | source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmtime-13.0.0-x86-64.raw 115 | - path: /opt/extensions/docker/docker-24.0.5-x86-64.raw 116 | contents: 117 | source: https://github.com/flatcar/sysext-bakery/releases/download/latest/docker-24.0.5-x86-64.raw 118 | - path: /etc/systemd/system-generators/torcx-generator 119 | - path: /etc/sysupdate.d/noop.conf 120 | contents: 121 | source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf 122 | - path: /etc/sysupdate.wasmtime.d/wasmtime.conf 123 | contents: 124 | source: https://github.com/flatcar/sysext-bakery/releases/download/latest/wasmtime.conf 125 | - path: /etc/sysupdate.docker.d/docker.conf 126 | contents: 127 | source: https://github.com/flatcar/sysext-bakery/releases/download/latest/docker.conf 128 | links: 129 | - target: /opt/extensions/wasmtime/wasmtime-13.0.0-x86-64.raw 130 | path: /etc/extensions/wasmtime.raw 131 | hard: false 132 | - target: /opt/extensions/docker/docker-24.0.5-x86-64.raw 133 | path: /etc/extensions/docker.raw 134 | hard: false 135 | - path: /etc/extensions/docker-flatcar.raw 136 | target: /dev/null 137 | overwrite: true 138 | - path: /etc/extensions/containerd-flatcar.raw 139 | target: /dev/null 140 | overwrite: true 141 | systemd: 142 | units: 143 | - name: systemd-sysupdate.timer 144 | enabled: true 145 | - name: systemd-sysupdate.service 146 | dropins: 147 | - name: wasmtime.conf 148 | contents: | 149 | [Service] 150 | ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C wasmtime update 151 | - name: docker.conf 152 | contents: | 153 | [Service] 154 | ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C docker update 155 | - name: sysext.conf 156 | contents: | 157 | [Service] 158 | ExecStartPost=systemctl restart systemd-sysext 159 | ``` 160 | 161 | This also configures systemd-sysupdate for auto-updates. The `noop.conf` is a workaround for systemd-sysupdate to run without error messages. 162 | 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. 163 | 164 | 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. 165 | 166 | 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. 167 | 168 | ### Creating a custom Docker sysext image 169 | 170 | The Docker releases publish static binaries including containerd and the only missing piece are the systemd units. 171 | 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: 172 | 173 | ``` 174 | ./create_docker_sysext.sh 20.10.13 mydocker 175 | [… writes mydocker.raw into current directory …] 176 | ``` 177 | 178 | Pass the `OS` or `ARCH` environment variables to build for another target than Flatcar amd64, e.g., for any distro with arm64: 179 | 180 | ``` 181 | OS=_any ARCH=arm64 ./create_docker_sysext.sh 20.10.13 mydocker 182 | [… writes mydocker.raw into current directory …] 183 | ``` 184 | 185 | See the above intro section on how to use the resulting sysext image. 186 | 187 | 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`. 188 | 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. 189 | 190 | ### Converting a Torcx image 191 | 192 | Torcx was a solution for switching between different Docker versions on Flatcar. 193 | In case you have an existing Torcx image you can convert it with the `convert_torcx_image.sh` helper script (Currently only Torcx tar balls are supported and the conversion is done on best effort): 194 | 195 | ``` 196 | ./convert_torcx_image.sh TORCXTAR SYSEXTNAME 197 | [… writes SYSEXTNAME.raw into the current directory …] 198 | ``` 199 | 200 | Please make also sure that your don't have a `containerd.service` drop in file under `/etc` that uses Torcx paths. 201 | -------------------------------------------------------------------------------- /build_devtools_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | VERSION="$1" 19 | SYSEXTNAME="$2" 20 | 21 | # The github release uses different arch identifiers, we map them here 22 | # and rely on sysext.sh to map them back to what systemd expects 23 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 24 | ARCH="x86_64" 25 | elif [ "${ARCH}" = "arm64" ]; then 26 | ARCH="aarch64" 27 | fi 28 | 29 | # clean target 30 | 31 | BLUEFINPREFIX="/usr/bluefin" 32 | 33 | cd "${SYSEXTNAME}" 34 | dnf -y --releasever=39 --installroot="${SCRIPTFOLDER}/${SYSEXTNAME}" \ 35 | --repo=fedora --repo=updates --setopt=install_weak_deps=False install \ 36 | gcc 37 | 38 | tree "${SCRIPTFOLDER}/${SYSEXTNAME}" 39 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}" 40 | -------------------------------------------------------------------------------- /build_docker_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | ONLY_CONTAINERD="${ONLY_CONTAINERD:-0}" 7 | ONLY_DOCKER="${ONLY_DOCKER:-0}" 8 | 9 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 10 | echo "Usage: $0 VERSION SYSEXTNAME" 11 | echo "The script will download the Docker release tar ball (e.g., for 20.10.13) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 12 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 13 | echo "All files in the sysext image will be owned by root." 14 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 15 | echo "To only package containerd without Docker, pass ONLY_CONTAINERD=1 as environment variable (current value is '${ONLY_CONTAINERD}')." 16 | echo "To only package Docker without containerd and runc, pass ONLY_DOCKER=1 as environment variable (current value is '${ONLY_DOCKER}')." 17 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 18 | "${SCRIPTFOLDER}"/sysext.sh --help 19 | exit 1 20 | fi 21 | 22 | if [ "${ONLY_CONTAINERD}" = 1 ] && [ "${ONLY_DOCKER}" = 1 ]; then 23 | echo "Cannot set both ONLY_CONTAINERD and ONLY_DOCKER" >&2 24 | exit 1 25 | fi 26 | 27 | VERSION="$1" 28 | SYSEXTNAME="$2" 29 | 30 | # The github release uses different arch identifiers, we map them here 31 | # and rely on sysext.sh to map them back to what systemd expects 32 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 33 | ARCH="x86_64" 34 | elif [ "${ARCH}" = "arm64" ]; then 35 | ARCH="aarch64" 36 | fi 37 | 38 | rm -f "docker-${VERSION}.tgz" 39 | curl -o "docker-${VERSION}.tgz" -fsSL "https://download.docker.com/linux/static/stable/${ARCH}/docker-${VERSION}.tgz" 40 | # TODO: Also allow to consume upstream containerd and runc release binaries with their respective versions 41 | 42 | tar --force-local -xf "docker-${VERSION}.tgz" -C "${SYSEXTNAME}" 43 | rm "docker-${VERSION}.tgz" 44 | mkdir -p "${SYSEXTNAME}"/usr/bin 45 | mv "${SYSEXTNAME}"/docker/* "${SYSEXTNAME}"/usr/bin/ 46 | rmdir "${SYSEXTNAME}"/docker 47 | mkdir -p "${SYSEXTNAME}/usr/lib/systemd/system" 48 | if [ "${ONLY_CONTAINERD}" = 1 ]; then 49 | rm "${SYSEXTNAME}/usr/bin/docker" "${SYSEXTNAME}/usr/bin/dockerd" "${SYSEXTNAME}/usr/bin/docker-init" "${SYSEXTNAME}/usr/bin/docker-proxy" 50 | elif [ "${ONLY_DOCKER}" = 1 ]; then 51 | rm "${SYSEXTNAME}/usr/bin/containerd" "${SYSEXTNAME}/usr/bin/containerd-shim-runc-v2" "${SYSEXTNAME}/usr/bin/ctr" "${SYSEXTNAME}/usr/bin/runc" 52 | if [[ "${VERSION%%.*}" -lt 23 ]] ; then 53 | # Binary releases 23 and higher don't ship containerd-shim 54 | rm "${SYSEXTNAME}/usr/bin/containerd-shim" 55 | fi 56 | fi 57 | rsync -av "${SCRIPTFOLDER}"/builders/docker/files/ "${SYSEXTNAME}"/ 58 | 59 | -------------------------------------------------------------------------------- /build_incus_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | git config --global --add safe.directory /bakery 19 | 20 | VERSION="$1" 21 | SYSEXTNAME="$2" 22 | 23 | pwd 24 | ls -la 25 | . ./builders/"${SYSEXTNAME}"/env.sh 26 | 27 | # The github release uses different arch identifiers, we map them here 28 | # and rely on sysext.sh to map them back to what systemd expects 29 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 30 | ARCH="x86_64" 31 | elif [ "${ARCH}" = "arm64" ]; then 32 | ARCH="aarch64" 33 | fi 34 | 35 | 36 | 37 | BLUEFINPREFIX="/usr/bluefin" 38 | 39 | cd "${SYSEXTNAME}" 40 | git clone https://github.com/cowsql/raft.git 41 | cd raft 42 | git checkout "v${RAFT_VERSION}" 43 | autoreconf -i 44 | ./configure --prefix="${BLUEFINPREFIX}" 45 | make 46 | make install DESTDIR="${SCRIPTFOLDER}/${SYSEXTNAME}" 47 | ls -la "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin 48 | 49 | 50 | cd "${SCRIPTFOLDER}" 51 | pwd 52 | export GOPATH="${SCRIPTFOLDER}/${SYSEXTNAME}" 53 | mkdir -p "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/include 54 | # cowsql 55 | rm -f "cowsql-${COWSQL_VERSION}.tar.gz" 56 | curl -o "cowsql-${COWSQL_VERSION}.tar.gz" -fsSL "https://github.com/cowsql/cowsql/archive/refs/tags/v${COWSQL_VERSION}.tar.gz" 57 | tar --force-local -xzvf "cowsql-${COWSQL_VERSION}.tar.gz" -C "${SYSEXTNAME}" 58 | cd "${SYSEXTNAME}"/cowsql-${COWSQL_VERSION} 59 | export PKG_CONFIG_PATH="${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/lib/pkgconfig" 60 | export CPPFLAGS="-I${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/include -I${SCRIPTFOLDER}/${SYSEXTNAME}/usr/include" 61 | export LD_LIBRARY_PATH="${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/lib" 62 | autoreconf -i 63 | ./configure --prefix="${BLUEFINPREFIX}" 64 | make 65 | make install DESTDIR="${SCRIPTFOLDER}/${SYSEXTNAME}" 66 | 67 | cd "${SCRIPTFOLDER}" 68 | 69 | # lxc 70 | rm -f "lxc-${LXC_VERSION}.tar.gz" 71 | curl -o "lxc-${LXC_VERSION}.tar.gz" -fsSL "https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz" 72 | 73 | tar --no-same-owner --no-same-permissions --force-local -xf "lxc-${LXC_VERSION}.tar.gz" -C "${SYSEXTNAME}" 74 | rm "lxc-${LXC_VERSION}.tar.gz" 75 | 76 | cd "${SYSEXTNAME}"/lxc-${LXC_VERSION} 77 | 78 | meson setup --prefix="${BLUEFINPREFIX}" build/ 79 | ninja -C build/ 80 | 81 | make install DESTDIR="${SCRIPTFOLDER}/${SYSEXTNAME}" 82 | 83 | # lxcfs 84 | cd "${SCRIPTFOLDER}" 85 | rm -f "lxcfs-${LXCFS_VERSION}.tar.gz" 86 | curl -o "lxcfs-${LXCFS_VERSION}.tar.gz" -fsSL "https://linuxcontainers.org/downloads/lxcfs/lxcfs-${LXCFS_VERSION}.tar.gz" 87 | 88 | tar --no-same-owner --no-same-permissions --force-local -xf "lxcfs-${LXCFS_VERSION}.tar.gz" -C "${SYSEXTNAME}" 89 | rm "lxcfs-${LXCFS_VERSION}.tar.gz" 90 | cd "${SYSEXTNAME}"/lxcfs-${LXCFS_VERSION} 91 | 92 | meson setup --prefix="${BLUEFINPREFIX}" build/ 93 | ninja -C build/ 94 | make install DESTDIR="${SCRIPTFOLDER}/${SYSEXTNAME}" 95 | 96 | echo "lxcfs done" 97 | 98 | # incus 99 | cd "${SCRIPTFOLDER}" 100 | 101 | rm -f "incus-${VERSION}.tar.xz" 102 | POINTTWO=${VERSION%.*} 103 | 104 | # source 105 | curl -o "incus-${VERSION}.tar.xz" -fsSL "https://github.com/lxc/incus/releases/download/v${VERSION}/incus-${POINTTWO}.tar.xz" 106 | # TODO: Also allow to consume upstream containerd and runc release binaries with their respective versions 107 | 108 | tar --no-same-owner --no-same-permissions --force-local -xf "incus-${VERSION}.tar.xz" -C "${SYSEXTNAME}" 109 | rm "incus-${VERSION}.tar.xz" 110 | mkdir -p "${SYSEXTNAME}"/usr/bluefin/bin 111 | 112 | cd "${SYSEXTNAME}"/incus-${POINTTWO} 113 | #make deps 114 | export CGO_CFLAGS="-I${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/include" 115 | export CGO_LDFLAGS="-L${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/lib/" 116 | export CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)" 117 | make 118 | cp "${GOPATH}/bin/incus" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 119 | cp "${GOPATH}/bin/incusd" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 120 | cp "${GOPATH}/bin/fuidshift" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 121 | cp "${GOPATH}/bin/generate" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 122 | cp "${GOPATH}/bin/incus-agent" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 123 | cp "${GOPATH}/bin/incus-benchmark" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 124 | cp "${GOPATH}/bin/incus-migrate" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 125 | cp "${GOPATH}/bin/incus-user" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 126 | cp "${GOPATH}/bin/lxc-to-incus" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 127 | cp "${GOPATH}/bin/lxd-to-incus" "${SCRIPTFOLDER}/${SYSEXTNAME}/usr/bluefin/bin/" 128 | 129 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}" 130 | rm -rf cowsql-${COWSQL_VERSION} 131 | rm -rf incus-${POINTTWO} 132 | rm -rf pkg 133 | rm -rf bin 134 | rm -rf raft 135 | 136 | #rmdir "${SYSEXTNAME}"/docker 137 | #mkdir -p "${SYSEXTNAME}/usr/lib/systemd/system" 138 | #if [ "${ONLY_CONTAINERD}" = 1 ]; then 139 | # rm "${SYSEXTNAME}/usr/bin/docker" "${SYSEXTNAME}/usr/bin/dockerd" "${SYSEXTNAME}/usr/bin/docker-init" "${SYSEXTNAME}/usr/bin/docker-proxy" 140 | #elif [ "${ONLY_DOCKER}" = 1 ]; then 141 | # rm "${SYSEXTNAME}/usr/bin/containerd" "${SYSEXTNAME}/usr/bin/containerd-shim-runc-v2" "${SYSEXTNAME}/usr/bin/ctr" "${SYSEXTNAME}/usr/bin/runc" 142 | # if [[ "${VERSION%%.*}" -lt 23 ]] ; then 143 | # # Binary releases 23 and higher don't ship containerd-shim 144 | # rm "${SYSEXTNAME}/usr/bin/containerd-shim" 145 | # fi 146 | #fi 147 | #if [ "${ONLY_CONTAINERD}" != 1 ]; then 148 | # cat > "${SYSEXTNAME}/usr/lib/systemd/system/docker.socket" <<-'EOF' 149 | # [Unit] 150 | # PartOf=docker.service 151 | # Description=Docker Socket for the API 152 | # [Socket] 153 | # ListenStream=/var/run/docker.sock 154 | # SocketMode=0660 155 | # SocketUser=root 156 | # SocketGroup=docker 157 | # [Install] 158 | # WantedBy=sockets.target 159 | # EOF 160 | # mkdir -p "${SYSEXTNAME}/usr/lib/systemd/system/sockets.target.d" 161 | # { echo "[Unit]"; echo "Upholds=docker.socket"; } > "${SYSEXTNAME}/usr/lib/systemd/system/sockets.target.d/10-docker-socket.conf" 162 | # cat > "${SYSEXTNAME}/usr/lib/systemd/system/docker.service" <<-'EOF' 163 | # [Unit] 164 | # Description=Docker Application Container Engine 165 | # After=containerd.service docker.socket network-online.target 166 | # Wants=network-online.target 167 | # Requires=containerd.service docker.socket 168 | # [Service] 169 | # Type=notify 170 | # EnvironmentFile=-/run/flannel/flannel_docker_opts.env 171 | # Environment=DOCKER_SELINUX=--selinux-enabled=true 172 | # ExecStart=/usr/bin/dockerd --host=fd:// --containerd=/run/containerd/containerd.sock $DOCKER_SELINUX $DOCKER_OPTS $DOCKER_CGROUPS $DOCKER_OPT_BIP $DOCKER_OPT_MTU $DOCKER_OPT_IPMASQ 173 | # ExecReload=/bin/kill -s HUP $MAINPID 174 | # LimitNOFILE=1048576 175 | # # Having non-zero Limit*s causes performance problems due to accounting overhead 176 | # # in the kernel. We recommend using cgroups to do container-local accounting. 177 | # LimitNPROC=infinity 178 | # LimitCORE=infinity 179 | # # Uncomment TasksMax if your systemd version supports it. 180 | # # Only systemd 226 and above support this version. 181 | # TasksMax=infinity 182 | # TimeoutStartSec=0 183 | # # set delegate yes so that systemd does not reset the cgroups of docker containers 184 | # Delegate=yes 185 | # # kill only the docker process, not all processes in the cgroup 186 | # KillMode=process 187 | # # restart the docker process if it exits prematurely 188 | # Restart=on-failure 189 | # StartLimitBurst=3 190 | # StartLimitInterval=60s 191 | # [Install] 192 | # WantedBy=multi-user.target 193 | # EOF 194 | # fi 195 | # if [ "${ONLY_DOCKER}" != 1 ]; then 196 | # cat > "${SYSEXTNAME}/usr/lib/systemd/system/containerd.service" <<-'EOF' 197 | # [Unit] 198 | # Description=containerd container runtime 199 | # After=network.target 200 | # [Service] 201 | # Delegate=yes 202 | # Environment=CONTAINERD_CONFIG=/usr/share/containerd/config.toml 203 | # ExecStartPre=mkdir -p /run/docker/libcontainerd 204 | # ExecStartPre=ln -fs /run/containerd/containerd.sock /run/docker/libcontainerd/docker-containerd.sock 205 | # ExecStart=/usr/bin/containerd --config ${CONTAINERD_CONFIG} 206 | # KillMode=process 207 | # Restart=always 208 | # # (lack of) limits from the upstream docker service unit 209 | # LimitNOFILE=1048576 210 | # LimitNPROC=infinity 211 | # LimitCORE=infinity 212 | # TasksMax=infinity 213 | # [Install] 214 | # WantedBy=multi-user.target 215 | # EOF 216 | # mkdir -p "${SYSEXTNAME}/usr/lib/systemd/system/multi-user.target.d" 217 | # { echo "[Unit]"; echo "Upholds=containerd.service"; } > "${SYSEXTNAME}/usr/lib/systemd/system/multi-user.target.d/10-containerd-service.conf" 218 | # mkdir -p "${SYSEXTNAME}/usr/share/containerd" 219 | # cat > "${SYSEXTNAME}/usr/share/containerd/config.toml" <<-'EOF' 220 | # version = 2 221 | # # set containerd's OOM score 222 | # oom_score = -999 223 | # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 224 | # # setting runc.options unsets parent settings 225 | # runtime_type = "io.containerd.runc.v2" 226 | # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 227 | # SystemdCgroup = true 228 | # EOF 229 | # sed 's/SystemdCgroup = true/SystemdCgroup = false/g' "${SYSEXTNAME}/usr/share/containerd/config.toml" > "${SYSEXTNAME}/usr/share/containerd/config-cgroupfs.toml" 230 | # fi 231 | -------------------------------------------------------------------------------- /build_neovim_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | VERSION="$1" 19 | SYSEXTNAME="$2" 20 | 21 | # The github release uses different arch identifiers, we map them here 22 | # and rely on sysext.sh to map them back to what systemd expects 23 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 24 | ARCH="x86_64" 25 | elif [ "${ARCH}" = "arm64" ]; then 26 | ARCH="aarch64" 27 | fi 28 | 29 | # clean target 30 | 31 | BLUEFINPREFIX="/usr/bluefin" 32 | 33 | cd "${SYSEXTNAME}" 34 | git clone https://github.com/neovim/neovim.git 35 | cd neovim 36 | git checkout "v${VERSION}" 37 | #TODO add prefix here 38 | make CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=${BLUEFINPREFIX}" 39 | 40 | make CMAKE_BUILD_TYPE=Release 41 | sudo make install DESTDIR="${SCRIPTFOLDER}/${SYSEXTNAME}" 42 | 43 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}" 44 | # remove cloned repo 45 | rm -rf neovim 46 | 47 | -------------------------------------------------------------------------------- /build_vscode_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | VERSION="$1" 19 | SYSEXTNAME="$2" 20 | 21 | # The github release uses different arch identifiers, we map them here 22 | # and rely on sysext.sh to map them back to what systemd expects 23 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 24 | ARCH="x86_64" 25 | elif [ "${ARCH}" = "arm64" ]; then 26 | ARCH="aarch64" 27 | fi 28 | 29 | # clean target 30 | 31 | 32 | cd "${SYSEXTNAME}" 33 | curl -o "vscode.tar.gz" -fsSL "https://code.visualstudio.com/sha/download?build=stable&os=linux-x64" 34 | 35 | tar -xzf vscode.tar.gz 36 | rm vscode.tar.gz 37 | mkdir -p "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/share/ 38 | mv VSCode-linux-x64 "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/share/code 39 | mkdir -p "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/bin 40 | mkdir -p "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/share/icons 41 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/bin 42 | ln -s ../share/code/bin/code code 43 | 44 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}"/usr/bluefin/share/icons 45 | ln -s ../code/resources/app/resources/linux/code.png vscode.png 46 | cd "${SCRIPTFOLDER}/${SYSEXTNAME}" 47 | 48 | -------------------------------------------------------------------------------- /builders/caddy/Containerfile.caddy: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools 5 | 6 | COPY . /bakery 7 | COPY --from=cgr.dev/chainguard/caddy:latest /usr/bin/caddy /bakery/chainguard/caddy 8 | COPY --from=cgr.dev/chainguard/caddy:latest /usr/share/caddy/index.html /bakery/chainguard/index.html 9 | 10 | RUN chown -R 1000:1000 /bakery 11 | WORKDIR /bakery 12 | 13 | 14 | -------------------------------------------------------------------------------- /builders/docker/Containerfile.docker: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools curl wget rsync 5 | 6 | COPY . /bakery 7 | RUN chown -R 1000:1000 /bakery 8 | WORKDIR /bakery 9 | 10 | -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system-preset/30-ublue.preset: -------------------------------------------------------------------------------- 1 | enable docker.socket 2 | enable containerd.service 3 | enable docker.service -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system/containerd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=containerd container runtime 3 | After=network.target 4 | [Service] 5 | Delegate=yes 6 | Environment=CONTAINERD_CONFIG=/usr/share/containerd/config.toml 7 | ExecStartPre=mkdir -p /run/docker/libcontainerd 8 | ExecStartPre=ln -fs /run/containerd/containerd.sock /run/docker/libcontainerd/docker-containerd.sock 9 | ExecStart=/usr/bin/containerd --config ${CONTAINERD_CONFIG} 10 | KillMode=process 11 | Restart=always 12 | # (lack of) limits from the upstream docker service unit 13 | LimitNOFILE=1048576 14 | LimitNPROC=infinity 15 | LimitCORE=infinity 16 | TasksMax=infinity 17 | [Install] 18 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system/docker.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Docker Application Container Engine 3 | After=containerd.service docker.socket network-online.target 4 | Wants=network-online.target 5 | Requires=containerd.service docker.socket 6 | [Service] 7 | Type=notify 8 | EnvironmentFile=-/run/flannel/flannel_docker_opts.env 9 | Environment=DOCKER_SELINUX=--selinux-enabled=true 10 | ExecStart=/usr/bin/dockerd --host=fd:// --containerd=/run/containerd/containerd.sock $DOCKER_SELINUX $DOCKER_OPTS $DOCKER_CGROUPS $DOCKER_OPT_BIP $DOCKER_OPT_MTU $DOCKER_OPT_IPMASQ 11 | ExecReload=/bin/kill -s HUP $MAINPID 12 | LimitNOFILE=1048576 13 | # Having non-zero Limit*s causes performance problems due to accounting overhead 14 | # in the kernel. We recommend using cgroups to do container-local accounting. 15 | LimitNPROC=infinity 16 | LimitCORE=infinity 17 | # Uncomment TasksMax if your systemd version supports it. 18 | # Only systemd 226 and above support this version. 19 | TasksMax=infinity 20 | TimeoutStartSec=0 21 | # set delegate yes so that systemd does not reset the cgroups of docker containers 22 | Delegate=yes 23 | # kill only the docker process, not all processes in the cgroup 24 | KillMode=process 25 | # restart the docker process if it exits prematurely 26 | Restart=on-failure 27 | StartLimitBurst=3 28 | StartLimitInterval=60s 29 | [Install] 30 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system/docker.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | PartOf=docker.service 3 | Description=Docker Socket for the API 4 | [Socket] 5 | ListenStream=/var/run/docker.sock 6 | SocketMode=0660 7 | SocketUser=root 8 | SocketGroup=docker 9 | [Install] 10 | WantedBy=sockets.target -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system/multi-user.target.d/10-containerd-service.conf: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Upholds=containerd.service -------------------------------------------------------------------------------- /builders/docker/files/usr/lib/systemd/system/sockets.target.d/10-docker-socket.conf: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Upholds=docker.socket -------------------------------------------------------------------------------- /builders/docker/files/usr/share/containerd/config-cgroupfs.toml: -------------------------------------------------------------------------------- 1 | version = 2 2 | # set containerd's OOM score 3 | oom_score = -999 4 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 5 | # setting runc.options unsets parent settings 6 | runtime_type = "io.containerd.runc.v2" 7 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 8 | SystemdCgroup = false -------------------------------------------------------------------------------- /builders/docker/files/usr/share/containerd/config.toml: -------------------------------------------------------------------------------- 1 | version = 2 2 | # set containerd's OOM score 3 | oom_score = -999 4 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 5 | # setting runc.options unsets parent settings 6 | runtime_type = "io.containerd.runc.v2" 7 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 8 | SystemdCgroup = true -------------------------------------------------------------------------------- /builders/go/Containerfile.go: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools 5 | 6 | COPY . /bakery 7 | RUN chown -R 1000:1000 /bakery 8 | WORKDIR /bakery 9 | 10 | -------------------------------------------------------------------------------- /builders/incus/Containerfile.incus: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | #COPY incus.dnf.sh /tmp 4 | #RUN /tmp/incus.dnf.sh 5 | 6 | RUN dnf install -y xz squashfs-tools libtool sqlite-devel libuv-devel golang-go lxc-devel libudev-devel libtool \ 7 | && dnf groupinstall -y "Development Tools" "Development Libraries" \ 8 | && dnf install -y meson docbook2X doxygen kernel-headers openssl-devel pam-devel libcap-devel libseccomp-devel \ 9 | help2man fuse3-devel python3 python-jinja2 libselinux-devel systemd-devel libcap-static glibc-static 10 | 11 | COPY . /bakery 12 | RUN chown -R 1000:1000 /bakery 13 | WORKDIR /bakery 14 | 15 | -------------------------------------------------------------------------------- /builders/incus/env.sh: -------------------------------------------------------------------------------- 1 | export RAFT_VERSION=0.19.1 2 | export COWSQL_VERSION=1.15.4 3 | 4 | export LXC_VERSION=5.0.3 5 | export LXCFS_VERSION=5.0.4 -------------------------------------------------------------------------------- /builders/meta/Containerfile.meta: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | #COPY incus.dnf.sh /tmp 4 | #RUN /tmp/incus.dnf.sh 5 | 6 | RUN dnf install -y xz squashfs-tools libtool sqlite-devel libuv-devel golang-go lxc-devel libudev-devel libtool \ 7 | && dnf groupinstall -y "Development Tools" "Development Libraries" \ 8 | && dnf install -y meson docbook2X doxygen kernel-headers openssl-devel pam-devel libcap-devel libseccomp-devel \ 9 | help2man fuse3-devel python3 python-jinja2 libselinux-devel systemd-devel libcap-static glibc-static \ 10 | ninja-build cmake gcc make unzip gettext curl glibc-gconv-extra rsync tree 11 | 12 | COPY . /bakery 13 | RUN chown -R 1000:1000 /bakery 14 | WORKDIR /bakery 15 | 16 | -------------------------------------------------------------------------------- /builders/meta/env.sh: -------------------------------------------------------------------------------- 1 | export RAFT_VERSION=0.19.1 2 | export COWSQL_VERSION=1.15.4 3 | 4 | export LXC_VERSION=5.0.3 5 | export LXCFS_VERSION=5.0.4 -------------------------------------------------------------------------------- /builders/meta/files/etc/profile.d/99-ublue.sh: -------------------------------------------------------------------------------- 1 | export PATH="$PATH:/usr/bluefin/bin" 2 | XDG_DATA_DIRS="/usr/bluefin/share:$XDG_DATA_DIRS" 3 | export XDG_DATA_DIRS -------------------------------------------------------------------------------- /builders/meta/files/usr/bluefin/share/applications/code.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Visual Studio Code 3 | Comment=Code Editing. Redefined. 4 | GenericName=Text Editor 5 | Exec=/usr/bluefin/share/code/code --unity-launch %F 6 | Icon=vscode 7 | Type=Application 8 | StartupNotify=false 9 | StartupWMClass=Code 10 | Categories=TextEditor;Development;IDE; 11 | MimeType=text/plain;inode/directory;application/x-code-workspace; 12 | Actions=new-empty-window; 13 | Keywords=vscode; 14 | 15 | [Desktop Action new-empty-window] 16 | Name=New Empty Window 17 | Name[de]=Neues leeres Fenster 18 | Name[es]=Nueva ventana vacía 19 | Name[fr]=Nouvelle fenêtre vide 20 | Name[it]=Nuova finestra vuota 21 | Name[ja]=新しい空のウィンドウ 22 | Name[ko]=새 빈 창 23 | Name[ru]=Новое пустое окно 24 | Name[zh_CN]=新建空窗口 25 | Name[zh_TW]=開新空視窗 26 | Exec=/usr/bluefin/share/code/code --new-window %F 27 | Icon=vscode 28 | -------------------------------------------------------------------------------- /builders/neovim/Containerfile.neovim: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools git ninja-build cmake gcc make unzip gettext curl glibc-gconv-extra 5 | 6 | COPY . /bakery 7 | RUN chown -R 1000:1000 /bakery 8 | WORKDIR /bakery 9 | 10 | -------------------------------------------------------------------------------- /builders/nix/Containerfile.nix: -------------------------------------------------------------------------------- 1 | FROM nixos/nix 2 | 3 | COPY . /bakery 4 | RUN chown -R 1000:1000 /bakery 5 | WORKDIR /bakery 6 | 7 | RUN nix-channel --update 8 | RUN nix-env -iA nixpkgs.squashfsTools 9 | -------------------------------------------------------------------------------- /builders/vscode/Containerfile.vscode: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools curl wget 5 | 6 | COPY . /bakery 7 | RUN chown -R 1000:1000 /bakery 8 | WORKDIR /bakery 9 | 10 | -------------------------------------------------------------------------------- /builders/wasmtime/Containerfile.wasmtime: -------------------------------------------------------------------------------- 1 | FROM fedora:latest 2 | 3 | 4 | RUN dnf install -y xz squashfs-tools 5 | 6 | COPY . /bakery 7 | RUN chown -R 1000:1000 /bakery 8 | WORKDIR /bakery 9 | 10 | -------------------------------------------------------------------------------- /confext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | OS="${OS-flatcar}" 5 | FORMAT="${FORMAT:-squashfs}" 6 | ARCH="${ARCH-}" 7 | SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH-0}" 8 | export SOURCE_DATE_EPOCH 9 | 10 | # This script is to be called as helper by other scripts but can also be used standalone 11 | if [ $# -lt 1 ]; then 12 | echo "Usage: $0 SYSEXTNAME" 13 | echo "The script will make a SYSEXTNAME.confext.raw image of the folder SYSEXTNAME, and create an os-release file in it, run with --help for the list of supported environment variables." 14 | exit 1 15 | elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 16 | echo "If ARCH is specified as environment variable the sysext image will be required to run on the given architecture." 17 | 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." 18 | 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')." 19 | 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." 20 | echo "To make builds reproducible the SOURCE_DATE_EPOCH environment variable will be set to 0 if not defined." 21 | echo 22 | exit 1 23 | fi 24 | 25 | SYSEXTNAME="$1" 26 | 27 | if [ "${FORMAT}" != "squashfs" ] && [ "${FORMAT}" != "btrfs" ] && [ "${FORMAT}" != "ext4" ] && [ "${FORMAT}" != "ext2" ]; then 28 | echo "Expected FORMAT=squashfs, FORMAT=btrfs, FORMAT=ext4, or FORMAT=ext2, got '${FORMAT}'" >&2 29 | exit 1 30 | fi 31 | 32 | # Map to valid values for https://www.freedesktop.org/software/systemd/man/os-release.html#ARCHITECTURE= 33 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86_64" ]; then 34 | ARCH="x86-64" 35 | elif [ "${ARCH}" = "aarch64" ]; then 36 | ARCH="arm64" 37 | fi 38 | 39 | # TODO fix for confext path 40 | # /etc/extension-release.d/extension-release. 41 | 42 | mkdir -p "${SYSEXTNAME}/etc/extension-release.d" 43 | { 44 | echo "ID=${OS}" 45 | if [ "${OS}" != "_any" ]; then 46 | echo "SYSEXT_LEVEL=1.0" 47 | fi 48 | if [ "${ARCH}" != "" ]; then 49 | echo "ARCHITECTURE=${ARCH}" 50 | fi 51 | } >"${SYSEXTNAME}/etc/extension-release.d/extension-release.${SYSEXTNAME}.confext" 52 | rm -f "${SYSEXTNAME}".confext.raw 53 | if [ "${FORMAT}" = "btrfs" ]; then 54 | # Note: We didn't chown to root:root, meaning that the file ownership is left as is 55 | mkfs.btrfs --mixed -m single -d single --shrink --rootdir "${SYSEXTNAME}" "${SYSEXTNAME}".confext.raw 56 | # This is for testing purposes and makes not much sense to use because --rootdir doesn't allow to enable compression 57 | elif [ "${FORMAT}" = "ext4" ] || [ "${FORMAT}" = "ext2" ]; then 58 | # Assuming that 1 GB is enough 59 | truncate -s 1G "${SYSEXTNAME}".confext.raw 60 | # Note: We didn't chown to root:root, meaning that the file ownership is left as is 61 | mkfs."${FORMAT}" -E root_owner=0:0 -d "${SYSEXTNAME}" "${SYSEXTNAME}".raw 62 | resize2fs -M "${SYSEXTNAME}".confext.raw 63 | else 64 | mksquashfs "${SYSEXTNAME}" "${SYSEXTNAME}".confext.raw -all-root 65 | fi 66 | echo "Created ${SYSEXTNAME}.confext.raw" 67 | -------------------------------------------------------------------------------- /create_caddy_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the wasmtime release tar ball (e.g., for 4.0.0) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 13 | "${SCRIPTFOLDER}"/sysext.sh --help 14 | exit 1 15 | fi 16 | 17 | VERSION="$1" 18 | SYSEXTNAME="$2" 19 | 20 | # The github release uses different arch identifiers, we map them here 21 | # and rely on sysext.sh to map them back to what systemd expects 22 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 23 | ARCH="x86_64" 24 | elif [ "${ARCH}" = "arm64" ]; then 25 | ARCH="aarch64" 26 | fi 27 | 28 | rm -rf "${SYSEXTNAME}" 29 | mkdir -p "${SYSEXTNAME}" 30 | 31 | ls -la /bakery/chainguard 32 | 33 | mkdir -p "${SYSEXTNAME}"/usr/bin 34 | 35 | mkdir -p "${SYSEXTNAME}"/usr/share/caddy 36 | 37 | cp /bakery/chainguard/caddy "${SYSEXTNAME}"/usr/bin/ 38 | cp /bakery/chainguard/index.html "${SYSEXTNAME}"/usr/share/caddy/ 39 | 40 | "${SCRIPTFOLDER}"/sysext.sh "${SYSEXTNAME}" 41 | mkdir -p result 42 | mv "${SYSEXTNAME}.raw" result/ 43 | rm -rf "${SYSEXTNAME}" 44 | -------------------------------------------------------------------------------- /create_docker_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | 19 | VERSION="$1" 20 | SYSEXTNAME="$2" 21 | 22 | pwd 23 | ls -la 24 | 25 | # The github release uses different arch identifiers, we map them here 26 | # and rely on sysext.sh to map them back to what systemd expects 27 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 28 | ARCH="x86_64" 29 | elif [ "${ARCH}" = "arm64" ]; then 30 | ARCH="aarch64" 31 | fi 32 | 33 | # clean target 34 | rm -rf "${SYSEXTNAME}" 35 | mkdir -p "${SYSEXTNAME}" 36 | 37 | BLUEFINPREFIX="/usr/bluefin" 38 | "${SCRIPTFOLDER}"/build_docker_sysext.sh 24.0.6 "${SYSEXTNAME}" 39 | 40 | cd "${SCRIPTFOLDER}" 41 | "${SCRIPTFOLDER}"/finalize.sh "${VERSION}" "${SYSEXTNAME}" 42 | 43 | -------------------------------------------------------------------------------- /create_go_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the wasmtime release tar ball (e.g., for 4.0.0) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 13 | "${SCRIPTFOLDER}"/sysext.sh --help 14 | exit 1 15 | fi 16 | 17 | VERSION="$1" 18 | SYSEXTNAME="$2" 19 | 20 | # The github release uses different arch identifiers, we map them here 21 | # and rely on sysext.sh to map them back to what systemd expects 22 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 23 | ARCH="x86_64" 24 | elif [ "${ARCH}" = "arm64" ]; then 25 | ARCH="aarch64" 26 | fi 27 | 28 | rm -f "go${VERSION}.linux-amd64.tar.xz" 29 | 30 | curl -o "go${VERSION}.linux-amd64.tar.xz" -fsSL "https://go.dev/dl/go${VERSION}.linux-amd64.tar.gz" 31 | rm -rf "${SYSEXTNAME}" 32 | mkdir -p "${SYSEXTNAME}"/usr/local 33 | tar --force-local -xzf "go${VERSION}.linux-amd64.tar.xz" -C "${SYSEXTNAME}"/usr/local 34 | rm -f "go${VERSION}.linux-amd64.tar.xz" 35 | "${SCRIPTFOLDER}"/sysext.sh "${SYSEXTNAME}" 36 | mkdir -p result 37 | mv "${SYSEXTNAME}.raw" result/ 38 | rm -rf "${SYSEXTNAME}" 39 | -------------------------------------------------------------------------------- /create_incus_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | git config --global --add safe.directory /bakery 19 | 20 | VERSION="$1" 21 | SYSEXTNAME="$2" 22 | 23 | pwd 24 | ls -la 25 | . ./builders/"${SYSEXTNAME}"/env.sh 26 | 27 | # The github release uses different arch identifiers, we map them here 28 | # and rely on sysext.sh to map them back to what systemd expects 29 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 30 | ARCH="x86_64" 31 | elif [ "${ARCH}" = "arm64" ]; then 32 | ARCH="aarch64" 33 | fi 34 | 35 | # clean target 36 | rm -rf "${SYSEXTNAME}" 37 | mkdir -p "${SYSEXTNAME}" 38 | 39 | BLUEFINPREFIX="/usr/bluefin" 40 | "${SCRIPTFOLDER}"/build_incus_sysext.sh 0.4.0 "${SYSEXTNAME}" 41 | 42 | cd "${SCRIPTFOLDER}" 43 | "${SCRIPTFOLDER}"/finalize.sh "${VERSION}" "${SYSEXTNAME}" 44 | 45 | -------------------------------------------------------------------------------- /create_meta_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the Incus release tar ball (e.g., for 0.4) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "The necessary systemd services will be created by this script, by default only docker.socket will be enabled." 13 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 14 | "${SCRIPTFOLDER}"/sysext.sh --help 15 | exit 1 16 | fi 17 | 18 | git config --global --add safe.directory /bakery 19 | 20 | VERSION="$1" 21 | SYSEXTNAME="$2" 22 | 23 | pwd 24 | ls -la 25 | . ./builders/"${SYSEXTNAME}"/env.sh 26 | 27 | # The github release uses different arch identifiers, we map them here 28 | # and rely on sysext.sh to map them back to what systemd expects 29 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 30 | ARCH="x86_64" 31 | elif [ "${ARCH}" = "arm64" ]; then 32 | ARCH="aarch64" 33 | fi 34 | 35 | # clean target 36 | rm -rf "${SYSEXTNAME}" 37 | mkdir -p "${SYSEXTNAME}" 38 | 39 | BLUEFINPREFIX="/usr/bluefin" 40 | "${SCRIPTFOLDER}"/build_vscode_sysext.sh "${VERSION}" "${SYSEXTNAME}" 41 | "${SCRIPTFOLDER}"/build_neovim_sysext.sh 0.9.5 "${SYSEXTNAME}" 42 | "${SCRIPTFOLDER}"/build_docker_sysext.sh 24.0.6 "${SYSEXTNAME}" 43 | #"${SCRIPTFOLDER}"/build_devtools_sysext.sh unused "${SYSEXTNAME}" 44 | rsync -av "${SCRIPTFOLDER}"/builders/meta/files/ "${SYSEXTNAME}"/ 45 | 46 | 47 | cd "${SCRIPTFOLDER}" 48 | "${SCRIPTFOLDER}"/finalize.sh "${VERSION}" "${SYSEXTNAME}" 49 | 50 | -------------------------------------------------------------------------------- /create_wasmtime_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 VERSION SYSEXTNAME" 9 | echo "The script will download the wasmtime release tar ball (e.g., for 4.0.0) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 13 | "${SCRIPTFOLDER}"/sysext.sh --help 14 | exit 1 15 | fi 16 | 17 | VERSION="$1" 18 | SYSEXTNAME="$2" 19 | 20 | # The github release uses different arch identifiers, we map them here 21 | # and rely on sysext.sh to map them back to what systemd expects 22 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 23 | ARCH="x86_64" 24 | elif [ "${ARCH}" = "arm64" ]; then 25 | ARCH="aarch64" 26 | fi 27 | 28 | rm -f "wasmtime-${VERSION}.tar.xz" 29 | curl -o "wasmtime-${VERSION}.tar.xz" -fsSL "https://github.com/bytecodealliance/wasmtime/releases/download/v${VERSION}/wasmtime-v${VERSION}-${ARCH}-linux.tar.xz" 30 | rm -rf "${SYSEXTNAME}" 31 | mkdir -p "${SYSEXTNAME}" 32 | tar --force-local -xf "wasmtime-${VERSION}.tar.xz" -C "${SYSEXTNAME}" 33 | rm "wasmtime-${VERSION}.tar.xz" 34 | mkdir -p "${SYSEXTNAME}"/usr/bin 35 | mv "${SYSEXTNAME}"/"wasmtime-v${VERSION}-${ARCH}-linux"/wasmtime "${SYSEXTNAME}"/usr/bin/ 36 | rm -r "${SYSEXTNAME}"/"wasmtime-v${VERSION}-${ARCH}-linux" 37 | "${SCRIPTFOLDER}"/sysext.sh "${SYSEXTNAME}" 38 | mkdir -p result 39 | mv "${SYSEXTNAME}.raw" result/ 40 | rm -rf "${SYSEXTNAME}" 41 | -------------------------------------------------------------------------------- /finalize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | 8 | VERSION="$1" 9 | SYSEXTNAME="$2" 10 | 11 | 12 | 13 | cd "${SCRIPTFOLDER}" 14 | # make the sysext 15 | "${SCRIPTFOLDER}"/sysext.sh "${SYSEXTNAME}" 16 | 17 | # remove the usr folder so only the etc folder is left 18 | rm -rf "${SYSEXTNAME}"/usr 19 | 20 | ls -la "${SYSEXTNAME}" 21 | # make the result folder 22 | mkdir -p result 23 | 24 | # if there are files in SYSEXTNAME/etc, call the confext.sh script too 25 | if [ "$(ls -A "${SYSEXTNAME}"/etc)" ]; then 26 | "${SCRIPTFOLDER}"/confext.sh "${SYSEXTNAME}" 27 | # move the result to the result folder 28 | mv "${SYSEXTNAME}.confext.raw" result/ 29 | fi 30 | 31 | mv "${SYSEXTNAME}.sysext.raw" result/ 32 | rm -rf "${SYSEXTNAME}" 33 | -------------------------------------------------------------------------------- /nix_bundle_sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | export ARCH="${ARCH-x86-64}" 5 | SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")" 6 | 7 | if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 8 | echo "Usage: $0 SYSEXTNAME" 9 | echo "The script will export a nix derivation for FLAKEREF and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder." 10 | echo "A temporary directory named SYSEXTNAME in the current folder will be created and deleted again." 11 | echo "All files in the sysext image will be owned by root." 12 | echo "To use arm64 pass 'ARCH=arm64' as environment variable (current value is '${ARCH}')." 13 | "${SCRIPTFOLDER}"/sysext.sh --help 14 | exit 1 15 | fi 16 | 17 | FLAKEREF="$1" 18 | SYSEXTNAME="$2" 19 | 20 | # The github release uses different arch identifiers, we map them here 21 | # and rely on sysext.sh to map them back to what systemd expects 22 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86-64" ]; then 23 | ARCH="x86_64" 24 | elif [ "${ARCH}" = "arm64" ]; then 25 | ARCH="aarch64" 26 | fi 27 | 28 | # clean target 29 | rm -rf "${SYSEXTNAME}" 30 | mkdir -p "${SYSEXTNAME}" 31 | 32 | cd "${SYSEXTNAME}" 33 | #nix things here 34 | nix bundle "${FLAKEREF}" --extra-experimental-features nix-command --extra-experimental-features flakes 35 | pwd 36 | ls -la 37 | target=$(readlink -f "${SYSEXTNAME}") 38 | echo $target 39 | 40 | cd "${SCRIPTFOLDER}" 41 | mkdir -p "${SYSEXTNAME}"/usr/local/bin 42 | cp "${target}" "${SYSEXTNAME}"/usr/local/bin/"${SYSEXTNAME}" 43 | 44 | cd "${SCRIPTFOLDER}" 45 | 46 | "${SCRIPTFOLDER}"/sysext.sh "${SYSEXTNAME}" 47 | mkdir -p result 48 | mv "${SYSEXTNAME}.raw" result/ 49 | rm -rf "${SYSEXTNAME}" 50 | -------------------------------------------------------------------------------- /result/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ublue-os/sysext/01eeb96ae99c9a0e52007ea76019de74c7a32f2e/result/.gitkeep -------------------------------------------------------------------------------- /sysext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | OS="${OS-flatcar}" 5 | FORMAT="${FORMAT:-squashfs}" 6 | ARCH="${ARCH-}" 7 | SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH-0}" 8 | export SOURCE_DATE_EPOCH 9 | 10 | # This script is to be called as helper by other scripts but can also be used standalone 11 | if [ $# -lt 1 ]; then 12 | echo "Usage: $0 SYSEXTNAME" 13 | echo "The script will make a SYSEXTNAME.raw image of the folder SYSEXTNAME, and create an os-release file in it, run with --help for the list of supported environment variables." 14 | exit 1 15 | elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 16 | echo "If ARCH is specified as environment variable the sysext image will be required to run on the given architecture." 17 | 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." 18 | 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')." 19 | 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." 20 | echo "To make builds reproducible the SOURCE_DATE_EPOCH environment variable will be set to 0 if not defined." 21 | echo 22 | exit 1 23 | fi 24 | 25 | SYSEXTNAME="$1" 26 | 27 | if [ "${FORMAT}" != "squashfs" ] && [ "${FORMAT}" != "btrfs" ] && [ "${FORMAT}" != "ext4" ] && [ "${FORMAT}" != "ext2" ]; then 28 | echo "Expected FORMAT=squashfs, FORMAT=btrfs, FORMAT=ext4, or FORMAT=ext2, got '${FORMAT}'" >&2 29 | exit 1 30 | fi 31 | 32 | # Map to valid values for https://www.freedesktop.org/software/systemd/man/os-release.html#ARCHITECTURE= 33 | if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86_64" ]; then 34 | ARCH="x86-64" 35 | elif [ "${ARCH}" = "aarch64" ]; then 36 | ARCH="arm64" 37 | fi 38 | 39 | mkdir -p "${SYSEXTNAME}/usr/lib/extension-release.d" 40 | { 41 | echo "ID=${OS}" 42 | echo "EXTENSION_RELOAD_MANAGER=1" 43 | if [ "${OS}" != "_any" ]; then 44 | echo "SYSEXT_LEVEL=1.0" 45 | fi 46 | if [ "${ARCH}" != "" ]; then 47 | echo "ARCHITECTURE=${ARCH}" 48 | fi 49 | } >"${SYSEXTNAME}/usr/lib/extension-release.d/extension-release.${SYSEXTNAME}.sysext" 50 | rm -f "${SYSEXTNAME}".sysext.raw 51 | if [ "${FORMAT}" = "btrfs" ]; then 52 | # Note: We didn't chown to root:root, meaning that the file ownership is left as is 53 | mkfs.btrfs --mixed -m single -d single --shrink --rootdir "${SYSEXTNAME}" "${SYSEXTNAME}".sysext.raw 54 | # This is for testing purposes and makes not much sense to use because --rootdir doesn't allow to enable compression 55 | elif [ "${FORMAT}" = "ext4" ] || [ "${FORMAT}" = "ext2" ]; then 56 | # Assuming that 1 GB is enough 57 | truncate -s 1G "${SYSEXTNAME}".sysext.raw 58 | # Note: We didn't chown to root:root, meaning that the file ownership is left as is 59 | mkfs."${FORMAT}" -E root_owner=0:0 -d "${SYSEXTNAME}" "${SYSEXTNAME}".raw 60 | resize2fs -M "${SYSEXTNAME}".sysext.raw 61 | else 62 | mksquashfs "${SYSEXTNAME}" "${SYSEXTNAME}".sysext.raw -all-root 63 | fi 64 | echo "Created ${SYSEXTNAME}.sysext.raw" 65 | -------------------------------------------------------------------------------- /systemd/ensure-sysext.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | BindsTo=systemd-sysext.service 3 | After=systemd-sysext.service 4 | DefaultDependencies=no 5 | # Keep in sync with systemd-sysext.service 6 | ConditionDirectoryNotEmpty=|/etc/extensions 7 | ConditionDirectoryNotEmpty=|/run/extensions 8 | ConditionDirectoryNotEmpty=|/var/lib/extensions 9 | ConditionDirectoryNotEmpty=|/usr/local/lib/extensions 10 | ConditionDirectoryNotEmpty=|/usr/lib/extensions 11 | [Service] 12 | Type=oneshot 13 | RemainAfterExit=yes 14 | ExecStart=/usr/bin/systemctl daemon-reload 15 | ExecStart=/usr/bin/systemctl restart --no-block sockets.target timers.target multi-user.target 16 | [Install] 17 | WantedBy=sysinit.target -------------------------------------------------------------------------------- /withmkosi/.gitignore: -------------------------------------------------------------------------------- 1 | /mkosi.cache 2 | /mkosi.output -------------------------------------------------------------------------------- /withmkosi/README.md: -------------------------------------------------------------------------------- 1 | sudo systemd-sysext refresh --image-policy=root=unprotected+encrypted+absent 2 | -------------------------------------------------------------------------------- /withmkosi/mkosi.conf: -------------------------------------------------------------------------------- 1 | [Output] 2 | OutputDirectory=mkosi.output 3 | CacheDirectory=mkosi.cache 4 | -------------------------------------------------------------------------------- /withmkosi/mkosi.images/base/mkosi.conf: -------------------------------------------------------------------------------- 1 | [Output] 2 | Format=directory 3 | [Distribution] 4 | Distribution=fedora 5 | [Content] 6 | Bootable=no 7 | CleanPackageMetadata=no 8 | Packages=systemd 9 | udev 10 | -------------------------------------------------------------------------------- /withmkosi/mkosi.images/tools/mkosi.conf: -------------------------------------------------------------------------------- 1 | [Config] 2 | Dependencies=base 3 | 4 | [Output] 5 | Format=disk 6 | Overlay=yes 7 | 8 | [Content] 9 | BaseTrees=%O/base 10 | ExtraTrees=mkosi.extra.sysext 11 | Packages=gcc 12 | @development-tools 13 | -------------------------------------------------------------------------------- /withmkosi/mkosi.images/tools/mkosi.extra.sysext/usr/lib/extension-release.d/extension-release.tools: -------------------------------------------------------------------------------- 1 | ID=_any 2 | SYSEXT_SCOPE="system initrd portable" --------------------------------------------------------------------------------