205 lines
8.0 KiB
YAML
205 lines
8.0 KiB
YAML
name: 'Maximize build disk space'
|
|
description: 'Maximize the available disk space for your build job'
|
|
branding:
|
|
icon: 'crop'
|
|
color: 'orange'
|
|
inputs:
|
|
root-reserve-mb:
|
|
description: 'Space to be left free on the root filesystem, in Megabytes.'
|
|
required: false
|
|
default: '1024'
|
|
temp-reserve-mb:
|
|
description: 'Space to be left free on the temp filesystem (/mnt), in Megabytes.'
|
|
required: false
|
|
default: '100'
|
|
swap-size-mb:
|
|
description: 'Swap space to create, in Megabytes.'
|
|
required: false
|
|
default: '4096'
|
|
overprovision-lvm:
|
|
description: |
|
|
Create the LVM disk images as sparse files, making the space required for the LVM image files *appear* unused on the
|
|
hosting volumes until actually allocated. Use with care, this can lead to surprising out-of-disk-space situations.
|
|
You should prefer adjusting root-reserve-mb/temp-reserve-mb over using this option.
|
|
required: false
|
|
default: 'false'
|
|
build-mount-path:
|
|
description: 'Absolute path to the mount point where the build space will be available, defaults to $GITHUB_WORKSPACE if unset.'
|
|
required: false
|
|
build-mount-path-ownership:
|
|
description: 'Ownership of the mount point path, defaults to standard "runner" user and group.'
|
|
required: false
|
|
default: 'runner:runner'
|
|
pv-loop-path:
|
|
description: 'Absolute file path for the LVM image created on the root filesystem, the default is usually fine.'
|
|
required: false
|
|
default: '/pv.img'
|
|
tmp-pv-loop-path:
|
|
description: 'Absolute file path for the LVM image created on the temp filesystem, the default is usually fine. Must reside on /mnt'
|
|
required: false
|
|
default: '/mnt/tmp-pv.img'
|
|
remove-dotnet:
|
|
description: 'Removes .NET runtime and libraries. (frees ~17 GB)'
|
|
required: false
|
|
default: 'false'
|
|
remove-android:
|
|
description: 'Removes Android SDKs and Tools. (frees ~11 GB)'
|
|
required: false
|
|
default: 'false'
|
|
remove-haskell:
|
|
description: 'Removes GHC (Haskell) artifacts. (frees ~2.7 GB)'
|
|
required: false
|
|
default: 'false'
|
|
remove-codeql:
|
|
description: 'Removes CodeQL Action Bundles. (frees ~5.4 GB)'
|
|
required: false
|
|
default: 'false'
|
|
remove-docker-images:
|
|
description: 'Removes cached Docker images. (frees ~3 GB)'
|
|
required: false
|
|
default: 'false'
|
|
runs:
|
|
using: "composite"
|
|
steps:
|
|
- name: Disk space report before modification
|
|
shell: bash
|
|
run: |
|
|
echo "Memory and swap:"
|
|
sudo free -h
|
|
echo
|
|
sudo swapon --show
|
|
echo
|
|
|
|
echo "Available storage:"
|
|
sudo df -h
|
|
echo
|
|
|
|
- name: Maximize build disk space
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
BUILD_MOUNT_PATH="${{ inputs.build-mount-path }}"
|
|
if [[ -z "${BUILD_MOUNT_PATH}" ]]; then
|
|
BUILD_MOUNT_PATH="${GITHUB_WORKSPACE}"
|
|
fi
|
|
|
|
echo "Arguments:"
|
|
echo
|
|
echo " Root reserve: ${{ inputs.root-reserve-mb }} MiB"
|
|
echo " Temp reserve: ${{ inputs.temp-reserve-mb }} MiB"
|
|
echo " Swap space: ${{ inputs.swap-size-mb }} MiB"
|
|
echo " Overprovision LVM: ${{ inputs.overprovision-lvm }}"
|
|
echo " Mount path: ${BUILD_MOUNT_PATH}"
|
|
echo " Root PV loop path: ${{ inputs.pv-loop-path }}"
|
|
echo " Temp PV loop path: ${{ inputs.tmp-pv-loop-path }}"
|
|
echo -n " Removing: "
|
|
if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then
|
|
echo -n "dotnet "
|
|
fi
|
|
if [[ ${{ inputs.remove-android }} == 'true' ]]; then
|
|
echo -n "android "
|
|
fi
|
|
if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then
|
|
echo -n "haskell "
|
|
fi
|
|
if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then
|
|
echo -n "codeql "
|
|
fi
|
|
if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then
|
|
echo -n "docker "
|
|
fi
|
|
echo
|
|
|
|
# store owner of $GITHUB_WORKSPACE in case the action deletes it
|
|
WORKSPACE_OWNER="$(stat -c '%U:%G' "${GITHUB_WORKSPACE}")"
|
|
|
|
# ensure mount path exists before the action
|
|
sudo mkdir -p "${BUILD_MOUNT_PATH}"
|
|
sudo find "${BUILD_MOUNT_PATH}" -maxdepth 0 ! -empty -exec echo 'WARNING: directory [{}] is not empty, data loss might occur. Content:' \; -exec ls -al "{}" \;
|
|
|
|
echo "Removing unwanted software... "
|
|
if [[ ${{ inputs.remove-dotnet }} == 'true' ]]; then
|
|
sudo rm -rf /usr/share/dotnet
|
|
fi
|
|
if [[ ${{ inputs.remove-android }} == 'true' ]]; then
|
|
sudo rm -rf /usr/local/lib/android
|
|
fi
|
|
if [[ ${{ inputs.remove-haskell }} == 'true' ]]; then
|
|
sudo rm -rf /opt/ghc
|
|
fi
|
|
if [[ ${{ inputs.remove-codeql }} == 'true' ]]; then
|
|
sudo rm -rf /opt/hostedtoolcache/CodeQL
|
|
fi
|
|
if [[ ${{ inputs.remove-docker-images }} == 'true' ]]; then
|
|
sudo docker image prune --all --force
|
|
fi
|
|
echo "... done"
|
|
|
|
VG_NAME=buildvg
|
|
|
|
# github runners have an active swap file in /mnt/swapfile
|
|
# we want to reuse the temp disk, so first unmount swap and clean the temp disk
|
|
echo "Unmounting and removing swap file."
|
|
sudo swapoff -a
|
|
sudo rm -f /mnt/swapfile
|
|
|
|
echo "Creating LVM Volume."
|
|
echo " Creating LVM PV on root fs."
|
|
# create loop pv image on root fs
|
|
ROOT_RESERVE_KB=$(expr ${{ inputs.root-reserve-mb }} \* 1024)
|
|
ROOT_FREE_KB=$(df --block-size=1024 --output=avail / | tail -1)
|
|
ROOT_LVM_SIZE_KB=$(expr $ROOT_FREE_KB - $ROOT_RESERVE_KB)
|
|
ROOT_LVM_SIZE_BYTES=$(expr $ROOT_LVM_SIZE_KB \* 1024)
|
|
sudo touch "${{ inputs.pv-loop-path }}" && sudo fallocate -z -l "${ROOT_LVM_SIZE_BYTES}" "${{ inputs.pv-loop-path }}"
|
|
export ROOT_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.pv-loop-path }}")
|
|
sudo pvcreate -f "${ROOT_LOOP_DEV}"
|
|
|
|
# create pv on temp disk
|
|
echo " Creating LVM PV on temp fs."
|
|
TMP_RESERVE_KB=$(expr ${{ inputs.temp-reserve-mb }} \* 1024)
|
|
TMP_FREE_KB=$(df --block-size=1024 --output=avail /mnt | tail -1)
|
|
TMP_LVM_SIZE_KB=$(expr $TMP_FREE_KB - $TMP_RESERVE_KB)
|
|
TMP_LVM_SIZE_BYTES=$(expr $TMP_LVM_SIZE_KB \* 1024)
|
|
sudo touch "${{ inputs.tmp-pv-loop-path }}" && sudo fallocate -z -l "${TMP_LVM_SIZE_BYTES}" "${{ inputs.tmp-pv-loop-path }}"
|
|
export TMP_LOOP_DEV=$(sudo losetup --find --show "${{ inputs.tmp-pv-loop-path }}")
|
|
sudo pvcreate -f "${TMP_LOOP_DEV}"
|
|
|
|
# create volume group from these pvs
|
|
sudo vgcreate "${VG_NAME}" "${TMP_LOOP_DEV}" "${ROOT_LOOP_DEV}"
|
|
|
|
echo "Recreating swap"
|
|
# create and activate swap
|
|
sudo lvcreate -L "${{ inputs.swap-size-mb }}M" -n swap "${VG_NAME}"
|
|
sudo mkswap "/dev/mapper/${VG_NAME}-swap"
|
|
sudo swapon "/dev/mapper/${VG_NAME}-swap"
|
|
|
|
echo "Creating build volume"
|
|
# create and mount build volume
|
|
sudo lvcreate -l 100%FREE -n buildlv "${VG_NAME}"
|
|
if [[ ${{ inputs.overprovision-lvm }} == 'true' ]]; then
|
|
sudo mkfs.ext4 -m0 "/dev/mapper/${VG_NAME}-buildlv"
|
|
else
|
|
sudo mkfs.ext4 -Enodiscard -m0 "/dev/mapper/${VG_NAME}-buildlv"
|
|
fi
|
|
sudo mount "/dev/mapper/${VG_NAME}-buildlv" "${BUILD_MOUNT_PATH}"
|
|
sudo chown -R "${{ inputs.build-mount-path-ownership }}" "${BUILD_MOUNT_PATH}"
|
|
|
|
# if build mount path is a parent of $GITHUB_WORKSPACE, and has been deleted, recreate it
|
|
if [[ ! -d "${GITHUB_WORKSPACE}" ]]; then
|
|
sudo mkdir -p "${GITHUB_WORKSPACE}"
|
|
sudo chown -R "${WORKSPACE_OWNER}" "${GITHUB_WORKSPACE}"
|
|
fi
|
|
|
|
- name: Disk space report after modification
|
|
shell: bash
|
|
run: |
|
|
echo "Memory and swap:"
|
|
sudo free -h
|
|
echo
|
|
sudo swapon --show
|
|
echo
|
|
|
|
echo "Available storage:"
|
|
sudo df -h
|