fix(docker): preserve resource containers during cleanup

This commit is contained in:
Andras Bacsai committed 2026-10-09 08:22:08 +02:00
1 parent df953bdcd1
commit d07bc9c0ff
5 files changed
+46 -5

No files matched your search

+15 -1
View File
@@ -161,7 +161,7 @@ class CleanupDocker implements ShouldBeUnique
);
$commands = [
'docker container prune -f --filter "label=coolify.managed=true" --filter "label!=coolify.proxy=true" --filter "label!=coolify.type=database" --filter "label!=coolify.type=application" --filter "label!=coolify.type=service"',
$this->buildContainerPruneCommand(),
$imagePruneCmd,
'docker builder prune -af',
"docker run --rm -v {$buildxMetadataVolume}:/root/.docker/buildx -v /var/run/docker.sock:/var/run/docker.sock {$helperImageWithVersion} docker buildx prune --builder coolify-railpack -af 2>/dev/null || true",
@@ -207,6 +207,20 @@ class CleanupDocker implements ShouldBeUnique
return instant_remote_process([$command], $server, false, timeout: $remaining);
}
/**
* Build a command that removes stopped Coolify containers, except the proxy and the
* containers of databases, applications and services.
*
* docker container prune only excludes a container that matches all of its label!= filters
* together, so we list the stopped containers and filter them by label in the shell.
*/
private function buildContainerPruneCommand(): string
{
return "docker ps -a --filter status=created --filter status=exited --filter status=dead --filter label=coolify.managed=true --format '{{.ID}} coolify.proxy={{.Label \"coolify.proxy\"}} coolify.type={{.Label \"coolify.type\"}}' | ".
"grep -v -E 'coolify\.proxy=true |coolify\.type=(database|application|service)$' | ".
"awk '{print $1}' | xargs -r docker rm";
}
/**
* Build a docker image prune command that excludes application image repositories.
*
+1 -1
View File
@@ -5,7 +5,7 @@ $sshCommandTimeout = (int) env('SSH_COMMAND_TIMEOUT', 3600);
return [
'coolify' => [
'version' => env('COOLIFY_VERSION') ?: '4.4.3',
'version' => env('COOLIFY_VERSION') ?: '4.4.4',
'helper_version' => '1.0.17',
'railpack_version' => '0.23.0',
'self_hosted' => env('SELF_HOSTED', true),
+1 -1
View File
@@ -1,7 +1,7 @@
{
"coolify": {
"v4": {
"version": "4.4.3"
"version": "4.4.4"
},
"nightly": {
"version": "4.5-rc.1"
+28 -1
View File
@@ -372,7 +372,7 @@ it('gives remote cleanup commands a local timeout and fails once the cleanup dea
expect(fn () => CleanupDocker::run($server))
->toThrow(RuntimeException::class, 'Docker cleanup did not finish within '.CleanupDocker::REMOTE_COMMANDS_DEADLINE.' seconds');
$sshCommands = $commands->filter(fn (string $command) => str_contains($command, 'docker container prune') || str_contains($command, 'docker image prune'))->values();
$sshCommands = $commands->filter(fn (string $command) => str_contains($command, 'label=coolify.managed=true') || str_contains($command, 'docker image prune'))->values();
expect(CleanupDocker::REMOTE_COMMANDS_DEADLINE)->toBeLessThan(CleanupDocker::JOB_TIMEOUT)
->and($sshCommands)->toHaveCount(2)
@@ -498,3 +498,30 @@ it('scans application images with a fixed number of remote commands and keeps th
expect($removal)->not->toContain($kept);
}
});
it('removes stopped Coolify containers but keeps the proxy, databases, applications and services', function () {
$command = (new ReflectionMethod(CleanupDocker::class, 'buildContainerPruneCommand'))->invoke(new CleanupDocker);
preg_match("/--format '([^']+)'/", $command, $format);
$stoppedContainers = collect([
['proxy', 'true', ''],
['database', '', 'database'],
['application', '', 'application'],
['service', '', 'service'],
['helper', '', ''],
])->map(fn (array $container) => str_replace(['{{.ID}}', '{{.Label "coolify.proxy"}}', '{{.Label "coolify.type"}}'], $container, $format[1]));
// Fake docker on PATH: `docker ps` prints the stopped containers, `docker rm` prints what it is asked to remove
$bin = sys_get_temp_dir().'/docker-cleanup-'.bin2hex(random_bytes(4));
mkdir($bin);
file_put_contents("$bin/containers", $stoppedContainers->implode("\n")."\n");
file_put_contents("$bin/docker", "#!/bin/sh\nif [ \"\$1\" = ps ]; then cat $bin/containers; else echo \"\$@\"; fi\n");
chmod("$bin/docker", 0755);
$output = shell_exec('PATH='.escapeshellarg("$bin:".getenv('PATH')).' /bin/sh -c '.escapeshellarg($command));
array_map('unlink', glob("$bin/*"));
rmdir($bin);
expect($command)->toContain('--filter label=coolify.managed=true')
->and(trim((string) $output))->toBe('rm helper');
});
+1 -1
View File
@@ -1,7 +1,7 @@
{
"coolify": {
"v4": {
"version": "4.4.3"
"version": "4.4.4"
},
"nightly": {
"version": "4.5-rc.1"