ops(docker): prune unused cache on deploys and nightly
CI / check (push) Failing after 23s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

Add scripts/docker-prune.sh (build cache >72h capped at 4g, unreferenced images >7d, stopped containers >24h; never volumes), run it after every CI deploy and compose update, and schedule a nightly prune from the host-side jobs-worker. Tighten the deployment contract tests to assert the scoped-prune boundaries.
This commit is contained in:
openhands committed 2026-09-13 13:04:03 +02:00
1 parent fb68df3ba9
commit 47917bb63b
6 files changed
+102 -5

No files matched your search

+9 -1
View File
@@ -26,10 +26,18 @@ it("preserves production runtime configuration and recent cache", () => {
expect(deploy).toContain("/var/www/Gamedata:/var/www/Gamedata");
expect(deploy).toContain("/app/storage");
expect(deploy).not.toContain("--env-file");
expect(deploy).toContain(
// The scoped prune lives in docker-prune.sh; deploys invoke it for both CI
// and scheduled updates. It reclaims build cache + old unreferenced images
// but never touches volumes.
expect(deploy).toContain("bash \"$deploy_dir/scripts/docker-prune.sh\"");
const prune = readFileSync("scripts/docker-prune.sh", "utf8");
expect(prune).toContain(
'docker builder prune -af --filter "until=72h" --max-used-space=4g',
);
expect(prune).toContain('docker image prune -af --filter "until=168h"');
expect(prune).toContain('docker container prune -f --filter "until=24h"');
expect(deploy).not.toContain("docker volume prune");
expect(prune).not.toContain("docker volume prune");
});
it("builds the checked out source without fetching a moving remote branch", () => {
const dockerfile = readFileSync("Dockerfile", "utf8");
+12 -2
View File
@@ -46,6 +46,10 @@ function simulate(scenario: string) {
resolve(root, "scripts/docker-update.sh"),
join(dir, "scripts/docker-update.sh"),
);
copyFileSync(
resolve(root, "scripts/docker-prune.sh"),
join(dir, "scripts/docker-prune.sh"),
);
writeFileSync(join(dir, ".env"), "HOTEL_NAME=Test\n");
if (scenario.startsWith("saved-"))
writeFileSync(
@@ -93,7 +97,7 @@ describe("Docker clone updates", () => {
expect(r.calls).toContain(
`docker pull registry.test/team/cms:${sha}-migrations`,
);
expect(r.calls).not.toContain("docker build");
expect(r.calls).not.toMatch(/docker build\s/);
expect(r.calls).not.toContain("docker compose build");
expect(r.calls).toContain("target=/app/.env,readonly");
});
@@ -140,7 +144,13 @@ describe("Docker clone updates", () => {
);
expect(r.calls).toContain("https://example.test/api/health");
expect(r.output).toContain(`Verified release ${sha}`);
expect(r.calls).not.toContain("prune");
// A successful update runs the scoped prune (build cache + unreferenced
// images + stopped containers), never a global or volume prune.
expect(r.calls).toContain("docker builder prune");
expect(r.calls).toContain("docker image prune");
expect(r.calls).toContain("docker container prune");
expect(r.calls).not.toContain("docker volume prune");
expect(r.calls).not.toContain("docker system prune");
});
it.each([
"dirty",