Compare commits
No commits in common. "acf114c41649ca45b17b84fe884747c63ba24979" and "b24fee8d379514aa1b78f711f6e538a5edb87966" have entirely different histories.
acf114c416
...
b24fee8d37
|
|
@ -14,8 +14,8 @@ on:
|
|||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
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_NAME: "${{ github.event.repository.name }}" # the name of the image produced by this build, matches repo names
|
||||
MY_IMAGE_DESC: "My Customized Universal Blue Image"
|
||||
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/!
|
||||
|
||||
|
|
@ -38,12 +38,6 @@ jobs:
|
|||
- name: Checkout
|
||||
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
|
||||
id: date
|
||||
run: |
|
||||
|
|
@ -99,30 +93,6 @@ jobs:
|
|||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
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
|
||||
# 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
|
||||
|
|
@ -133,27 +103,14 @@ jobs:
|
|||
username: ${{ github.actor }}
|
||||
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
|
||||
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)
|
||||
id: push
|
||||
env:
|
||||
REGISTRY_USER: ${{ github.actor }}
|
||||
REGISTRY_PASSWORD: ${{ github.token }}
|
||||
with:
|
||||
registry: ${{ steps.registry_case.outputs.lowercase }}
|
||||
registry: ${{ env.IMAGE_REGISTRY }}
|
||||
image: ${{ env.IMAGE_NAME }}
|
||||
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
|
||||
# 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
|
||||
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
|
||||
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
|
||||
cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
cosign.key
|
||||
_build_*
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
# FROM ghcr.io/ublue-os/bazzite:stable
|
||||
|
|
|
|||
203
Justfile
203
Justfile
|
|
@ -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")
|
||||
19
README.md
19
README.md
|
|
@ -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.
|
||||
|
||||
# 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
|
||||
|
||||
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 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
|
||||
|
||||
### 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.
|
||||
|
||||
# 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.
|
||||
|
||||
## Community Examples
|
||||
|
||||
### Examples
|
||||
- [m2os](https://github.com/m2giles/m2os)
|
||||
- [bos](https://github.com/bsherman/bos)
|
||||
- [homer](https://github.com/bketelsen/homer/)
|
||||
|
|
|
|||
8
build.sh
8
build.sh
|
|
@ -12,12 +12,8 @@ set -ouex pipefail
|
|||
# this installs a package from fedora repos
|
||||
dnf install -y tmux
|
||||
|
||||
# Use a COPR Example:
|
||||
#
|
||||
# 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
|
||||
# this would install a package from rpmfusion
|
||||
# rpm-ostree install vlc
|
||||
|
||||
#### Example for enabling a System Unit File
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
[[customizations.filesystem]]
|
||||
mountpoint = "/"
|
||||
minsize = "20 GiB"
|
||||
19
iso.toml
19
iso.toml
|
|
@ -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"
|
||||
]
|
||||
Loading…
Reference in New Issue