How to build Photon OS images using POI - dcasota/photonos-scripts GitHub Wiki

prerequisites.

tdnf makecache
tdnf install -y git docker docker-buildx
systemctl enable docker
systemctl start docker
# credentials
docker login

Clean an old installation.

CONTAINERNAME="photon-os-installer"
rm -rf /root/repo
docker image rm $CONTAINERNAME --force && docker system prune --force && docker image prune --force && docker container prune --force && docker volume prune --force

Clone photon-os-installer.

RELEASE="4.0"
mkdir -p $HOME/repo/$RELEASE
cd $HOME/repo/$RELEASE
# tags might be necessary
git clone --branch v2.7 https://github.com/vmware/photon-os-installer
cd $HOME/repo/$RELEASE/photon-os-installer

Copy the following zip file into $HOME/repo/$RELEASE/photon-os-installer. minimal-iso-4.0_x86_64.zip

Unzip it.

tdnf install -y unzip wget
wget https://github.com/user-attachments/files/21205924/minimal-iso-4.0_x86_64.zip
unzip ./minimal-iso-4.0_x86_64.zip

Build the container and start it interactively.

docker buildx build -t $CONTAINERNAME --build-context poi-helper=/root/repo/4.0/photon-os-installer ./minimal-iso-4.0_x86_64/.
docker run --rm -it --privileged -v /dev:/dev -v /$HOME/repo/4.0/photon-os-installer/minimal-iso-4.0_x86_64:/output $CONTAINERNAME /bin/bash

Make the iso.

# run inside the container
cd examples/iso
photon-iso-builder -y iso.yaml
# after the iso has been created, copy it to /output
cp photon-4.0.iso /output

Setup of a vm from the iso still fails. See https://github.com/vmware/photon-os-installer/issues/35 (edited 9th July 2025).

Cleanup.

# cleanup old photon-iso-builder directories
rm -rf /$HOME/repo/4.0/photon-os-installer/examples/iso/photon-*
docker image rm $CONTAINERNAME --force && docker system prune --force && docker image prune --force && docker container prune --force && docker volume prune --force

vmdk-convert Dockerfile. Dockerfile.txt

local cached repo

Optional: classic make minimal iso build with official remote sources Insert here the classic make build process or copy all official RPMS from https://packages.vmware.com/photon/4.0/photon_release_4.0_x86_64.

#!/bin/bash

# define the path
mkdir -p $HOME/4.0/stage/RPMS
cd $HOME/4.0/stage/RPMS

# Array of URLs and corresponding output directories
urls=(
    "https://packages.vmware.com/photon/4.0/photon_release_4.0_x86_64/x86_64/"
    "https://packages.vmware.com/photon/4.0/photon_release_4.0_x86_64/noarch/"
)
output_dirs=(
    "./x86_64"
    "./noarch"
)

# Check if the number of URLs matches the number of output directories
if [ ${#urls[@]} -ne ${#output_dirs[@]} ](/dcasota/photonos-scripts/wiki/-${#urls[@]}--ne-${#output_dirs[@]}-); then
    echo "Error: Number of URLs (${#urls[@]}) does not match number of output directories (${#output_dirs[@]})"
    exit 1
fi

# Loop through URLs and output directories
for ((i=0; i<${#urls[@]}; i++)); do
    url="${urls[$i]}"
    output_dir="${output_dirs[$i]}"

    # Create output directory if it doesn't exist
    mkdir -p "$output_dir"

    # Fetch directory listing and extract .rpm file URLs
    echo "Processing URL: $url"
    curl -s "$url" | grep -o 'href="[^"]*\.rpm"' | sed 's/href="//' | sed 's/"//' | while read -r file; do
        # Decode %2B%2B to ++ in the filename
        decoded_file=$(echo "$file" | sed 's/%2B%2B/++/g')
        # Download the file, saving it with the decoded filename
        curl -s -o "$output_dir/$decoded_file" "$url$file"
        if [ $? -ne 0 ](/dcasota/photonos-scripts/wiki/-$?--ne-0-); then
            echo "Error: Failed to download $decoded_file from $url"
            exit 1
        fi
        echo "Downloaded: $output_dir/$decoded_file"
    done

    # Check if any files were downloaded for this URL
    if ls "$output_dir"/*.rpm >/dev/null 2>&1; then
        echo "Successfully downloaded RPMs to $output_dir"
    else
        echo "Warning: No RPM files downloaded to $output_dir from $url"
    fi
done

echo "All downloads completed"

Copy the missing RPMS from photon_updates_4.0/RPMS/noarch.

cd $HOME/4.0
mkdir -p ./photon_updates_4.0/RPMS/noarch
cd ./photon_updates_4.0/RPMS/noarch
wget https://packages.vmware.com/photon/4.0/photon_updates_4.0_x86_64/noarch/stig-hardening-1.5-2.ph4.noarch.rpm
wget https://packages.vmware.com/photon/4.0/photon_updates_4.0_x86_64/noarch/grub2-theme-4.0-2.ph4.noarch.rpm
wget https://packages.vmware.com/photon/4.0/photon_updates_4.0_x86_64/noarch/python3-requests-2.26.0-5.ph4.noarch.rpm
mkdir -p ./photon_updates_4.0/RPMS/x86_64/
cd /root/4.0/photon_updates_4.0/RPMS/x86_64/
wget https://packages.vmware.com/photon/4.0/photon_updates_4.0_x86_64/x86_64/rpm-plugin-systemd-inhibit-4.16.1.3-21.ph4.x86_64.rpm

content of rpmdb.sqlite.

#!/bin/bash

# SQLite database file
db_file="/var/lib/rpm/rpmdb.sqlite"

# Check if file exists
if [ ! -f "$db_file" ](/dcasota/photonos-scripts/wiki/-!--f-"$db_file"-); then
    echo "Error: SQLite file $db_file not found"
    exit 1
fi

# Check if sqlite3 is installed
if ! command -v sqlite3 >/dev/null 2>&1; then
    echo "Error: sqlite3 command not found. Install with 'tdnf install sqlite'"
    exit 1
fi

# List all tables
echo "Tables in $db_file:"
sqlite3 "$db_file" ".tables"

# Loop through each table and display schema and data
tables=$(sqlite3 "$db_file" ".tables")
for table in $tables; do
    echo -e "\nSchema for table '$table':"
    sqlite3 "$db_file" ".schema $table"
    echo -e "\nData in table '$table':"
    sqlite3 -column -header "$db_file" "SELECT * FROM $table;"
done

run container interactively:

# cleanup old photon-iso-builder directories
rm -rf /workdir/photon-*

docker run --rm -it --privileged -v /dev:/dev -v /$HOME/4.0/photon_updates_4.0:/photon_updates_4.0 -v /$HOME/4.0/stage:/repo -v /$HOME/repo/4.0/photon-os-installer/examples/iso:/workdir $CONTAINERNAME /bin/bash

Run inside the interactive shell.

createrepo /repo
createrepo /photon_updates_4.0

Some remarks. The more you use the /repo repository, adopt the yaml files to use local rpms. (todo)

The following script modifies packages_installer_40_initrd.json with the /repo path and full file name of the package. update_json_packages.txt

mv update_json_packages.txt update_json_packages.sh
chmod a+x ./update_json_packages.sh
./update_json_packages.sh ./packages_installer_40_initrd.json
./update_json_packages.sh ./packages_minimal.json

Make the iso.

cd /$HOME/repo/4.0/photon-os-installer/examples/iso
# -v /$HOME/repo/4.0/photon-os-installer/examples/iso:/workdir : Here are all .json and .yaml files
# -v /$HOME/4.0/stage:/repo : Here is the local repository done by classic make build
docker run --rm --privileged -v /dev:/dev -v /$HOME/4.0/stage:/repo -v /$HOME/repo/4.0/photon-os-installer/examples/iso:/workdir $CONTAINERNAME photon-iso-builder -y iso_40_minimal.yaml