Compare commits

...

6 Commits

Author SHA1 Message Date
mudler
efc7cfd4e9 Add helper to pre-build static images (for ARM) 2023-02-18 14:46:54 +01:00
Ettore Di Giacinto
093850c59d 📖 Update README
Signed-off-by: Ettore Di Giacinto <mudler@users.noreply.github.com>
2023-02-07 12:11:07 +01:00
Dimitris Karakasilis
724a8903fc Merge pull request #23 from kairos-io/514-produce-loadable-tar
Always produce an importable tar from the image
2023-01-09 17:10:06 +02:00
Dimitris Karakasilis
04d46465a7 Fallback to the spec name when a push image name is not provided
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-01-09 13:25:04 +02:00
Dimitris Karakasilis
4c8f1dd0f0 Fix typo
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-12-21 15:29:10 +02:00
Dimitris Karakasilis
ed201a72ef Always produce an importable tar from the image
and name it after the artifact

Fixes https://github.com/kairos-io/kairos/issues/514

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-12-20 10:26:10 +02:00
5 changed files with 197 additions and 13 deletions

View File

@@ -1,9 +1,64 @@
# osbuilder
<h1 align="center">
<br>
<img width="184" alt="kairos-white-column 5bc2fe34" src="https://user-images.githubusercontent.com/2420543/193010398-72d4ba6e-7efe-4c2e-b7ba-d3a826a55b7d.png"><br>
osbuilder
<br>
</h1>
<h3 align="center">Kubernetes Native Extension to build Linux distributions artifacts from container images</h3>
<p align="center">
<a href="https://opensource.org/licenses/">
<img src="https://img.shields.io/badge/licence-APL2-brightgreen"
alt="license">
</a>
<a href="https://github.com/kairos-io/osbuilder/issues"><img src="https://img.shields.io/github/issues/kairos-io/osbuilder"></a>
<a href="https://kairos.io/docs/" target=_blank> <img src="https://img.shields.io/badge/Documentation-blue"
alt="docs"></a>
<img src="https://img.shields.io/badge/made%20with-Go-blue">
<img src="https://goreportcard.com/badge/github.com/kairos-io/osbuilder" alt="go report card" />
</p>
With Kairos you can build immutable, bootable Kubernetes and OS images for your edge devices as easily as writing a Dockerfile. Optional P2P mesh with distributed ledger automates node bootstrapping and coordination. Updating nodes is as easy as CI/CD: push a new image to your container registry and let secure, risk-free A/B atomic upgrades do the rest.
<table>
<tr>
<th align="center">
<img width="640" height="1px">
<p>
<small>
Documentation
</small>
</p>
</th>
<th align="center">
<img width="640" height="1">
<p>
<small>
Contribute
</small>
</p>
</th>
</tr>
<tr>
<td>
📚 [Getting started with Kairos](https://kairos.io/docs/getting-started) <br> :bulb: [Examples](https://kairos.io/docs/examples) <br> :movie_camera: [Video](https://kairos.io/docs/media/) <br> :open_hands:[Engage with the Community](https://kairos.io/community/)
</td>
<td>
🙌[ CONTRIBUTING.md ]( https://github.com/kairos-io/kairos/blob/master/CONTRIBUTING.md ) <br> :raising_hand: [ GOVERNANCE ]( https://github.com/kairos-io/kairos/blob/master/GOVERNANCE.md ) <br>:construction_worker:[Code of conduct](https://github.com/kairos-io/kairos/blob/master/CODE_OF_CONDUCT.md)
</td>
</tr>
</table>
| :exclamation: | This is experimental! |
|-|:-|
This is the Kairos osbuilder Kubernetes Native Extension.
## Installation
To install, use helm:
@@ -28,3 +83,5 @@ TEST SUITE: None
# Installs osbuilder
$ helm install kairos-osbuilder kairos/osbuilder
```
Documentation available at: https://kairos.io/docs/advanced/build/

View File

@@ -49,7 +49,8 @@ type OSArtifactSpec struct {
Bundles []string `json:"bundles,omitempty"`
PullOptions Pull `json:"pull,omitempty"`
OSRelease string `json:"osRelease,omitempty"`
PushOptions Push `json:"push,omitempty"`
// TODO: Currently not used. Reserved to be used when we have a way to push to registries.
PushOptions Push `json:"push,omitempty"`
}
type Push struct {

View File

@@ -65,7 +65,17 @@ func unpackContainer(id, containerImage, pullImage string, pullOptions buildv1al
}
}
func createImageContainer(containerImage string, pushOptions buildv1alpha1.Push) v1.Container {
func pushImageName(artifact buildv1alpha1.OSArtifact) string {
pushName := artifact.Spec.PushOptions.ImageName
if pushName != "" {
return pushName
}
return artifact.Name
}
func createImageContainer(containerImage string, artifact buildv1alpha1.OSArtifact) v1.Container {
imageName := pushImageName(artifact)
return v1.Container{
ImagePullPolicy: v1.PullAlways,
Name: "create-image",
@@ -73,8 +83,9 @@ func createImageContainer(containerImage string, pushOptions buildv1alpha1.Push)
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"tar -czvpf test.tar -C /rootfs . && luet util pack %s test.tar image.tar && mv image.tar /artifacts",
pushOptions.ImageName,
"tar -czvpf test.tar -C /rootfs . && luet util pack %[1]s test.tar %[2]s.tar && chmod +r %[2]s.tar && mv %[2]s.tar /artifacts",
imageName,
artifact.Name,
),
},
VolumeMounts: []v1.VolumeMount{
@@ -139,8 +150,6 @@ func osReleaseContainer(containerImage string) v1.Container {
func (r *OSArtifactReconciler) genJob(artifact buildv1alpha1.OSArtifact) *batchv1.Job {
objMeta := genObjectMeta(artifact)
pushImage := artifact.Spec.PushOptions.Push
privileged := false
serviceAccount := true
@@ -326,11 +335,7 @@ func (r *OSArtifactReconciler) genJob(artifact buildv1alpha1.OSArtifact) *batchv
pod.InitContainers = append(pod.InitContainers, buildGCECloudImageContainer)
}
// TODO: Does it make sense to build the image and not push it? Maybe remove
// this flag?
if pushImage {
pod.InitContainers = append(pod.InitContainers, createImageContainer(r.ToolImage, artifact.Spec.PushOptions))
}
pod.InitContainers = append(pod.InitContainers, createImageContainer(r.ToolImage, artifact))
pod.Containers = []v1.Container{
createPushToServerImageContainer(r.CopierImage, r.ArtifactPodInfo),

View File

@@ -82,6 +82,7 @@ COPY ./add-cloud-init.sh /add-cloud-init.sh
# ARM helpers
COPY ./build-arm-image.sh /build-arm-image.sh
COPY ./arm /arm
COPY ./prepare_arm_images.sh /prepare_arm_images.sh
# RAW images helpers
COPY ./gce.sh /gce.sh

120
tools-image/prepare_arm_images.sh Executable file
View File

@@ -0,0 +1,120 @@
#!/bin/bash
# This script prepares Kairos state, recovery, oem and pesistent partitions as img files.
set -e
# Temp dir used during build
WORKDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
TARGET=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
STATEDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
: "${OEM_LABEL:=COS_OEM}"
: "${RECOVERY_LABEL:=COS_RECOVERY}"
: "${ACTIVE_LABEL:=COS_ACTIVE}"
: "${PASSIVE_LABEL:=COS_PASSIVE}"
: "${PERSISTENT_LABEL:=COS_PERSISTENT}"
: "${SYSTEM_LABEL:=COS_SYSTEM}"
: "${STATE_LABEL:=COS_STATE}"
size="${SIZE:-7544}"
state_size="${STATE_SIZE:-4992}"
recovery_size="${RECOVERY_SIZE:-2192}"
default_active_size="${DEFAULT_ACTIVE_SIZE:-2400}"
container_image="${container_image:-quay.io/kairos/kairos-opensuse-leap-arm-rpi:v1.5.1-k3sv1.25.6-k3s1}"
ensure_dir_structure() {
local target=$1
for mnt in /sys /proc /dev /tmp /boot /usr/local /oem
do
if [ ! -d "${target}${mnt}" ]; then
mkdir -p ${target}${mnt}
fi
done
}
mkdir -p ${STATEDIR}/cOS
dd if=/dev/zero of=${STATEDIR}/cOS/active.img bs=1M count=$default_active_size
mkfs.ext2 ${STATEDIR}/cOS/active.img -L ${ACTIVE_LABEL}
LOOP=$(losetup --show -f ${STATEDIR}/cOS/active.img)
if [ -z "$LOOP" ]; then
echo "No device"
exit 1
fi
mount -t ext2 $LOOP $TARGET
ensure_dir_structure $TARGET
# Download the container image
if [ -z "$directory" ]; then
echo ">>> Downloading container image"
luet util unpack $container_image $TARGET
else
echo ">>> Copying files from $directory"
rsync -axq --exclude='host' --exclude='mnt' --exclude='proc' --exclude='sys' --exclude='dev' --exclude='tmp' ${directory}/ $TARGET
fi
umount $TARGET
sync
losetup -d $LOOP
echo ">> Preparing passive.img"
cp -rfv ${STATEDIR}/cOS/active.img ${STATEDIR}/cOS/passive.img
tune2fs -L ${PASSIVE_LABEL} ${STATEDIR}/cOS/passive.img
# Preparing recovery
echo ">> Preparing recovery.img"
RECOVERY=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
mkdir -p ${RECOVERY}/cOS
cp -rfv ${STATEDIR}/cOS/active.img ${RECOVERY}/cOS/recovery.img
tune2fs -L ${SYSTEM_LABEL} ${RECOVERY}/cOS/recovery.img
# Install real grub config to recovery
cp -rfv /arm/grub/config/* $RECOVERY
mkdir -p $RECOVERY/grub2
cp -rfv /arm/grub/artifacts/* $RECOVERY/grub2
dd if=/dev/zero of=recovery_partition.img bs=1M count=$recovery_size
dd if=/dev/zero of=state_partition.img bs=1M count=$state_size
mkfs.ext4 -F -L ${RECOVERY_LABEL} recovery_partition.img
LOOP=$(losetup --show -f recovery_partition.img)
mkdir -p $WORKDIR/recovery
mount $LOOP $WORKDIR/recovery
cp -arf $RECOVERY/* $WORKDIR/recovery
umount $WORKDIR/recovery
losetup -d $LOOP
mkfs.ext4 -F -L ${STATE_LABEL} state_partition.img
LOOP=$(losetup --show -f state_partition.img)
mkdir -p $WORKDIR/state
mount $LOOP $WORKDIR/state
cp -arf $STATEDIR/* $WORKDIR/state
grub2-editenv $WORKDIR/state/grub_oem_env set "default_menu_entry=Kairos"
umount $WORKDIR/state
losetup -d $LOOP
cp -rfv state_partition.img bootloader/
cp -rfv recovery_partition.img bootloader/
## Optional, prepare COS_OEM and COS_PERSISTENT
# Create the grubenv forcing first boot to be on recovery system
mkdir -p $WORKDIR/oem
cp -rfv /defaults.yaml $WORKDIR/oem/01_defaults.yaml
# Create a 64MB filesystem for OEM volume
truncate -s $((64*1024*1024)) bootloader/oem.img
mkfs.ext2 -L "${OEM_LABEL}" -d $WORKDIR/oem bootloader/oem.img
# Create a 2GB filesystem for COS_PERSISTENT volume
truncate -s $((2048*1024*1024)) bootloader/persistent.img
mkfs.ext2 -L "${PERSISTENT_LABEL}" bootloader/persistent.img