SampleOS is a dummy example of a derivate system built with containerOS-toolkit (cOS-toolkit). The purpose of this repository is moslty to showcase and demonstrate how to extend and customize containerOS using its own toolkit.
cOS is built from containers, and completely hosted on image registries. The build process results in a single container image used to deliver regular upgrades in OTA approach. Refer to cOS project for further details regarding the toolkit or the base cOS system.
This SampleOS only includes a dummy http service on top of the cOS base that
listens to http://<IP>:8090/fortuneteller
which is enabled through a
cloud-init configuration (10_sampleOSService.yaml) applied at
boot time the over the ephemeral /etc
.
- SampleOS
Download the ISO (see actions artifacts) and boot it with the hipervisor of your choice. The ISO can be simply boot using KVM with the following commands:
# create a virtual disk of 20G
$ qemu-img create -f raw test.img 20G
# Run a VM with the ISO
$ qemu-kvm -m 2048 -cdrom sampleOS-0.20210415.iso -hda test.img
Default root password is set to sampleos
on in 04_accounting.yaml, then, after loging into the VM, you can check SampleService by typing:
# Service status
systemctl status sampleservice
# Check is up and running properly
curl -L http://localhost:8090/fortuneteller
cOS has a docker image which can be used to build cOS locally in order to generate the cOS packages and the cOS iso from your checkout.
From your git folder, use the .envrc
file:
$> source .envrc
$> cos-build
or manually:
$> docker build -t cos-builder .
$> docker run --privileged=true \
--rm -v /var/run/docker.sock:/var/run/docker.sock \
-v $PWD:/cOS cos-builder
SampleOS can be build locally by using the following make targets.
# Install toolchain dependencies (luet, luet-makeiso)
$ sudo make deps
# Builds all the packages of the repository
$ sudo make build
# Creates a local repo and builds an ISO using the local repository
# on top of the raccos/realeases-cos docker repository
$ sudo make local-iso
The sampleOS relies on luet for the build, in fact this is the core of the toolchain. Consider running the following commands to build SampleOS.
- squashfs
- xorriso
# Install packages for openSUSE
zypper in squashfs xorriso
# Installing Luet (or grab a release from https://github.com/mudler/luet/releases )
$ curl https://get.mocaccino.org/luet/get_luet_root.sh | sh
# Install luet makeiso for iso creation (or grab a release from https://github.com/mudler/luet-makeiso/releases )
$ sudo luet install -y extension/makeiso
$ sudo luet build --only-target-package --pull --image-repository raccos/sampleos \
--tree packages --from-repositories system/sampleOS
Where:
- --only-target-package: tells that we will just need to build
system/sampleOS
, and not its dependencies - --pull: Enable reusal of the
cos-toolkit
image caches - --image-repository: Is where our resulting caches images are named after. Combined with
--push
it allows to push all the images used during build. It is optional - --tree: A path where the specfiles are, in this case
packages
. Defaults to current working directory - --from-repositories: Allow to resolve package dependencies compilation specs from remote repositories (see
.luet.yaml
)
The resulting artifacts will be available in build/
. You can tweak the output folder with the --destination
flag.
$ luet create-repo --tree packages --name sampleOS --from-repositories
$ sudo luet-makeiso iso.yaml --local build
The sampleOS derivative install can be upgraded in two ways:
- by running
cos-upgrade
and attaching to the standard upgrade channel (default) - by running
cos-upgrade <container_image>
to upgrade to a specific container image
To push the images required for upgrades via standard channel upgrades, pass the --push-images --type docker --output <image reference>
to luet create-repo
.
The same image reference needs to be annotated here so calling cos-upgrade
will automatically pull from the container image.
Note: You can also run make FINAL_REPO=<image_reference> publish-repo
, which automatically pushes the images to raccos/releases-sampleos
.
To push upgrades by image tags ( e.g. pointing at foo/bar:latest
), set CHANNEL_UPGRADES to false
in /etc/cos-upgrade-image
and provide a default UPGRADE_IMAGE.
Build cache allows to rebuild the same packages given a git checkout (assuming the cache images are pushed during build).
The cache images are generated under the image reference passed by --image-repository
and they can be pushed automatically during build time by specifying the --push
flag.
Note: In order to use build caches, you need to include the cos-toolkit
tree checkout, or either as a git submodule under the packages
folder, or by specifying an additional --tree
argument when calling luet build
pointing to a local path.
cos-toolkit
uses luet behind the scenes to build the images. Luet uses a YAML syntax and a template engine to define packages that are built from containers.
The sample repository and cos-toolkit
are Luet trees which contains package definitions. This allows derivatives to re-use the same components of cos
as a whole, just consume parts of it or point to specific versions of it by checking out the cos-toolkit
version in the derivative's tree repository.
The .luet.yaml file in the repository root defines where to take the compilations definition from and links it with the images built by the cos-toolkit
CI.
Note: You can at any time decide to drop this file and replace it with a git submodule inside the packages
directory - this allows you to point to specific versions of cos-toolkit
.
In the repository we define just two packages:
- The definition of our OS
system/sampleOS
(https://github.com/rancher-sandbox/cos-toolkit-sample-repo/blob/master/packages/sampleOS/definition.yaml) - The definition of our App
app/sampleOSService
(https://github.com/rancher-sandbox/cos-toolkit-sample-repo/blob/master/packages/sampleOSService/definition.yaml)
We can see we reuse cos
as we reference it in the sampleOS
build requirements:
join:
- category: "system"
name: "cos"
version: ">=0"
- category: "app"
name: "sampleOSService"
version: ">=0"
This already allows us to inherit all the system/cos
featureset, which is presented in the README. Another approach is available here where we use requires
instead. See also the official docs for more details.
We just apply some minor changes ( default username and password ) and define where our images will be pushed to. This is needed in order to allow cos-upgrade
to upgrade from your container registry.
At this point, we have our application, which is a golang app, and the build definition looks like the following:
requires:
- name: "golang"
category: "build"
version: ">=0"
env:
- PATH=$PATH:/usr/local/go/bin
- GOPATH=/luetbuild/go
steps:
- zypper in -y {{.Values.additional_packages}}
- go build -o sampleOSService main.go
- mv sampleOSService /usr/bin
- cp 10_sampleOSService.yaml /system/oem/
We have added some additional packages needed for our service (zypper in -y {{.Values.additional_packages}}
, where additional_packages
are defined here), and we have built the golang application by requiring build/golang
, which is provided by cos-toolkit
.
At this point, cos-build
will just run luet build
and luet geniso
inside a container. geniso
is a simple script that reads the iso spec and creates an ISO with the defined luet packages, which in our case is system/sampleOS
.
For a more concrete example where we embed k3s and pinpoint to a specific cos-toolkit
version, see the EpinioOS appliance demo example