Initial commit
This commit is contained in:
commit
8df44d76d1
9 changed files with 897 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
cosign.key
|
||||
_build_*
|
||||
output
|
||||
_build-*/**
|
31
Containerfile
Normal file
31
Containerfile
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Allow build scripts to be referenced without being copied into the final image
|
||||
FROM scratch AS ctx
|
||||
COPY build_files /
|
||||
|
||||
# Base Image
|
||||
# FROM ghcr.io/ublue-os/bazzite:stable
|
||||
FROM quay.io/fedora/fedora-bootc:42
|
||||
|
||||
## Other possible base images include:
|
||||
# FROM ghcr.io/ublue-os/bazzite:latest
|
||||
# FROM ghcr.io/ublue-os/bluefin-nvidia:stable
|
||||
#
|
||||
# ... and so on, here are more base images
|
||||
# Universal Blue Images: https://github.com/orgs/ublue-os/packages
|
||||
# Fedora base image: quay.io/fedora/fedora-bootc:41
|
||||
# CentOS base images: quay.io/centos-bootc/centos-bootc:stream10
|
||||
|
||||
### MODIFICATIONS
|
||||
## make modifications desired in your image and install packages by modifying the build.sh script
|
||||
## the following RUN directive does all the things required to run "build.sh" as recommended.
|
||||
|
||||
RUN --mount=type=bind,from=ctx,source=/,target=/ctx \
|
||||
--mount=type=cache,dst=/var/cache \
|
||||
--mount=type=cache,dst=/var/log \
|
||||
--mount=type=tmpfs,dst=/tmp \
|
||||
/ctx/build.sh && \
|
||||
ostree container commit
|
||||
|
||||
### LINTING
|
||||
## Verify final image and contents are correct.
|
||||
RUN bootc container lint
|
332
Justfile
Normal file
332
Justfile
Normal file
|
@ -0,0 +1,332 @@
|
|||
export repo_organization := env("GITHUB_REPOSITORY_OWNER", "cx")
|
||||
export image_name := env("IMAGE_NAME", "fedora-coreos-incus-image")
|
||||
export centos_version := env("CENTOS_VERSION", "stream10")
|
||||
export fedora_version := env("CENTOS_VERSION", "42")
|
||||
export default_tag := env("DEFAULT_TAG", "latest")
|
||||
export bib_image := env("BIB_IMAGE", "quay.io/centos-bootc/bootc-image-builder:latest")
|
||||
|
||||
alias build-vm := build-qcow2
|
||||
alias rebuild-vm := rebuild-qcow2
|
||||
alias run-vm := run-vm-qcow2
|
||||
|
||||
[private]
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Check Just Syntax
|
||||
[group('Just')]
|
||||
check:
|
||||
#!/usr/bin/bash
|
||||
find . -type f -name "*.just" | while read -r file; do
|
||||
echo "Checking syntax: $file"
|
||||
just --unstable --fmt --check -f $file
|
||||
done
|
||||
echo "Checking syntax: Justfile"
|
||||
just --unstable --fmt --check -f Justfile
|
||||
|
||||
# Fix Just Syntax
|
||||
[group('Just')]
|
||||
fix:
|
||||
#!/usr/bin/bash
|
||||
find . -type f -name "*.just" | while read -r file; do
|
||||
echo "Checking syntax: $file"
|
||||
just --unstable --fmt -f $file
|
||||
done
|
||||
echo "Checking syntax: Justfile"
|
||||
just --unstable --fmt -f Justfile || { exit 1; }
|
||||
|
||||
# Clean Repo
|
||||
[group('Utility')]
|
||||
clean:
|
||||
#!/usr/bin/bash
|
||||
set -eoux pipefail
|
||||
touch _build
|
||||
find *_build* -exec rm -rf {} \;
|
||||
rm -f previous.manifest.json
|
||||
rm -f changelog.md
|
||||
rm -f output.env
|
||||
rm -f output/
|
||||
|
||||
# Sudo Clean Repo
|
||||
[group('Utility')]
|
||||
[private]
|
||||
sudo-clean:
|
||||
just sudoif just clean
|
||||
|
||||
# sudoif bash function
|
||||
[group('Utility')]
|
||||
[private]
|
||||
sudoif command *args:
|
||||
#!/usr/bin/bash
|
||||
function sudoif(){
|
||||
if [[ "${UID}" -eq 0 ]]; then
|
||||
"$@"
|
||||
elif [[ "$(command -v sudo)" && -n "${SSH_ASKPASS:-}" ]] && [[ -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ]]; then
|
||||
/usr/bin/sudo --askpass "$@" || exit 1
|
||||
elif [[ "$(command -v sudo)" ]]; then
|
||||
/usr/bin/sudo "$@" || exit 1
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
sudoif {{ command }} {{ args }}
|
||||
|
||||
# This Justfile recipe builds a container image using Podman.
|
||||
#
|
||||
# Arguments:
|
||||
# $target_image - The tag you want to apply to the image (default: aurora).
|
||||
# $tag - The tag for the image (default: lts).
|
||||
# $dx - Enable DX (default: "0").
|
||||
# $hwe - Enable HWE (default: "0").
|
||||
# $gdx - Enable GDX (default: "0").
|
||||
#
|
||||
# DX:
|
||||
# Developer Experience (DX) is a feature that allows you to install the latest developer tools for your system.
|
||||
# Packages include VScode, Docker, Distrobox, and more.
|
||||
# HWE:
|
||||
# Hardware Enablement (HWE) is a feature that allows you to install the latest hardware support for your system.
|
||||
# Currently this install the Hyperscale SIG kernel which will stay ahead of the CentOS Stream kernel and enables btrfs
|
||||
# GDX: https://docs.projectaurora.io/gdx/
|
||||
# GPU Developer Experience (GDX) creates a base as an AI and Graphics platform.
|
||||
# Installs Nvidia drivers, CUDA, and other tools.
|
||||
#
|
||||
# The script constructs the version string using the tag and the current date.
|
||||
# If the git working directory is clean, it also includes the short SHA of the current HEAD.
|
||||
#
|
||||
# just build $target_image $tag $dx $hwe $gdx
|
||||
#
|
||||
# Example usage:
|
||||
# just build aurora lts 1 0 1
|
||||
#
|
||||
# This will build an image 'aurora:lts' with DX and GDX enabled.
|
||||
#
|
||||
|
||||
# Build the image using the specified parameters
|
||||
build $target_image=image_name $tag=default_tag $dx="0" $hwe="0" $gdx="0":
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Get Version
|
||||
ver="${tag}-${centos_version}.$(date +%Y%m%d)"
|
||||
|
||||
BUILD_ARGS=()
|
||||
BUILD_ARGS+=("--build-arg" "MAJOR_VERSION=${centos_version}")
|
||||
BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${target_image}")
|
||||
BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR=${repo_organization}")
|
||||
BUILD_ARGS+=("--build-arg" "ENABLE_DX=${dx}")
|
||||
BUILD_ARGS+=("--build-arg" "ENABLE_HWE=${hwe}")
|
||||
BUILD_ARGS+=("--build-arg" "ENABLE_GDX=${gdx}")
|
||||
if [[ -z "$(git status -s)" ]]; then
|
||||
BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=$(git rev-parse --short HEAD)")
|
||||
fi
|
||||
|
||||
podman build \
|
||||
"${BUILD_ARGS[@]}" \
|
||||
--pull=newer \
|
||||
--tag "${target_image}:${tag}" \
|
||||
.
|
||||
|
||||
# Command: _rootful_load_image
|
||||
# Description: This script checks if the current user is root or running under sudo. If not, it attempts to resolve the image tag using podman inspect.
|
||||
# If the image is found, it loads it into rootful podman. If the image is not found, it pulls it from the repository.
|
||||
#
|
||||
# Parameters:
|
||||
# $target_image - The name of the target image to be loaded or pulled.
|
||||
# $tag - The tag of the target image to be loaded or pulled. Default is 'default_tag'.
|
||||
#
|
||||
# Example usage:
|
||||
# _rootful_load_image my_image latest
|
||||
#
|
||||
# Steps:
|
||||
# 1. Check if the script is already running as root or under sudo.
|
||||
# 2. Check if target image is in the non-root podman container storage)
|
||||
# 3. If the image is found, load it into rootful podman using podman scp.
|
||||
# 4. If the image is not found, pull it from the remote repository into reootful podman.
|
||||
|
||||
_rootful_load_image $target_image=image_name $tag=default_tag:
|
||||
#!/usr/bin/bash
|
||||
set -eoux pipefail
|
||||
|
||||
# Check if already running as root or under sudo
|
||||
if [[ -n "${SUDO_USER:-}" || "${UID}" -eq "0" ]]; then
|
||||
echo "Already root or running under sudo, no need to load image from user podman."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Try to resolve the image tag using podman inspect
|
||||
set +e
|
||||
resolved_tag=$(podman inspect -t image "${target_image}:${tag}" | jq -r '.[].RepoTags.[0]')
|
||||
return_code=$?
|
||||
set -e
|
||||
|
||||
USER_IMG_ID=$(podman images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'")
|
||||
|
||||
if [[ $return_code -eq 0 ]]; then
|
||||
# If the image is found, load it into rootful podman
|
||||
ID=$(just sudoif podman images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'")
|
||||
if [[ "$ID" != "$USER_IMG_ID" ]]; then
|
||||
# If the image ID is not found or different from user, copy the image from user podman to root podman
|
||||
COPYTMP=$(mktemp -p "${PWD}" -d -t _build_podman_scp.XXXXXXXXXX)
|
||||
just sudoif TMPDIR=${COPYTMP} podman image scp ${UID}@localhost::"${target_image}:${tag}" root@localhost::"${target_image}:${tag}"
|
||||
rm -rf "${COPYTMP}"
|
||||
fi
|
||||
else
|
||||
# If the image is not found, pull it from the repository
|
||||
just sudoif podman pull "${target_image}:${tag}"
|
||||
fi
|
||||
|
||||
# Build a bootc bootable image using Bootc Image Builder (BIB)
|
||||
# Converts a container image to a bootable image
|
||||
# Parameters:
|
||||
# target_image: The name of the image to build (ex. localhost/fedora)
|
||||
# tag: The tag of the image to build (ex. latest)
|
||||
# type: The type of image to build (ex. qcow2, raw, iso)
|
||||
# config: The configuration file to use for the build (default: image.toml)
|
||||
|
||||
# Example: just _rebuild-bib localhost/fedora latest qcow2 image.toml
|
||||
_build-bib $target_image $tag $type $config: (_rootful_load_image target_image tag)
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
args="--type ${type} "
|
||||
args+="--use-librepo=True "
|
||||
args+="--rootfs=btrfs"
|
||||
|
||||
if [[ $target_image == localhost/* ]]; then
|
||||
args+=" --local"
|
||||
fi
|
||||
|
||||
BUILDTMP=$(mktemp -p "${PWD}" -d -t _build-bib.XXXXXXXXXX)
|
||||
|
||||
sudo podman run \
|
||||
--rm \
|
||||
-it \
|
||||
--privileged \
|
||||
--pull=newer \
|
||||
--net=host \
|
||||
--security-opt label=type:unconfined_t \
|
||||
-v $(pwd)/${config}:/config.toml:ro \
|
||||
-v $BUILDTMP:/output \
|
||||
-v /var/lib/containers/storage:/var/lib/containers/storage \
|
||||
"${bib_image}" \
|
||||
${args} \
|
||||
"${target_image}:${tag}"
|
||||
|
||||
mkdir -p output
|
||||
sudo mv -f $BUILDTMP/* output/
|
||||
sudo rmdir $BUILDTMP
|
||||
sudo chown -R $USER:$USER output/
|
||||
|
||||
# Podman builds the image from the Containerfile and creates a bootable image
|
||||
# Parameters:
|
||||
# target_image: The name of the image to build (ex. localhost/fedora)
|
||||
# tag: The tag of the image to build (ex. latest)
|
||||
# type: The type of image to build (ex. qcow2, raw, iso)
|
||||
# config: The configuration file to use for the build (deafult: image.toml)
|
||||
|
||||
# Example: just _rebuild-bib localhost/fedora latest qcow2 image.toml
|
||||
_rebuild-bib $target_image $tag $type $config: (build target_image tag) && (_build-bib target_image tag type config)
|
||||
|
||||
# Build a QCOW2 virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
build-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "qcow2" "image.toml")
|
||||
|
||||
# Build a RAW virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
build-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "raw" "image.toml")
|
||||
|
||||
# Build an ISO virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
build-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "iso.toml")
|
||||
|
||||
# Rebuild a QCOW2 virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "image.toml")
|
||||
|
||||
# Rebuild a RAW virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
rebuild-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "raw" "image.toml")
|
||||
|
||||
# Rebuild an ISO virtual machine image
|
||||
[group('Build Virtal Machine Image')]
|
||||
rebuild-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "iso" "iso.toml")
|
||||
|
||||
# Run a virtual machine with the specified image type and configuration
|
||||
_run-vm $target_image $tag $type $config:
|
||||
#!/usr/bin/bash
|
||||
set -eoux pipefail
|
||||
|
||||
# Determine the image file based on the type
|
||||
image_file="output/${type}/disk.${type}"
|
||||
if [[ $type == iso ]]; then
|
||||
image_file="output/bootiso/install.iso"
|
||||
fi
|
||||
|
||||
# Build the image if it does not exist
|
||||
if [[ ! -f "${image_file}" ]]; then
|
||||
just "build-${type}" "$target_image" "$tag"
|
||||
fi
|
||||
|
||||
# Determine an available port to use
|
||||
port=8006
|
||||
while grep -q :${port} <<< $(ss -tunalp); do
|
||||
port=$(( port + 1 ))
|
||||
done
|
||||
echo "Using Port: ${port}"
|
||||
echo "Connect to http://localhost:${port}"
|
||||
|
||||
# Set up the arguments for running the VM
|
||||
run_args=()
|
||||
run_args+=(--rm --privileged)
|
||||
run_args+=(--pull=newer)
|
||||
run_args+=(--publish "127.0.0.1:${port}:8006")
|
||||
run_args+=(--env "CPU_CORES=4")
|
||||
run_args+=(--env "RAM_SIZE=8G")
|
||||
run_args+=(--env "DISK_SIZE=64G")
|
||||
run_args+=(--env "TPM=Y")
|
||||
run_args+=(--env "GPU=Y")
|
||||
run_args+=(--device=/dev/kvm)
|
||||
run_args+=(--volume "${PWD}/${image_file}":"/boot.${type}")
|
||||
run_args+=(docker.io/qemux/qemu-docker)
|
||||
|
||||
# Run the VM and open the browser to connect
|
||||
(sleep 30 && xdg-open http://localhost:"$port") &
|
||||
podman run "${run_args[@]}"
|
||||
|
||||
# Run a virtual machine from a QCOW2 image
|
||||
[group('Run Virtal Machine')]
|
||||
run-vm-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "qcow2" "image.toml")
|
||||
|
||||
# Run a virtual machine from a RAW image
|
||||
[group('Run Virtal Machine')]
|
||||
run-vm-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "raw" "image.toml")
|
||||
|
||||
# Run a virtual machine from an ISO
|
||||
[group('Run Virtal Machine')]
|
||||
run-vm-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "iso.toml")
|
||||
|
||||
# Run a virtual machine using systemd-vmspawn
|
||||
[group('Run Virtal Machine')]
|
||||
spawn-vm rebuild="0" type="qcow2" ram="6G":
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
[ "{{ rebuild }}" -eq 1 ] && echo "Rebuilding the ISO" && just build-vm {{ rebuild }} {{ type }}
|
||||
|
||||
systemd-vmspawn \
|
||||
-M "bootc-image" \
|
||||
--console=gui \
|
||||
--cpus=2 \
|
||||
--ram=$(echo {{ ram }}| /usr/bin/numfmt --from=iec) \
|
||||
--network-user-mode \
|
||||
--vsock=false --pass-ssh-key=false \
|
||||
-i ./output/**/*.{{ type }}
|
||||
|
||||
|
||||
# Runs shell check on all Bash scripts
|
||||
lint:
|
||||
/usr/bin/find . -iname "*.sh" -type f -exec shellcheck "{}" ';'
|
||||
|
||||
# Runs shfmt on all Bash scripts
|
||||
format:
|
||||
/usr/bin/find . -iname "*.sh" -type f -exec shfmt --write "{}" ';'
|
201
LICENSE
Normal file
201
LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
274
README.md
Normal file
274
README.md
Normal file
|
@ -0,0 +1,274 @@
|
|||
# image-template
|
||||
|
||||
# Purpose
|
||||
|
||||
This repository is meant to be a template for building your own custom Universal Blue image. This template is the recommended way to make customizations to any image published by the Universal Blue Project:
|
||||
- [Aurora](https://getaurora.dev/)
|
||||
- [Bazzite](https://bazzite.gg/)
|
||||
- [Bluefin](https://projectbluefin.io/)
|
||||
- [uCore](https://projectucore.io/)
|
||||
- [main](https://github.com/ublue-os/main/)
|
||||
- [hwe](https://github.com/ublue-os/hwe/)
|
||||
|
||||
or any other base image if you want to start from scratch:
|
||||
|
||||
- Fedora: `quay.io/fedora/fedora-bootc:41`
|
||||
- CentOS Stream 9: `quay.io/centos-bootc/centos-bootc:stream9`
|
||||
- CentOS Stream 10 (in development): `quay.io/centos-bootc/centos-bootc:stream10`
|
||||
|
||||
This template includes a Containerfile and a Github workflow for building the container image, signing, and proper metadata to be listed on [artifacthub](https://artifacthub.io/). As soon as the workflow is enabled in your repository, it will build the container image and push it to the Github Container Registry.
|
||||
|
||||
# Prerequisites
|
||||
|
||||
Working knowledge in the following topics:
|
||||
|
||||
- Containers
|
||||
- https://www.youtube.com/watch?v=SnSH8Ht3MIc
|
||||
- https://www.mankier.com/5/Containerfile
|
||||
- bootc
|
||||
- https://bootc-dev.github.io/bootc/
|
||||
- Fedora Silverblue (and other Fedora Atomic variants)
|
||||
- https://docs.fedoraproject.org/en-US/fedora-silverblue/
|
||||
- Github Workflows
|
||||
- https://docs.github.com/en/actions/using-workflows
|
||||
|
||||
# How to Use
|
||||
|
||||
## Template
|
||||
|
||||
Select `Use this Template` and create a new repository from it. To enable the workflows, you may need to go the `Actions` tab of the new repository and click to enable workflows.
|
||||
|
||||
## Containerfile
|
||||
|
||||
This file defines the operations used to customize the selected image. It contains examples of possible modifications, including how to:
|
||||
- change the upstream from which the custom image is derived
|
||||
- add additional RPM packages
|
||||
- add binaries as a layer from other images
|
||||
|
||||
## Building an ISO
|
||||
|
||||
This template provides an out of the box workflow for getting an ISO image for your custom OCI image which can be used to directly install onto your machines.
|
||||
|
||||
This template provides a way to upload the ISO that is generated from the workflow to a S3 bucket or it will be available as an artifact from the job. To upload to S3 we use a tool called [rclone](https://rclone.org/) which is able to use [many S3 providers](https://rclone.org/s3/). For more details on how to configure this see the details [below](#build-isoyml).
|
||||
|
||||
### Justfile Documentation
|
||||
|
||||
This `Justfile` contains various commands and configurations for building and managing container images and virtual machine images using Podman and other utilities.
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
- `repo_organization`: The GitHub repository owner (default: "yourname").
|
||||
- `image_name`: The name of the image (default: "yourimage").
|
||||
- `centos_version`: The CentOS version (default: "stream10").
|
||||
- `fedora_version`: The Fedora version (default: "41").
|
||||
- `default_tag`: The default tag for the image (default: "latest").
|
||||
- `bib_image`: The Bootc Image Builder (BIB) image (default: "quay.io/centos-bootc/bootc-image-builder:latest").
|
||||
|
||||
#### Aliases
|
||||
|
||||
- `build-vm`: Alias for `build-qcow2`.
|
||||
- `rebuild-vm`: Alias for `rebuild-qcow2`.
|
||||
- `run-vm`: Alias for `run-vm-qcow2`.
|
||||
|
||||
|
||||
#### Commands
|
||||
|
||||
###### `check`
|
||||
|
||||
Checks the syntax of all `.just` files and the `Justfile`.
|
||||
|
||||
###### `fix`
|
||||
|
||||
Fixes the syntax of all `.just` files and the `Justfile`.
|
||||
|
||||
###### `clean`
|
||||
|
||||
Cleans the repository by removing build artifacts.
|
||||
|
||||
##### Build Commands
|
||||
|
||||
###### `build`
|
||||
|
||||
Builds a container image using Podman.
|
||||
|
||||
```bash
|
||||
just build $target_image $tag $dx $hwe $gdx
|
||||
```
|
||||
|
||||
Arguments:
|
||||
- `$target_image`: The tag you want to apply to the image (default: aurora).
|
||||
- `$tag`: The tag for the image (default: lts).
|
||||
- `$dx`: Enable DX (default: "0").
|
||||
- `$hwe`: Enable HWE (default: "0").
|
||||
- `$gdx`: Enable GDX (default: "0").
|
||||
|
||||
##### Building Virtual Machines and ISOs
|
||||
|
||||
###### `build-qcow2`
|
||||
|
||||
Builds a QCOW2 virtual machine image.
|
||||
|
||||
```bash
|
||||
just build-qcow2 $target_image $tag
|
||||
```
|
||||
|
||||
###### `build-raw`
|
||||
|
||||
Builds a RAW virtual machine image.
|
||||
|
||||
```bash
|
||||
just build-raw $target_image $tag
|
||||
```
|
||||
|
||||
###### `build-iso`
|
||||
|
||||
Builds an ISO virtual machine image.
|
||||
|
||||
```bash
|
||||
just build-iso $target_image $tag
|
||||
```
|
||||
|
||||
###### `rebuild-qcow2`
|
||||
|
||||
Rebuilds a QCOW2 virtual machine image.
|
||||
|
||||
```bash
|
||||
just rebuild-qcow2 $target_image $tag
|
||||
```
|
||||
|
||||
###### `rebuild-raw`
|
||||
|
||||
Rebuilds a RAW virtual machine image.
|
||||
|
||||
```bash
|
||||
just rebuild-raw $target_image $tag
|
||||
```
|
||||
|
||||
###### `rebuild-iso`
|
||||
|
||||
Rebuilds an ISO virtual machine image.
|
||||
|
||||
```bash
|
||||
just rebuild-iso $target_image $tag
|
||||
```
|
||||
|
||||
##### Run Virtual Machines
|
||||
|
||||
###### `run-vm-qcow2`
|
||||
|
||||
Runs a virtual machine from a QCOW2 image.
|
||||
|
||||
```bash
|
||||
just run-vm-qcow2 $target_image $tag
|
||||
```
|
||||
|
||||
###### `run-vm-raw`
|
||||
|
||||
Runs a virtual machine from a RAW image.
|
||||
|
||||
```bash
|
||||
just run-vm-raw $target_image $tag
|
||||
```
|
||||
|
||||
###### `run-vm-iso`
|
||||
|
||||
Runs a virtual machine from an ISO.
|
||||
|
||||
```bash
|
||||
just run-vm-iso $target_image $tag
|
||||
```
|
||||
|
||||
###### `spawn-vm`
|
||||
|
||||
Runs a virtual machine using systemd-vmspawn.
|
||||
|
||||
```bash
|
||||
just spawn-vm rebuild="0" type="qcow2" ram="6G"
|
||||
```
|
||||
|
||||
##### Lint and Format
|
||||
|
||||
###### `lint`
|
||||
|
||||
Runs shell check on all Bash scripts.
|
||||
|
||||
###### `format`
|
||||
|
||||
Runs shfmt on all Bash scripts.
|
||||
|
||||
## Workflows
|
||||
|
||||
### build.yml
|
||||
|
||||
This workflow creates your custom OCI image and publishes it to the Github Container Registry (GHCR). By default, the image name will match the Github repository name.
|
||||
|
||||
### build-iso.yml
|
||||
|
||||
This workflow creates an ISO from your OCI image by utilizing the [bootc-image-builder](https://osbuild.org/docs/bootc/) to generate an ISO. In order to use this workflow you must complete the following steps:
|
||||
|
||||
- Modify `iso.toml` to point to your custom image before generating an ISO.
|
||||
- If you changed your image name from the default in `build.yml` then in the `build-iso.yml` file edit the `IMAGE_REGISTRY` and `DEFAULT_TAG` environment variables with the correct values. If you did not make changes, skip this step.
|
||||
- Finally, if you want to upload your ISOs to S3 then you will need to add your S3 configuration to the repository's Action secrets. This can be found by going to your repository settings, under `Secrets and Variables` -> `Actions`. You will need to add the following
|
||||
- `S3_PROVIDER` - Must match one of the values from the [supported list](https://rclone.org/s3/)
|
||||
- `S3_BUCKET_NAME` - Your unique bucket name
|
||||
- `S3_ACCESS_KEY_ID` - It is recommended that you make a separate key just for this workflow
|
||||
- `S3_SECRET_ACCESS_KEY` - See above.
|
||||
- `S3_REGION` - The region your bucket lives in. If you do not know then set this value to `auto`.
|
||||
- `S3_ENDPOINT` - This value will be specific to the bucket as well.
|
||||
|
||||
Once the workflow is done, you'll find it either in your S3 bucket or as part of the summary under `Artifacts` after the workflow is completed.
|
||||
|
||||
#### Container Signing
|
||||
|
||||
Container signing is important for end-user security and is enabled on all Universal Blue images. It is recommended you set this up, and by default the image builds *will fail* if you don't.
|
||||
|
||||
This provides users a method of verifying the image.
|
||||
|
||||
1. Install the [cosign CLI tool](https://edu.chainguard.dev/open-source/sigstore/cosign/how-to-install-cosign/#installing-cosign-with-the-cosign-binary)
|
||||
|
||||
2. Run inside your repo folder:
|
||||
|
||||
```bash
|
||||
cosign generate-key-pair
|
||||
```
|
||||
|
||||
|
||||
- Do NOT put in a password when it asks you to, just press enter. The signing key will be used in GitHub Actions and will not work if it is encrypted.
|
||||
|
||||
> [!WARNING]
|
||||
> Be careful to *never* accidentally commit `cosign.key` into your git repo.
|
||||
|
||||
3. Add the private key to GitHub
|
||||
|
||||
- This can also be done manually. Go to your repository settings, under `Secrets and Variables` -> `Actions`
|
||||

|
||||
Add a new secret and name it `SIGNING_SECRET`, then paste the contents of `cosign.key` into the secret and save it. Make sure it's the .key file and not the .pub file. Once done, it should look like this:
|
||||

|
||||
|
||||
- (CLI instructions) If you have the `github-cli` installed, run:
|
||||
|
||||
```bash
|
||||
gh secret set SIGNING_SECRET < cosign.key
|
||||
```
|
||||
|
||||
4. Commit the `cosign.pub` file to the root of your git repository.
|
||||
|
||||
# Community
|
||||
|
||||
- [**bootc discussion forums**](https://github.com/bootc-dev/bootc/discussions) - Nothing in this template is ublue specific, the upstream bootc project has a discussions forum where custom image builders can hang out and ask questions.
|
||||
|
||||
## Artifacthub
|
||||
|
||||
This template comes with the necessary tooling to index your image on [artifacthub.io](https://artifacthub.io), use the `artifacthub-repo.yml` file at the root to verify yourself as the publisher. This is important to you for a few reasons:
|
||||
|
||||
- The value of artifacthub is it's one place for people to index their custom images, and since we depend on each other to learn, it helps grow the community.
|
||||
- You get to see your pet project listed with the other cool projects in Cloud Native.
|
||||
- Since the site puts your README front and center, it's a good way to learn how to write a good README, learn some marketing, finding your audience, etc.
|
||||
|
||||
[Discussion thread](https://universal-blue.discourse.group/t/listing-your-custom-image-on-artifacthub/6446)
|
||||
|
||||
## Community Examples
|
||||
|
||||
- [m2os](https://github.com/m2giles/m2os)
|
||||
- [bos](https://github.com/bsherman/bos)
|
||||
- [homer](https://github.com/bketelsen/homer/)
|
8
artifacthub-repo.yml
Normal file
8
artifacthub-repo.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# This file is completely optional, but if you want to index your image on https://artifacthub.io/ you can
|
||||
# Sign up and add the Repository ID to the right field. Owners fields are optional.
|
||||
# Examples: https://artifacthub.io/packages/search?ts_query_web=ublue&sort=relevance&page=1
|
||||
|
||||
repositoryID: my-custom-id-here # Fill in with your own credentials
|
||||
owners: # (optional, used to claim repository ownership)
|
||||
- name: My Name
|
||||
email: my_email@email.com
|
25
build_files/build.sh
Executable file
25
build_files/build.sh
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ouex pipefail
|
||||
|
||||
### Install packages
|
||||
|
||||
# Packages can be installed from any enabled yum repo on the image.
|
||||
# RPMfusion repos are available by default in ublue main images
|
||||
# List of rpmfusion packages can be found here:
|
||||
# https://mirrors.rpmfusion.org/mirrorlist?path=free/fedora/updates/39/x86_64/repoview/index.html&protocol=https&redirect=1
|
||||
|
||||
# Basic packages
|
||||
dnf5 install -y fish htop podman-compose podman-docker tmux vim systemd-networkd
|
||||
dnf5 remove -y NetworkManager
|
||||
|
||||
# Incus related packages
|
||||
dnf5 install -y 'dnf5-command(copr)'
|
||||
dnf5 -y copr enable rcallicotte/incus
|
||||
dnf5 install -y distrobox edk2-ovmf incus qemu-system-x86 swtpm zstd
|
||||
|
||||
#### Enable services
|
||||
|
||||
systemctl enable podman.socket
|
||||
systemctl enable incus-startup
|
||||
systemctl enable systemd-networkd
|
3
image.toml
Normal file
3
image.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[[customizations.filesystem]]
|
||||
mountpoint = "/"
|
||||
minsize = "20 GiB"
|
19
iso.toml
Normal file
19
iso.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[customizations.installer.kickstart]
|
||||
contents = """
|
||||
%post
|
||||
bootc switch --mutate-in-place --transport registry ghcr.io/yourrepo/yourimage:latest
|
||||
%end
|
||||
"""
|
||||
|
||||
[customizations.installer.modules]
|
||||
enable = [
|
||||
"org.fedoraproject.Anaconda.Modules.Storage"
|
||||
]
|
||||
disable = [
|
||||
"org.fedoraproject.Anaconda.Modules.Network",
|
||||
"org.fedoraproject.Anaconda.Modules.Security",
|
||||
"org.fedoraproject.Anaconda.Modules.Services",
|
||||
"org.fedoraproject.Anaconda.Modules.Users",
|
||||
"org.fedoraproject.Anaconda.Modules.Subscription",
|
||||
"org.fedoraproject.Anaconda.Modules.Timezone"
|
||||
]
|
Loading…
Reference in a new issue