2
0
Fork 0
mirror of https://code.forgejo.org/docker/build-push-action.git synced 2025-08-17 17:20:53 +00:00

src: move buildkit prune to cleanup stage and invoke it inline

Previously, we were firing off an async buildkit prune to clean
up layers unused in 14 days. This changes that to cleanup layers
unused in 7 days and fires it off inline on cleanup. It just seems
easier to reason about that way.
This commit is contained in:
Claude 2025-04-22 16:21:08 -04:00
parent 49f6d185dd
commit c80185915d
4 changed files with 29 additions and 16 deletions

2
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View file

@ -20,7 +20,7 @@ import * as context from './context';
import {promisify} from 'util'; import {promisify} from 'util';
import {exec} from 'child_process'; import {exec} from 'child_process';
import * as reporter from './reporter'; import * as reporter from './reporter';
import {setupStickyDisk, startAndConfigureBuildkitd, getNumCPUs, leaveTailnet} from './setup_builder'; import {setupStickyDisk, startAndConfigureBuildkitd, getNumCPUs, leaveTailnet, pruneBuildkitCache} from './setup_builder';
import {Metric_MetricType} from '@buf/blacksmith_vm-agent.bufbuild_es/stickydisk/v1/stickydisk_pb'; import {Metric_MetricType} from '@buf/blacksmith_vm-agent.bufbuild_es/stickydisk/v1/stickydisk_pb';
const buildxVersion = 'v0.17.0'; const buildxVersion = 'v0.17.0';
@ -74,9 +74,9 @@ export async function startBlacksmithBuilder(inputs: context.Inputs): Promise<{a
// If setup-only is true, we don't want to report the build to our control plane // If setup-only is true, we don't want to report the build to our control plane
// since we are only setting up the builder and therefore cannot expose any analytics // since we are only setting up the builder and therefore cannot expose any analytics
// about the build. // about the build.
const dockerfilePath = inputs.setupOnly ? "" : context.getDockerfilePath(inputs); const dockerfilePath = inputs.setupOnly ? '' : context.getDockerfilePath(inputs);
if (!inputs.setupOnly && !dockerfilePath) { if (!inputs.setupOnly && !dockerfilePath) {
throw new Error('Failed to resolve dockerfile path'); throw new Error('Failed to resolve dockerfile path');
} }
const stickyDiskStartTime = Date.now(); const stickyDiskStartTime = Date.now();
const stickyDiskSetup = await setupStickyDisk(dockerfilePath || '', inputs.setupOnly); const stickyDiskSetup = await setupStickyDisk(dockerfilePath || '', inputs.setupOnly);
@ -217,7 +217,6 @@ actionsToolkit.run(
core.warning(`Failed to create builder setup sentinel file: ${error.message}`); core.warning(`Failed to create builder setup sentinel file: ${error.message}`);
} }
let builder: BuilderInfo; let builder: BuilderInfo;
await core.group(`Builder info`, async () => { await core.group(`Builder info`, async () => {
builder = await toolkit.builder.inspect(); builder = await toolkit.builder.inspect();
@ -227,11 +226,10 @@ actionsToolkit.run(
// If setup-only is true, we don't want to continue configuring and running the build. // If setup-only is true, we don't want to continue configuring and running the build.
if (inputs.setupOnly) { if (inputs.setupOnly) {
core.info('setup-only mode enabled, builder is ready for use by Docker'); core.info('setup-only mode enabled, builder is ready for use by Docker');
// Let's remove the default // Let's remove the default
process.exit(0); process.exit(0);
} }
await core.group(`Proxy configuration`, async () => { await core.group(`Proxy configuration`, async () => {
let dockerConfig: ConfigFile | undefined; let dockerConfig: ConfigFile | undefined;
let dockerConfigMalformed = false; let dockerConfigMalformed = false;
@ -362,6 +360,16 @@ actionsToolkit.run(
}); });
} }
// Prune buildkit cache to clean up unused layers before shutting down buildkitd.
try {
core.info('Pruning BuildKit cache');
await pruneBuildkitCache();
core.info('BuildKit cache pruned');
} catch (error) {
// Log warning but don't fail the cleanup
core.warning(`Error pruning BuildKit cache: ${error.message}`);
}
await leaveTailnet(); await leaveTailnet();
try { try {
@ -448,6 +456,16 @@ actionsToolkit.run(
try { try {
const {stdout} = await execAsync('pgrep buildkitd'); const {stdout} = await execAsync('pgrep buildkitd');
if (stdout.trim()) { if (stdout.trim()) {
// Prune buildkit cache to clean up unused layers before shutting down buildkitd.
try {
core.info('Pruning BuildKit cache');
await pruneBuildkitCache();
core.info('BuildKit cache pruned');
} catch (error) {
// Log warning but don't fail the cleanup
core.warning(`Error pruning BuildKit cache: ${error.message}`);
}
await shutdownBuildkitd(); await shutdownBuildkitd();
core.info('Shutdown buildkitd'); core.info('Shutdown buildkitd');
} }

View file

@ -300,16 +300,11 @@ export async function startAndConfigureBuildkitd(parallelism: number, setupOnly:
throw error; throw error;
} }
// Start cache pruning in the background without blocking.
pruneBuildkitCache().catch(error => {
core.warning(`Background cache pruning failed: ${error.message}`);
});
return addr; return addr;
} }
/** /**
* Prunes buildkit cache data older than 14 days. * Prunes buildkit cache data older than 7 days.
* We don't specify any keep bytes here since we are * We don't specify any keep bytes here since we are
* handling the ceph volume size limits ourselves in * handling the ceph volume size limits ourselves in
* the VM Agent. * the VM Agent.
@ -317,8 +312,8 @@ export async function startAndConfigureBuildkitd(parallelism: number, setupOnly:
*/ */
export async function pruneBuildkitCache(): Promise<void> { export async function pruneBuildkitCache(): Promise<void> {
try { try {
const fourteenDaysInHours = 14 * 24; const sevenDaysInHours = 7 * 24;
await execAsync(`sudo buildctl --addr ${BUILDKIT_DAEMON_ADDR} prune --keep-duration ${fourteenDaysInHours}h --all`); await execAsync(`sudo buildctl --addr ${BUILDKIT_DAEMON_ADDR} prune --keep-duration ${sevenDaysInHours}h --all`);
core.debug('Successfully pruned buildkit cache'); core.debug('Successfully pruned buildkit cache');
} catch (error) { } catch (error) {
core.warning(`Error pruning buildkit cache: ${error.message}`); core.warning(`Error pruning buildkit cache: ${error.message}`);