mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-15 00:17:16 +00:00
fix(docker): replace deprecated stop flags with version-aware ones
Store each server's Docker version and build stop commands via dockerStopCommand() so newer Docker uses --timeout instead of deprecated --time/-t. Also show Docker version in server details.
This commit is contained in:
1 parent
6481ffffcf
commit
e79230cf37
32 files changed
+697
-64
No files matched your search
@@ -40,7 +40,7 @@ class StopApplication
|
||||
|
||||
foreach ($containersToStop as $containerName) {
|
||||
instant_remote_process(command: [
|
||||
"docker stop --time=$timeout $containerName",
|
||||
dockerStopCommand($timeout, $containerName, $server),
|
||||
"docker rm -f $containerName",
|
||||
], server: $server, throwError: false);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class StopApplicationOneServer
|
||||
if ($containerName) {
|
||||
instant_remote_process(
|
||||
[
|
||||
"docker stop --time=$timeout $containerName",
|
||||
dockerStopCommand($timeout, $containerName, $server),
|
||||
"docker rm -f $containerName",
|
||||
],
|
||||
$server
|
||||
|
||||
@@ -104,7 +104,7 @@ class StartClickhouse
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
@@ -191,7 +191,7 @@ class StartDragonfly
|
||||
if ($this->database->enable_ssl) {
|
||||
$this->commands[] = "chown -R 999:999 $this->configuration_dir/ssl/server.key $this->configuration_dir/ssl/server.crt";
|
||||
}
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
@@ -209,7 +209,7 @@ class StartKeydb
|
||||
if (! is_null($this->database->keydb_conf) && ! empty($this->database->keydb_conf)) {
|
||||
$this->commands[] = "chown 999:999 $this->configuration_dir/keydb.conf";
|
||||
}
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
@@ -208,7 +208,7 @@ class StartMariadb
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
@@ -257,7 +257,7 @@ class StartMongodb
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
if ($this->database->enable_ssl) {
|
||||
|
||||
@@ -209,7 +209,7 @@ class StartMysql
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ class StartPostgresql
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
if ($this->database->enable_ssl) {
|
||||
|
||||
@@ -204,7 +204,7 @@ class StartRedis
|
||||
if (! is_null($this->database->redis_conf) && ! empty($this->database->redis_conf)) {
|
||||
$this->commands[] = "chown 999:999 $this->configuration_dir/redis.conf";
|
||||
}
|
||||
$this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true";
|
||||
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
|
||||
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
@@ -56,7 +56,7 @@ class StopDatabase
|
||||
{
|
||||
$server = $database->destination->server;
|
||||
instant_remote_process(command: [
|
||||
"docker stop -t $timeout $containerName",
|
||||
dockerStopCommand($timeout, $containerName, $server),
|
||||
"docker rm -f $containerName",
|
||||
], server: $server, throwError: false);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class StopProxy
|
||||
}
|
||||
|
||||
instant_remote_process(command: [
|
||||
"docker stop -t=$timeout $containerName 2>/dev/null || true",
|
||||
dockerStopCommand($timeout, $containerName, $server).' 2>/dev/null || true',
|
||||
"docker rm -f $containerName 2>/dev/null || true",
|
||||
'# Wait for container to be fully removed',
|
||||
'for i in {1..10}; do',
|
||||
|
||||
@@ -67,7 +67,7 @@ class StopService
|
||||
$timeout = count($containersToStop) > 5 ? 10 : 30;
|
||||
$commands = [];
|
||||
$containerList = implode(' ', $containersToStop);
|
||||
$commands[] = "docker stop -t $timeout $containerList";
|
||||
$commands[] = dockerStopCommand($timeout, $containerList, $server);
|
||||
$commands[] = "docker rm -f $containerList";
|
||||
instant_remote_process(
|
||||
command: $commands,
|
||||
|
||||
@@ -431,6 +431,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
["docker version --format '{{.Server.Version}}'"],
|
||||
$serverToCheck
|
||||
);
|
||||
$serverToCheck->rememberDockerVersion($dockerVersion);
|
||||
|
||||
$versionParts = explode('.', $dockerVersion);
|
||||
$majorVersion = (int) $versionParts[0];
|
||||
@@ -3972,11 +3973,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
|
||||
if ($skipRemove) {
|
||||
$this->execute_remote_command(
|
||||
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||
[dockerStopCommand($timeout, $containerName, $this->server), 'hidden' => true, 'ignore_errors' => true]
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true],
|
||||
[dockerStopCommand($timeout, $containerName, $this->server), 'hidden' => true, 'ignore_errors' => true],
|
||||
["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
$containerList = implode(' ', array_map('escapeshellarg', $containerNames));
|
||||
$commands = [
|
||||
"docker stop -t $timeout $containerList",
|
||||
dockerStopCommand($timeout, $containerList, $server),
|
||||
"docker rm -f $containerList",
|
||||
];
|
||||
instant_remote_process(
|
||||
|
||||
@@ -98,7 +98,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
|
||||
// === STOP PHASE ===
|
||||
$commands = $commands->merge([
|
||||
"echo 'Stopping proxy...'",
|
||||
"docker stop -t=$stopTimeout $containerName 2>/dev/null || true",
|
||||
dockerStopCommand($stopTimeout, $containerName, $this->server).' 2>/dev/null || true',
|
||||
"docker rm -f $containerName 2>/dev/null || true",
|
||||
'# Wait for container to be fully removed',
|
||||
'for i in {1..15}; do',
|
||||
|
||||
@@ -194,6 +194,20 @@ class ServerConnectionCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$output = trim($output);
|
||||
if (! empty($output)) {
|
||||
$dockerInfo = json_decode($output, true);
|
||||
$dockerVersion = dockerEngineVersionFromJson($output);
|
||||
if ($dockerVersion !== null) {
|
||||
$this->server->rememberDockerVersion($dockerVersion);
|
||||
}
|
||||
|
||||
$composeOutput = instant_remote_process_with_timeout(
|
||||
['docker compose version --short'],
|
||||
$this->server,
|
||||
false
|
||||
);
|
||||
$composeVersion = parseDockerEngineVersion($composeOutput);
|
||||
if ($composeVersion !== null) {
|
||||
$this->server->rememberComposeVersion($composeVersion);
|
||||
}
|
||||
|
||||
return isset($dockerInfo['Server']['Version']);
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ class Previews extends Component
|
||||
|
||||
foreach ($containersToStop as $containerName) {
|
||||
instant_remote_process(command: [
|
||||
"docker stop --time=$timeout $containerName",
|
||||
dockerStopCommand($timeout, $containerName, $server),
|
||||
"docker rm -f $containerName",
|
||||
], server: $server, throwError: false);
|
||||
}
|
||||
|
||||
@@ -371,6 +371,8 @@ class Show extends Component
|
||||
$this->server->settings->is_usable = $this->isUsable = true;
|
||||
$this->server->settings->save();
|
||||
ServerReachabilityChanged::dispatch($this->server);
|
||||
$this->server->gatherServerMetadata();
|
||||
$this->server->refresh();
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);
|
||||
|
||||
@@ -671,12 +673,18 @@ class Show extends Component
|
||||
{
|
||||
try {
|
||||
$this->authorize('update', $this->server);
|
||||
if (! $this->server->isFunctional()) {
|
||||
$this->dispatch('error', 'Validate the server connection before fetching details.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->server->gatherServerMetadata();
|
||||
if ($result) {
|
||||
$this->server->refresh();
|
||||
$this->server->refresh()->load('settings');
|
||||
$this->dispatch('success', 'Server details refreshed.');
|
||||
} else {
|
||||
$this->dispatch('error', 'Could not fetch server details. Is the server reachable?');
|
||||
$this->dispatch('error', 'Could not collect server details. Check the application logs for the remote command output.');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
handleError($e, $this);
|
||||
|
||||
+48
-2
@@ -961,7 +961,7 @@ $schema://$host {
|
||||
|
||||
public function stopUnmanaged($id)
|
||||
{
|
||||
return instant_remote_process(['docker stop -t 0 '.escapeshellarg($id)], $this);
|
||||
return instant_remote_process([dockerStopCommand(0, escapeshellarg($id), $this)], $this);
|
||||
}
|
||||
|
||||
public function restartUnmanaged($id)
|
||||
@@ -1351,7 +1351,7 @@ $schema://$host {
|
||||
|
||||
try {
|
||||
$output = instant_remote_process([
|
||||
'echo "---PRETTY_NAME---" && grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d \'"\' && echo "---ARCH---" && uname -m && echo "---KERNEL---" && uname -r && echo "---CPUS---" && nproc && echo "---MEMORY---" && free -b | awk \'/Mem:/{print $2}\' && echo "---UPTIME_SINCE---" && uptime -s',
|
||||
'echo "---PRETTY_NAME---" && grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d \'"\' && echo "---ARCH---" && uname -m && echo "---KERNEL---" && uname -r && echo "---CPUS---" && nproc && echo "---MEMORY---" && free -b | awk \'/Mem:/{print $2}\' && echo "---UPTIME_SINCE---" && uptime -s && echo "---DOCKER---" && (docker version --format \'{{.Server.Version}}\' 2>/dev/null || true) && echo "---COMPOSE---" && (docker compose version --short 2>/dev/null || true)',
|
||||
], $this, false);
|
||||
|
||||
if (! $output) {
|
||||
@@ -1381,6 +1381,23 @@ $schema://$host {
|
||||
|
||||
$this->update(['server_metadata' => $metadata]);
|
||||
|
||||
try {
|
||||
$detectedDockerVersion = parseDockerEngineVersion($sections['DOCKER'] ?? null);
|
||||
if ($detectedDockerVersion !== null) {
|
||||
$this->rememberDockerVersion($detectedDockerVersion);
|
||||
}
|
||||
|
||||
$detectedComposeVersion = parseDockerEngineVersion($sections['COMPOSE'] ?? null);
|
||||
if ($detectedComposeVersion !== null) {
|
||||
$this->rememberComposeVersion($detectedComposeVersion);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::debug('Failed to store server runtime versions', [
|
||||
'server_id' => $this->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
} catch (\Throwable $e) {
|
||||
Log::debug('Failed to gather server metadata', [
|
||||
@@ -1604,11 +1621,40 @@ $schema://$host {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dockerVersion(): ?string
|
||||
{
|
||||
return $this->settings?->docker_version;
|
||||
}
|
||||
|
||||
public function rememberDockerVersion(?string $version): void
|
||||
{
|
||||
$this->settings->update([
|
||||
'docker_version' => parseDockerEngineVersion($version),
|
||||
'docker_version_checked_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function composeVersion(): ?string
|
||||
{
|
||||
return $this->settings?->compose_version;
|
||||
}
|
||||
|
||||
public function rememberComposeVersion(?string $version): void
|
||||
{
|
||||
$this->settings->update([
|
||||
'compose_version' => parseDockerEngineVersion($version),
|
||||
'compose_version_checked_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function validateDockerEngineVersion()
|
||||
{
|
||||
$dockerVersionRaw = instant_remote_process(['docker version --format json'], $this, false);
|
||||
$dockerVersionJson = json_decode($dockerVersionRaw, true);
|
||||
$dockerVersion = data_get($dockerVersionJson, 'Server.Version', '0.0.0');
|
||||
$this->rememberDockerVersion(is_string($dockerVersion) ? $dockerVersion : null);
|
||||
$composeVersionRaw = instant_remote_process(['docker compose version --short'], $this, false);
|
||||
$this->rememberComposeVersion(is_string($composeVersionRaw) ? $composeVersionRaw : null);
|
||||
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||
if (is_null($dockerVersion)) {
|
||||
$this->settings->is_usable = false;
|
||||
|
||||
@@ -51,6 +51,10 @@ use OpenApi\Attributes as OA;
|
||||
'delete_unused_volumes' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused volumes should be deleted.'],
|
||||
'delete_unused_networks' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused networks should be deleted.'],
|
||||
'connection_timeout' => ['type' => 'integer', 'description' => 'SSH connection timeout in seconds.'],
|
||||
'docker_version' => ['type' => 'string', 'nullable' => true, 'description' => 'Detected Docker Engine version on the server.'],
|
||||
'docker_version_checked_at' => ['type' => 'string', 'nullable' => true, 'description' => 'When Docker Engine version was last detected.'],
|
||||
'compose_version' => ['type' => 'string', 'nullable' => true, 'description' => 'Detected Docker Compose plugin version on the server.'],
|
||||
'compose_version_checked_at' => ['type' => 'string', 'nullable' => true, 'description' => 'When Docker Compose version was last detected.'],
|
||||
]
|
||||
)]
|
||||
class ServerSetting extends Model
|
||||
@@ -100,6 +104,10 @@ class ServerSetting extends Model
|
||||
'deployment_queue_limit',
|
||||
'disable_application_image_retention',
|
||||
'connection_timeout',
|
||||
'docker_version',
|
||||
'docker_version_checked_at',
|
||||
'compose_version',
|
||||
'compose_version_checked_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -113,6 +121,8 @@ class ServerSetting extends Model
|
||||
'is_terminal_enabled' => 'boolean',
|
||||
'disable_application_image_retention' => 'boolean',
|
||||
'connection_timeout' => 'integer',
|
||||
'docker_version_checked_at' => 'datetime',
|
||||
'compose_version_checked_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user