diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php index fe0976250..3f6449af2 100644 --- a/app/Actions/Database/StartDatabaseProxy.php +++ b/app/Actions/Database/StartDatabaseProxy.php @@ -21,26 +21,33 @@ class StartDatabaseProxy $type = $database->getMorphClass(); $network = data_get($database, 'destination.network'); $server = data_get($database, 'destination.server'); + $containerName = data_get($database, 'uuid'); + $proxyContainerName = "{$database->uuid}-proxy"; if ($database->getMorphClass() === 'App\Models\ServiceDatabase') { $databaseType = $database->databaseType(); $network = data_get($database, 'service.destination.network'); $server = data_get($database, 'service.destination.server'); - ray($databaseType, $network); + $proxyContainerName = "{$database->service->uuid}-proxy"; switch ($databaseType) { case 'standalone-mariadb': $type = 'App\Models\StandaloneMariadb'; + $containerName = "mariadb-{$database->service->uuid}"; break; case 'standalone-mongodb': $type = 'App\Models\StandaloneMongodb'; + $containerName = "mongodb-{$database->service->uuid}"; break; case 'standalone-mysql': $type = 'App\Models\StandaloneMysql'; + $containerName = "mysql-{$database->service->uuid}"; break; case 'standalone-postgresql': $type = 'App\Models\StandalonePostgresql'; + $containerName = "postgresql-{$database->service->uuid}"; break; case 'standalone-redis': $type = 'App\Models\StandaloneRedis'; + $containerName = "redis-{$database->service->uuid}"; break; } } @@ -55,7 +62,6 @@ class StartDatabaseProxy } else if ($type === 'App\Models\StandaloneMariadb') { $internalPort = 3306; } - $containerName = "{$database->uuid}-proxy"; $configuration_dir = database_proxy_dir($database->uuid); $nginxconf = <<public_port; - proxy_pass $database->uuid:$internalPort; + proxy_pass $containerName:$internalPort; } } EOF; @@ -81,13 +87,13 @@ class StartDatabaseProxy $docker_compose = [ 'version' => '3.8', 'services' => [ - $containerName => [ + $proxyContainerName => [ 'build' => [ 'context' => $configuration_dir, 'dockerfile' => 'Dockerfile', ], 'image' => "nginx:stable-alpine", - 'container_name' => $containerName, + 'container_name' => $proxyContainerName, 'restart' => RESTART_MODE, 'ports' => [ "$database->public_port:$database->public_port", diff --git a/app/Actions/Database/StartMariadb.php b/app/Actions/Database/StartMariadb.php index 75fd69adc..14110cf9b 100644 --- a/app/Actions/Database/StartMariadb.php +++ b/app/Actions/Database/StartMariadb.php @@ -56,7 +56,7 @@ class StartMariadb 'memswap_limit' => $this->database->limits_memory_swap, 'mem_swappiness' => $this->database->limits_memory_swappiness, 'mem_reservation' => $this->database->limits_memory_reservation, - 'cpus' => $this->database->limits_cpus, + 'cpus' => (int) $this->database->limits_cpus, 'cpuset' => $this->database->limits_cpuset, 'cpu_shares' => $this->database->limits_cpu_shares, ] diff --git a/app/Actions/Database/StartMongodb.php b/app/Actions/Database/StartMongodb.php index 8bfb9a982..bc21bf50a 100644 --- a/app/Actions/Database/StartMongodb.php +++ b/app/Actions/Database/StartMongodb.php @@ -63,7 +63,7 @@ class StartMongodb 'memswap_limit' => $this->database->limits_memory_swap, 'mem_swappiness' => $this->database->limits_memory_swappiness, 'mem_reservation' => $this->database->limits_memory_reservation, - 'cpus' => $this->database->limits_cpus, + 'cpus' => (int) $this->database->limits_cpus, 'cpuset' => $this->database->limits_cpuset, 'cpu_shares' => $this->database->limits_cpu_shares, ] diff --git a/app/Actions/Database/StartMysql.php b/app/Actions/Database/StartMysql.php index 8ee0db6e9..103affb89 100644 --- a/app/Actions/Database/StartMysql.php +++ b/app/Actions/Database/StartMysql.php @@ -56,7 +56,7 @@ class StartMysql 'memswap_limit' => $this->database->limits_memory_swap, 'mem_swappiness' => $this->database->limits_memory_swappiness, 'mem_reservation' => $this->database->limits_memory_reservation, - 'cpus' => $this->database->limits_cpus, + 'cpus' => (int) $this->database->limits_cpus, 'cpuset' => $this->database->limits_cpuset, 'cpu_shares' => $this->database->limits_cpu_shares, ] diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php index 2dc9a38b0..6821926be 100644 --- a/app/Actions/Database/StartPostgresql.php +++ b/app/Actions/Database/StartPostgresql.php @@ -66,7 +66,7 @@ class StartPostgresql 'memswap_limit' => $this->database->limits_memory_swap, 'mem_swappiness' => $this->database->limits_memory_swappiness, 'mem_reservation' => $this->database->limits_memory_reservation, - 'cpus' => $this->database->limits_cpus, + 'cpus' => (int) $this->database->limits_cpus, 'cpuset' => $this->database->limits_cpuset, 'cpu_shares' => $this->database->limits_cpu_shares, ] diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index af6b2ad4f..1fe8b463a 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -65,7 +65,7 @@ class StartRedis 'memswap_limit' => $this->database->limits_memory_swap, 'mem_swappiness' => $this->database->limits_memory_swappiness, 'mem_reservation' => $this->database->limits_memory_reservation, - 'cpus' => $this->database->limits_cpus, + 'cpus' => (int) $this->database->limits_cpus, 'cpuset' => $this->database->limits_cpuset, 'cpu_shares' => $this->database->limits_cpu_shares, ] diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 99ff873b3..469566060 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -192,6 +192,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->deploy_dockerimage_buildpack(); } else if ($this->application->build_pack === 'dockerfile') { $this->deploy_dockerfile_buildpack(); + } else if ($this->application->build_pack === 'static') { + $this->deploy_static_buildpack(); } else { if ($this->pull_request_id !== 0) { $this->deploy_pull_request(); @@ -227,6 +229,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted [ "docker rm -f {$this->deployment_uuid} >/dev/null 2>&1", "hidden" => true, + "ignore_errors" => true, + ] + ); + $this->execute_remote_command( + [ + "docker image prune -f >/dev/null 2>&1", + "hidden" => true, + "ignore_errors" => true, ] ); } @@ -421,6 +431,23 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->build_image(); $this->rolling_update(); } + private function deploy_static_buildpack() + { + $this->execute_remote_command( + [ + "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'" + ], + ); + $this->prepare_builder_image(); + $this->check_git_if_build_needed(); + $this->set_base_dir(); + $this->generate_image_names(); + $this->clone_repository(); + $this->cleanup_git(); + $this->build_image(); + $this->generate_compose_file(); + $this->rolling_update(); + } private function rolling_update() { @@ -787,7 +814,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted 'memswap_limit' => $this->application->limits_memory_swap, 'mem_swappiness' => $this->application->limits_memory_swappiness, 'mem_reservation' => $this->application->limits_memory_reservation, - 'cpus' => $this->application->limits_cpus, + 'cpus' => (int) $this->application->limits_cpus, 'cpuset' => $this->application->limits_cpuset, 'cpu_shares' => $this->application->limits_cpu_shares, ] @@ -910,22 +937,26 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private function build_image() { - $this->execute_remote_command([ - "echo -n 'Building docker image for your application. To check the current progress, click on Show Debug Logs.'", - ]); - - if ($this->application->settings->is_static) { + if ($this->application->build_pack === 'static') { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}/{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true + "echo -n 'Static deployment. Copying static assets to the image.'", ]); + } else { + $this->execute_remote_command([ + "echo -n 'Building docker image for your application. To check the current progress, click on Show Debug Logs.'", + ]); + } - $dockerfile = base64_encode("FROM {$this->application->static_image} + if ($this->application->settings->is_static || $this->application->build_pack === 'static') { + if ($this->application->build_pack === 'static') { + $dockerfile = base64_encode("FROM {$this->application->static_image} WORKDIR /usr/share/nginx/html/ LABEL coolify.deploymentId={$this->deployment_uuid} -COPY --from=$this->build_image_name /app/{$this->application->publish_directory} . +COPY . . +RUN rm -f /usr/share/nginx/html/nginx.conf +RUN rm -f /usr/share/nginx/html/Dockerfile COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); - - $nginx_config = base64_encode("server { + $nginx_config = base64_encode("server { listen 80; listen [::]:80; server_name localhost; @@ -941,15 +972,43 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); root /usr/share/nginx/html; } }"); + } else { + $this->execute_remote_command([ + executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}/{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true + ]); + + $dockerfile = base64_encode("FROM {$this->application->static_image} +WORKDIR /usr/share/nginx/html/ +LABEL coolify.deploymentId={$this->deployment_uuid} +COPY --from=$this->build_image_name /app/{$this->application->publish_directory} . +COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); + + $nginx_config = base64_encode("server { + listen 80; + listen [::]:80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + }"); + } $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod") + executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile") ], [ executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf") ], [ - executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true + executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true ] ); } else { diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 0813c1218..0b068d4b1 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -3,6 +3,7 @@ namespace App\Jobs; use App\Models\Server; +use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; @@ -10,12 +11,13 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Log; class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public $timeout = 1000; + public $timeout = 300; public ?string $dockerRootFilesystem = null; public ?int $usageBefore = null; @@ -33,14 +35,15 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted } public function handle(): void { - $queuedCount = 0; - $this->server->applications()->each(function ($application) use ($queuedCount) { - $count = data_get($application->deployments(), 'count', 0); - $queuedCount += $count; + $isInprogress = false; + $this->server->applications()->each(function ($application) use (&$isInprogress) { + if ($application->isDeploymentInprogress()) { + $isInprogress = true; + return; + } }); - if ($queuedCount > 0) { - ray('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping')->color('orange'); - return; + if ($isInprogress) { + throw new Exception('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping...'); } try { if (!$this->server->isFunctional()) { @@ -49,23 +52,25 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted $this->dockerRootFilesystem = "/"; $this->usageBefore = $this->getFilesystemUsage(); if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) { - ray('Cleaning up ' . $this->server->name)->color('orange'); + ray('Cleaning up ' . $this->server->name); instant_remote_process(['docker image prune -af'], $this->server); instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $this->server); instant_remote_process(['docker builder prune -af'], $this->server); $usageAfter = $this->getFilesystemUsage(); if ($usageAfter < $this->usageBefore) { - ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name)->color('orange'); + ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); send_internal_notification('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); + Log::info('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); } else { - ray('DockerCleanupJob failed to save disk space on ' . $this->server->name)->color('orange'); + Log::info('DockerCleanupJob failed to save disk space on ' . $this->server->name); } } else { - ray('No need to clean up ' . $this->server->name)->color('orange'); + ray('No need to clean up ' . $this->server->name); + Log::info('No need to clean up ' . $this->server->name); } } catch (\Throwable $e) { send_internal_notification('DockerCleanupJob failed with: ' . $e->getMessage()); - ray($e->getMessage())->color('orange'); + ray($e->getMessage()); throw $e; } } diff --git a/app/Models/Application.php b/app/Models/Application.php index ca7334b7e..0e72f94ce 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -213,6 +213,14 @@ class Application extends BaseModel return $this->morphTo(); } + public function isDeploymentInprogress() { + $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'in_progress')->count(); + if ($deployments > 0) { + return true; + } + return false; + } + public function deployments(int $skip = 0, int $take = 10) { $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->orderBy('created_at', 'desc'); diff --git a/app/View/Components/Forms/Input.php b/app/View/Components/Forms/Input.php index 6d3346dcf..09cee0338 100644 --- a/app/View/Components/Forms/Input.php +++ b/app/View/Components/Forms/Input.php @@ -20,7 +20,7 @@ class Input extends Component public bool $readonly = false, public string|null $helper = null, public bool $allowToPeak = true, - public string $defaultClass = "input input-sm bg-coolgray-200 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" + public string $defaultClass = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" ) { } diff --git a/app/View/Components/Forms/Select.php b/app/View/Components/Forms/Select.php index 58f59a683..381b86dce 100644 --- a/app/View/Components/Forms/Select.php +++ b/app/View/Components/Forms/Select.php @@ -19,7 +19,7 @@ class Select extends Component public string|null $label = null, public string|null $helper = null, public bool $required = false, - public string $defaultClass = "select select-sm w-full rounded text-white text-sm bg-coolgray-200 font-normal disabled:bg-coolgray-200/50 disabled:border-none" + public string $defaultClass = "select select-sm w-full rounded text-white text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none" ) { // } diff --git a/app/View/Components/Forms/Textarea.php b/app/View/Components/Forms/Textarea.php index b0fda78bf..69c618fb4 100644 --- a/app/View/Components/Forms/Textarea.php +++ b/app/View/Components/Forms/Textarea.php @@ -25,7 +25,7 @@ class Textarea extends Component public bool $readonly = false, public string|null $helper = null, public bool $realtimeValidation = false, - public string $defaultClass = "textarea leading-normal bg-coolgray-200 rounded text-white scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" + public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" ) { // } diff --git a/config/sentry.php b/config/sentry.php index bcc77e76c..d14fcc227 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.119', + 'release' => '4.0.0-beta.120', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 14c1a5817..0cce81b80 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@
-
diff --git a/resources/views/components/navbar-subscription.blade.php b/resources/views/components/navbar-subscription.blade.php index ddb9d1a44..4636db475 100644 --- a/resources/views/components/navbar-subscription.blade.php +++ b/resources/views/components/navbar-subscription.blade.php @@ -1,6 +1,7 @@ @auth +