Compare commits

..

No commits in common. "acf114c41649ca45b17b84fe884747c63ba24979" and "b24fee8d379514aa1b78f711f6e538a5edb87966" have entirely different histories.

8 changed files with 13 additions and 293 deletions

View File

@ -14,8 +14,8 @@ on:
workflow_dispatch: workflow_dispatch:
env: env:
IMAGE_NAME: "${{ github.event.repository.name }}" # the name of the image produced by this build, matches repo names MY_IMAGE_NAME: "${{ github.event.repository.name }}" # the name of the image produced by this build, matches repo names
IMAGE_DESC: "My Customized Universal Blue Image" MY_IMAGE_DESC: "My Customized Universal Blue Image"
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit
ARTIFACTHUB_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" # You should put your own image here so that you get a fancy profile image on https://artifacthub.io/! ARTIFACTHUB_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" # You should put your own image here so that you get a fancy profile image on https://artifacthub.io/!
@ -37,12 +37,6 @@ jobs:
# These stage versions are pinned by https://github.com/renovatebot/renovate # These stage versions are pinned by https://github.com/renovatebot/renovate
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
# This is optional, but if you see that your builds are way too big for the runners, you can enable this by uncommenting the following lines:
# - name: Maximize build space
# uses: ublue-os/remove-unwanted-software@517622d6452028f266b7ba4cc9a123b5f58a6b53 # v7
# with:
# remove-codeql: true
- name: Get current date - name: Get current date
id: date id: date
@ -99,30 +93,6 @@ jobs:
labels: ${{ steps.metadata.outputs.labels }} labels: ${{ steps.metadata.outputs.labels }}
oci: false oci: false
# Rechunk is a script that we use on Universal Blue to make sure there isnt a single huge layer when your image gets published.
# This does not make your image faster to download, just provides better resumability and fixes a few errors.
# Documentation for Rechunk is provided on their github repository at https://github.com/hhd-dev/rechunk
# You can enable it by uncommenting the following lines:
# - name: Run Rechunker
# id: rechunk
# uses: hhd-dev/rechunk@f153348d8100c1f504dec435460a0d7baf11a9d2 # v1.1.1
# with:
# rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.1'
# ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}"
# prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}"
# skip_compression: true
# version: ${{ env.CENTOS_VERSION }}
# labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator
# This is necessary so that the podman socket can find the rechunked image on its storage
# - name: Load in podman and tag
# run: |
# IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }})
# sudo rm -rf ${{ steps.rechunk.outputs.output }}
# for tag in ${{ steps.metadata.outputs.tags }}; do
# podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag
# done
# These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing # These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing
# They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work # They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
@ -133,27 +103,14 @@ jobs:
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
# Workaround bug where capital letters in your GitHub username make it impossible to push to GHCR.
# https://github.com/macbre/push-to-ghcr/issues/12
- name: Lowercase Registry
id: registry_case
uses: ASzc/change-string-case-action@v6
with:
string: ${{ env.IMAGE_REGISTRY }}
- name: Push To GHCR - name: Push To GHCR
uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2 uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
id: push id: push
env:
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
with: with:
registry: ${{ steps.registry_case.outputs.lowercase }} registry: ${{ env.IMAGE_REGISTRY }}
image: ${{ env.IMAGE_NAME }} image: ${{ env.IMAGE_NAME }}
tags: ${{ steps.metadata.outputs.tags }} tags: ${{ steps.metadata.outputs.tags }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
# This section is optional and only needs to be enabled if you plan on distributing # This section is optional and only needs to be enabled if you plan on distributing
# your project for others to consume. You will need to create a public and private key # your project for others to consume. You will need to create a public and private key
@ -166,7 +123,7 @@ jobs:
- name: Sign container image - name: Sign container image
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
run: | run: |
IMAGE_FULL="${{ steps.registry_case.outputs.lowercase }}/${IMAGE_NAME}" IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${IMAGE_NAME}"
for tag in ${{ steps.metadata.outputs.tags }}; do for tag in ${{ steps.metadata.outputs.tags }}; do
cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag
done done

1
.gitignore vendored
View File

@ -1,2 +1 @@
cosign.key cosign.key
_build_*

View File

@ -1,4 +1,4 @@
FROM ghcr.io/ublue-os/silverblue-main:latest FROM ghcr.io/ublue-os/ublue-os/silverblue-main:latest
## Other possible base images include: ## Other possible base images include:
# FROM ghcr.io/ublue-os/bazzite:stable # FROM ghcr.io/ublue-os/bazzite:stable

203
Justfile
View File

@ -1,203 +0,0 @@
export repo_organization := env("GITHUB_REPOSITORY_OWNER", "yourname")
export image_name := env("IMAGE_NAME", "yourimage")
export default_tag := env("DEFAULT_TAG", "latest")
export bib_image := env("BIB_IMAGE", "quay.io/centos-bootc/bootc-image-builder:latest")
export SUDO_DISPLAY := if `if [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then echo true; fi` == "true" { "true" } else { "false" }
export SUDOIF := if `id -u` == "0" { "" } else { if SUDO_DISPLAY == "true" { "sudo --askpass" } else { "sudo" } }
export PODMAN := if path_exists("/usr/bin/podman") == "true" { env("PODMAN", "/usr/bin/podman") } else { if path_exists("/usr/bin/docker") == "true" { env("PODMAN", "docker") } else { env("PODMAN", "exit 1 ; ") } }
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
# Sudo Clean Repo
[group('Utility')]
[private]
sudo-clean:
${SUDOIF} just clean
build $target_image=image_name $tag=default_tag:
#!/usr/bin/env bash
# Get Version
ver="${tag}-$(date +%Y%m%d)"
BUILD_ARGS=()
BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${image_name}")
BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR=${repo_organization}")
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 "${image_name}:${tag}" \
.
_rootful_load_image $target_image=image_name $tag=default_tag:
#!/usr/bin/bash
set -eoux pipefail
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
set +e
resolved_tag=$(${PODMAN} inspect -t image "${target_image}:${tag}" | jq -r '.[].RepoTags.[0]')
return_code=$?
set -e
if [[ $return_code -eq 0 ]]; then
# Load into Rootful ${PODMAN}
ID=$(${SUDOIF} ${PODMAN} images --filter reference="${target_image}:${tag}" --format "'{{ '{{.ID}}' }}'")
if [[ -z "$ID" ]]; then
COPYTMP=$(mktemp -p "${PWD}" -d -t _build_podman_scp.XXXXXXXXXX)
${SUDOIF} TMPDIR=${COPYTMP} ${PODMAN} image scp ${UID}@localhost::"${target_image}:${tag}" root@localhost::"${target_image}:${tag}"
rm -rf "${COPYTMP}"
fi
else
# Make sure the image is present and/or up to date
${SUDOIF} ${PODMAN} pull "${target_image}:${tag}"
fi
_build-bib $target_image $tag $type $config: (_rootful_load_image target_image tag)
#!/usr/bin/env bash
set -euo pipefail
mkdir -p "output"
echo "Cleaning up previous build"
if [[ $type == iso ]]; then
sudo rm -rf "output/bootiso" || true
else
sudo rm -rf "output/${type}" || true
fi
args="--type ${type}"
if [[ $target_image == localhost/* ]]; then
args+=" --local"
fi
sudo ${PODMAN} run \
--rm \
-it \
--privileged \
--pull=newer \
--net=host \
--security-opt label=type:unconfined_t \
-v $(pwd)/${config}:/config.toml:ro \
-v $(pwd)/output:/output \
-v /var/lib/containers/storage:/var/lib/containers/storage \
"${bib_image}" \
${args} \
"${target_image}"
sudo chown -R $USER:$USER output
_rebuild-bib $target_image $tag $type $config: (build target_image tag) && (_build-bib target_image tag type config)
[group('Build Virtual Machine Image')]
build-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "qcow2" "image.toml")
[group('Build Virtual Machine Image')]
build-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "raw" "image.toml")
[group('Build Virtual Machine Image')]
build-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_build-bib target_image tag "iso" "iso.toml")
[group('Build Virtual Machine Image')]
rebuild-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "qcow2" "image.toml")
[group('Build Virtual Machine Image')]
rebuild-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "raw" "image.toml")
[group('Build Virtual Machine Image')]
rebuild-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_rebuild-bib target_image tag "iso" "iso.toml")
_run-vm $target_image $tag $type $config:
#!/usr/bin/bash
set -eoux pipefail
image_file="output/${type}/disk.${type}"
if [[ $type == iso ]]; then
image_file="output/bootiso/install.iso"
fi
if [[ ! -f "${image_file}" ]]; then
just "build-${type}" "$target_image" "$tag"
fi
# Determine which 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}"
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 "BOOT_MODE=windows_secure")
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)
${PODMAN} run "${run_args[@]}" &
xdg-open http://localhost:${port}
fg "%${PODMAN}"
[group('Run Virtual Machine')]
run-vm-qcow2 $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "qcow2" "image-builder.config.toml")
[group('Run Virtual Machine')]
run-vm-raw $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "raw" "image-builder.config.toml")
[group('Run Virtual Machine')]
run-vm-iso $target_image=("localhost/" + image_name) $tag=default_tag: && (_run-vm target_image tag "iso" "image-builder-iso.config.toml")

View File

@ -12,6 +12,11 @@ This repository is meant to be a template for building your own custom Universal
This template includes a Containerfile and a Github workflow for building the container image. As soon as the workflow is enabled in your repository, it will build the container image and push it to the Github Container Registry. This template includes a Containerfile and a Github workflow for building the container image. As soon as the workflow is enabled in your repository, it will build the container image and push it to the Github Container Registry.
# Community
- [**bootc discussion forums**](https://github.com/containers/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.
- Index your image on [artifacthub.io](https://artifacthub.io), use the `artifacthub-repo.yml` file at the root to verify yourself as the publisher.
# Prerequisites # Prerequisites
Working knowledge in the following topics: Working knowledge in the following topics:
@ -39,12 +44,6 @@ This file defines the operations used to customize the selected image. It contai
- add additional RPM packages - add additional RPM packages
- add binaries as a layer from other images - add binaries as a layer from other images
## Building an ISO
Modify `iso.toml` to point to your custom image before generating an ISO.
- (Steps in progress)
## Workflows ## Workflows
### build.yml ### build.yml
@ -86,13 +85,7 @@ This provides users a method of verifying the image.
4. Commit the `cosign.pub` file to the root of your git repository. 4. Commit the `cosign.pub` file to the root of your git repository.
# Community ### Examples
- [**bootc discussion forums**](https://github.com/containers/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.
- Index your image on [artifacthub.io](https://artifacthub.io), use the `artifacthub-repo.yml` file at the root to verify yourself as the publisher.
## Community Examples
- [m2os](https://github.com/m2giles/m2os) - [m2os](https://github.com/m2giles/m2os)
- [bos](https://github.com/bsherman/bos) - [bos](https://github.com/bsherman/bos)
- [homer](https://github.com/bketelsen/homer/) - [homer](https://github.com/bketelsen/homer/)

View File

@ -12,12 +12,8 @@ set -ouex pipefail
# this installs a package from fedora repos # this installs a package from fedora repos
dnf install -y tmux dnf install -y tmux
# Use a COPR Example: # this would install a package from rpmfusion
# # rpm-ostree install vlc
# dnf5 -y copr enable ublue-os/staging
# dnf5 -y install package
# Disable COPRs so they don't end up enabled on the final image:
# dnf5 -y copr disable ublue-os/staging
#### Example for enabling a System Unit File #### Example for enabling a System Unit File

View File

@ -1,3 +0,0 @@
[[customizations.filesystem]]
mountpoint = "/"
minsize = "20 GiB"

View File

@ -1,19 +0,0 @@
[customizations.installer.kickstart]
contents = """
%post
bootc switch --mutate-in-place --transport registry ghcr.io/yourname/yourusername: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"
]