From c25baf69e17606938c141a9b0b586ccbdf45dc14 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 4 Dec 2023 11:20:50 +0100 Subject: [PATCH] fix: workdir issue for basedir fix: remove / mount on helpers image --- app/Jobs/ApplicationDeploymentJob.php | 32 +++++++---------- app/Models/Application.php | 4 +-- bootstrap/helpers/applications.php | 4 +-- bootstrap/helpers/shared.php | 51 +++++++++++++++++++++++++-- 4 files changed, 66 insertions(+), 25 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 2b4796862..3b2313e19 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -347,6 +347,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->generate_image_names(); $this->check_image_locally_or_remotely(); if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) { + $this->create_workdir(); $this->generate_compose_file(); $this->rolling_update(); return; @@ -442,10 +443,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->clone_repository(); $this->generate_image_names(); $this->cleanup_git(); + $this->application->loadComposeFile(isInit: false); $composeFile = $this->application->parseCompose(pull_request_id: $this->pull_request_id); $yaml = Yaml::dump($composeFile->toArray(), 10); - ray($composeFile); - ray($this->container_name); $this->docker_compose_base64 = base64_encode($yaml); $this->execute_remote_command([ executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}{$this->docker_compose_location}"), "hidden" => true @@ -453,12 +453,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->save_environment_variables(); $this->stop_running_container(force: true); - ray($this->pull_request_id); $networkId = $this->application->uuid; if ($this->pull_request_id !== 0) { $networkId = "{$this->application->uuid}-{$this->pull_request_id}"; } - ray($networkId); if ($this->server->isSwarm()) { // TODO } else { @@ -487,7 +485,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted ); } $this->start_by_compose_file(); - $this->application->loadComposeFile(isInit: false); } private function deploy_dockerfile_buildpack() { @@ -530,6 +527,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if (!$this->force_rebuild) { $this->check_image_locally_or_remotely(); if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) { + $this->create_workdir(); $this->execute_remote_command([ "echo 'No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.'", ]); @@ -677,7 +675,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true], ); } - + private function create_workdir() + { + $this->execute_remote_command( + [ + "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}") + ], + ); + } private function prepare_builder_image() { $helperImage = config('coolify.helper_image'); @@ -686,9 +691,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server); if ($this->dockerConfigFileExists === 'OK') { - $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; + $runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; } else { - $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; + $runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; } $this->execute_remote_command( [ @@ -703,13 +708,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted ], ); - if ($this->restart_only || !$this->force_rebuild) { - $this->execute_remote_command( - [ - "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}") - ], - ); - } } private function deploy_to_additional_destinations() { @@ -1250,10 +1248,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true], ); - } else if ($this->application->build_pack === 'dockercompose') { - $this->execute_remote_command( - ["docker compose --project-directory {$this->configuration_dir} up --build -d", "hidden" => true], - ); } else { $this->execute_remote_command( [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true], diff --git a/app/Models/Application.php b/app/Models/Application.php index 5d5082cbf..341d6faf5 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -587,12 +587,12 @@ class Application extends BaseModel $commands = collect([]); if ($dockerConfigFileExists === 'OK') { $commands->push([ - "command" => "docker run -d --network $network -v /:/host --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage", + "command" => "docker run -d --network $network --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage", "hidden" => true, ]); } else { $commands->push([ - "command" => "docker run -d --network {$network} -v /:/host --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}", + "command" => "docker run -d --network {$network} --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}", "hidden" => true, ]); } diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php index bc0de5c47..25ca66241 100644 --- a/bootstrap/helpers/applications.php +++ b/bootstrap/helpers/applications.php @@ -97,12 +97,12 @@ function prepareHelperContainer(Server $server, string $network, string $deploym $commands = collect([]); if ($dockerConfigFileExists === 'OK') { $commands->push([ - "command" => "docker run -d --network $network -v /:/host --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage", + "command" => "docker run -d --network $network --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage", "hidden" => true, ]); } else { $commands->push([ - "command" => "docker run -d --network {$network} -v /:/host --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}", + "command" => "docker run -d --network {$network} --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}", "hidden" => true, ]); } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index d52aa4d8e..8e63cfe3b 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -1003,7 +1003,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($savedService->serviceType()) { $fqdns = generateServiceSpecificFqdns($savedService, forTraefik: true); } else { - $fqdns = collect(data_get($savedService, 'fqdns')); + $fqdns = collect(data_get($savedService, 'fqdns'))->filter(); } $defaultLabels = defaultLabels($resource->id, $containerName, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id); $serviceLabels = $serviceLabels->merge($defaultLabels); @@ -1102,6 +1102,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $serviceNetworks = collect(data_get($service, 'networks', [])); $serviceVariables = collect(data_get($service, 'environment', [])); $serviceLabels = collect(data_get($service, 'labels', [])); + $serviceBuildVariables = collect(data_get($service, 'build.args', [])); + $serviceVariables = $serviceVariables->merge($serviceBuildVariables); if ($serviceLabels->count() > 0) { $removedLabels = collect([]); $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) { @@ -1148,7 +1150,52 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal data_set($service, 'volumes', $serviceVolumes->toArray()); } } else { - // TODO + if (count($serviceVolumes) > 0) { + $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) { + if (is_string($volume)) { + $volume = str($volume); + if ($volume->contains(':')) { + $name = $volume->before(':'); + $mount = $volume->after(':'); + if ($name->startsWith('.') || $name->startsWith('~')) { + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + if ($name->startsWith('.')) { + $name = $name->replaceFirst('.', $dir); + } + if ($name->startsWith('~')) { + $name = $name->replaceFirst('~', $dir); + } + $volume = str("$name:$mount"); + } else { + $topLevelVolumes->put($name->value(), [ + 'name' => $name->value(), + ]); + } + } + } else if (is_array($volume)) { + $source = data_get($volume, 'source'); + if ($source) { + if (str($source, '.') || str($source, '~')) { + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + if (str($source, '.')) { + $source = str('.', $dir, $source); + } + if (str($source, '~')) { + $source = str('~', $dir, $source); + } + data_set($volume, 'source', $source); + } else { + data_set($volume, 'source', $source); + $topLevelVolumes->put($source, [ + 'name' => $source, + ]); + } + } + } + return $volume->value(); + }); + data_set($service, 'volumes', $serviceVolumes->toArray()); + } } // Decide if the service is a database $isDatabase = isDatabaseImage(data_get_str($service, 'image'));