From 967fca9eca0d302402ac5e3b295c3a6d2f9f4915 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 15 Dec 2023 15:17:49 +0100 Subject: [PATCH 01/15] version ++ --- config/sentry.php | 2 +- config/version.php | 2 +- versions.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/sentry.php b/config/sentry.php index 23c9af8bb..b24ec892f 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.164', + 'release' => '4.0.0-beta.165', // 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 d9e28384f..a0b2aca88 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Fri, 15 Dec 2023 15:48:01 +0100 Subject: [PATCH 02/15] wip: swarm --- .../New/{StandaloneDocker.php => Docker.php} | 50 ++++++++++++------- app/Livewire/Destination/Show.php | 6 ++- app/Livewire/Project/New/Select.php | 8 +-- bootstrap/helpers/proxy.php | 46 ++++++++++++----- resources/views/destination/new.blade.php | 2 +- ...lone-docker.blade.php => docker.blade.php} | 1 + .../views/livewire/destination/show.blade.php | 11 +++- .../livewire/project/new/select.blade.php | 40 ++++++++------- .../views/livewire/server/form.blade.php | 4 +- .../views/livewire/server/new/by-ip.blade.php | 4 +- 10 files changed, 112 insertions(+), 60 deletions(-) rename app/Livewire/Destination/New/{StandaloneDocker.php => Docker.php} (53%) rename resources/views/livewire/destination/new/{standalone-docker.blade.php => docker.blade.php} (90%) diff --git a/app/Livewire/Destination/New/StandaloneDocker.php b/app/Livewire/Destination/New/Docker.php similarity index 53% rename from app/Livewire/Destination/New/StandaloneDocker.php rename to app/Livewire/Destination/New/Docker.php index 72516752a..3b76a7d13 100644 --- a/app/Livewire/Destination/New/StandaloneDocker.php +++ b/app/Livewire/Destination/New/Docker.php @@ -4,29 +4,32 @@ namespace App\Livewire\Destination\New; use App\Models\Server; use App\Models\StandaloneDocker as ModelsStandaloneDocker; +use App\Models\SwarmDocker; use Illuminate\Database\Eloquent\Collection; -use Illuminate\Support\Str; use Livewire\Component; use Visus\Cuid2\Cuid2; -class StandaloneDocker extends Component +class Docker extends Component { public string $name; public string $network; public Collection $servers; public Server $server; - public int|null $server_id = null; + public ?int $server_id = null; + public bool $is_swarm = false; protected $rules = [ 'name' => 'required|string', 'network' => 'required|string', - 'server_id' => 'required|integer' + 'server_id' => 'required|integer', + 'is_swarm' => 'boolean' ]; protected $validationAttributes = [ 'name' => 'name', 'network' => 'network', - 'server_id' => 'server' + 'server_id' => 'server', + 'is_swarm' => 'swarm' ]; public function mount() @@ -43,13 +46,13 @@ class StandaloneDocker extends Component } else { $this->network = new Cuid2(7); } - $this->name = Str::kebab("{$this->servers->first()->name}-{$this->network}"); + $this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab(); } public function generate_name() { $this->server = Server::find($this->server_id); - $this->name = Str::kebab("{$this->server->name}-{$this->network}"); + $this->name = str("{$this->server->name}-{$this->network}")->kebab(); } public function submit() @@ -57,17 +60,30 @@ class StandaloneDocker extends Component $this->validate(); try { $this->server = Server::find($this->server_id); - $found = $this->server->standaloneDockers()->where('network', $this->network)->first(); - if ($found) { - $this->createNetworkAndAttachToProxy(); - $this->dispatch('error', 'Network already added to this server.'); - return; + if ($this->is_swarm) { + $found = $this->server->swarmDockers()->where('network', $this->network)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + return; + } else { + $docker = SwarmDocker::create([ + 'name' => $this->name, + 'network' => $this->network, + 'server_id' => $this->server_id, + ]); + } } else { - $docker = ModelsStandaloneDocker::create([ - 'name' => $this->name, - 'network' => $this->network, - 'server_id' => $this->server_id, - ]); + $found = $this->server->standaloneDockers()->where('network', $this->network)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + return; + } else { + $docker = ModelsStandaloneDocker::create([ + 'name' => $this->name, + 'network' => $this->network, + 'server_id' => $this->server_id, + ]); + } } $this->createNetworkAndAttachToProxy(); return $this->redirectRoute('destination.show', $docker->uuid, navigate: true); diff --git a/app/Livewire/Destination/Show.php b/app/Livewire/Destination/Show.php index 77495c83e..b9cbcc147 100644 --- a/app/Livewire/Destination/Show.php +++ b/app/Livewire/Destination/Show.php @@ -13,7 +13,11 @@ class Show extends Component public function scan() { - $alreadyAddedNetworks = $this->server->standaloneDockers; + if ($this->server->isSwarm()) { + $alreadyAddedNetworks = $this->server->swarmDockers; + } else { + $alreadyAddedNetworks = $this->server->standaloneDockers; + } $networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false); $this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) { return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none'; diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 856a9b9a9..635e0de51 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -6,13 +6,12 @@ use App\Models\Project; use App\Models\Server; use Countable; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\Cache; use Livewire\Component; class Select extends Component { public $current_step = 'type'; - public ?int $server = null; + public ?Server $server = null; public string $type; public string $server_id; public string $destination_uuid; @@ -31,7 +30,7 @@ class Select extends Component public ?string $search = null; protected $queryString = [ - 'server', + 'server_id', 'search' ]; @@ -111,7 +110,7 @@ class Select extends Component $this->setServer($server); } if (!is_null($this->server)) { - $foundServer = $this->servers->where('id', $this->server)->first(); + $foundServer = $this->servers->where('id', $this->server->id)->first(); if ($foundServer) { return $this->setServer($foundServer); } @@ -122,6 +121,7 @@ class Select extends Component public function setServer(Server $server) { $this->server_id = $server->id; + $this->server = $server; $this->standaloneDockers = $server->standaloneDockers; $this->swarmDockers = $server->swarmDockers; $this->current_step = 'destinations'; diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index b738b5a9d..b40edd1d2 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -15,10 +15,16 @@ function get_proxy_path() } function connectProxyToNetworks(Server $server) { - // Standalone networks - $networks = collect($server->standaloneDockers)->map(function ($docker) { - return $docker['network']; - }); + if ($server->isSwarm()) { + $networks = collect($server->swarmDockers)->map(function ($docker) { + return $docker['network']; + }); + } else { + // Standalone networks + $networks = collect($server->standaloneDockers)->map(function ($docker) { + return $docker['network']; + }); + } // Service networks foreach ($server->services()->get() as $service) { $networks->push($service->networks()); @@ -41,16 +47,30 @@ function connectProxyToNetworks(Server $server) $networks->push($network); } $networks = collect($networks)->flatten()->unique(); - if ($networks->count() === 0) { - $networks = collect(['coolify']); + if ($server->isSwarm()) { + if ($networks->count() === 0) { + $networks = collect(['coolify-overlay']); + } + $commands = $networks->map(function ($network) { + return [ + "echo 'Connecting coolify-proxy to $network network...'", + "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null || docker network create --driver overlay --attachable $network >/dev/null", + "docker network connect $network coolify-proxy >/dev/null 2>&1 || true", + ]; + }); + } else { + if ($networks->count() === 0) { + $networks = collect(['coolify']); + } + $commands = $networks->map(function ($network) { + return [ + "echo 'Connecting coolify-proxy to $network network...'", + "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null || docker network create --attachable $network >/dev/null", + "docker network connect $network coolify-proxy >/dev/null 2>&1 || true", + ]; + }); } - $commands = $networks->map(function ($network) { - return [ - "echo 'Connecting coolify-proxy to $network network...'", - "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null || docker network create --attachable $network >/dev/null", - "docker network connect $network coolify-proxy >/dev/null 2>&1 || true", - ]; - }); + return $commands->flatten(); } function generate_default_proxy_configuration(Server $server) diff --git a/resources/views/destination/new.blade.php b/resources/views/destination/new.blade.php index 37cad6f7a..e3dbeee9b 100644 --- a/resources/views/destination/new.blade.php +++ b/resources/views/destination/new.blade.php @@ -1,3 +1,3 @@ - + diff --git a/resources/views/livewire/destination/new/standalone-docker.blade.php b/resources/views/livewire/destination/new/docker.blade.php similarity index 90% rename from resources/views/livewire/destination/new/standalone-docker.blade.php rename to resources/views/livewire/destination/new/docker.blade.php index 90335e51a..2fe0c6340 100644 --- a/resources/views/livewire/destination/new/standalone-docker.blade.php +++ b/resources/views/livewire/destination/new/docker.blade.php @@ -12,6 +12,7 @@ @endforeach + Save Destination diff --git a/resources/views/livewire/destination/show.blade.php b/resources/views/livewire/destination/show.blade.php index 5bc0b595a..1287e2ca2 100644 --- a/resources/views/livewire/destination/show.blade.php +++ b/resources/views/livewire/destination/show.blade.php @@ -11,7 +11,16 @@
Available for using: @forelse ($server->standaloneDockers as $docker) - + + + + @empty +
N/A
+ @endforelse + @forelse ($server->swarmDockers as $docker) + @empty diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index ab04b7ee3..e176cd379 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -232,27 +232,29 @@
- - @foreach ($standaloneDockers as $standaloneDocker) -
-
-
- Standalone Docker ({{ $standaloneDocker->name }}) -
-
- network: {{ $standaloneDocker->network }}
-
-
- @endforeach - @foreach ($swarmDockers as $swarmDocker) -
-
-
- Swarm Docker ({{ $swarmDocker->name }}) + @if ($server->isSwarm()) + @foreach ($swarmDockers as $swarmDocker) +
+
+
+ Swarm Docker ({{ $swarmDocker->name }}) +
-
- @endforeach + @endforeach + @else + @foreach ($standaloneDockers as $standaloneDocker) +
+
+
+ Standalone Docker ({{ $standaloneDocker->name }}) +
+
+ network: {{ $standaloneDocker->network }}
+
+
+ @endforeach + @endif
diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 557525729..049b1735f 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -53,8 +53,8 @@ helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.Coolify does not install/setup Cloudflare (cloudflared) on your server." id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" /> @endif - {{-- --}} + {{-- --}}
diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index c8247c50f..787270aee 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -25,10 +25,10 @@ @endif @endforeach - {{--
+
-
--}} +
Save New Server From 27c36bec83f12746d4fc805e9407fc631248968a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 17 Dec 2023 20:56:12 +0100 Subject: [PATCH 03/15] feat: custom docker compose commands --- app/Jobs/ApplicationDeploymentJob.php | 45 ++++++++--- app/Livewire/Project/Application/General.php | 7 +- ...dd_custom_docker_compose_start_command.php | 33 ++++++++ .../project/application/general.blade.php | 80 ++++++++++++------- 4 files changed, 123 insertions(+), 42 deletions(-) create mode 100644 database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 652fd2262..d684473ad 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -75,6 +75,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private $docker_compose_base64; private string $dockerfile_location = '/Dockerfile'; private string $docker_compose_location = '/docker-compose.yml'; + private ?string $docker_compose_custom_start_command = null; + private ?string $docker_compose_custom_build_command = null; private ?string $addHosts = null; private ?string $buildTarget = null; private Collection $saved_outputs; @@ -432,6 +434,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if (data_get($this->application, 'docker_compose_location')) { $this->docker_compose_location = $this->application->docker_compose_location; } + if (data_get($this->application, 'docker_compose_custom_start_command')) { + $this->docker_compose_custom_start_command = $this->application->docker_compose_custom_start_command; + } + if (data_get($this->application, 'docker_compose_custom_build_command')) { + $this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command; + } if ($this->pull_request_id === 0) { $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}."); } else { @@ -454,7 +462,18 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted ]); $this->save_environment_variables(); // Build new container to limit downtime. - $this->build_by_compose_file(); + $this->application_deployment_queue->addLogEntry("Pulling & building required images."); + + if ($this->docker_compose_custom_build_command) { + $this->execute_remote_command( + [executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_build_command}"), "hidden" => true], + ); + } else { + $this->execute_remote_command( + [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true], + ); + } + $this->stop_running_container(force: true); $networkId = $this->application->uuid; @@ -488,7 +507,17 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted ] ); } - $this->start_by_compose_file(); + // Start compose file + if ($this->docker_compose_custom_start_command) { + $this->execute_remote_command( + [executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), "hidden" => true], + ); + } else { + $this->execute_remote_command( + [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true], + ); + } + $this->application_deployment_queue->addLogEntry("New container started."); } private function deploy_dockerfile_buildpack() { @@ -1258,15 +1287,9 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true], ); } else { - if ($this->docker_compose_location) { - $this->execute_remote_command( - [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true], - ); - } else { - $this->execute_remote_command( - [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true], - ); - } + $this->execute_remote_command( + [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true], + ); } $this->application_deployment_queue->addLogEntry("New images built."); } diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index abc091917..996774e0b 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -64,6 +64,8 @@ class General extends Component 'application.custom_labels' => 'nullable', 'application.dockerfile_target_build' => 'nullable', 'application.settings.is_static' => 'boolean|required', + 'application.docker_compose_custom_start_command' => 'nullable', + 'application.docker_compose_custom_build_command' => 'nullable', ]; protected $validationAttributes = [ 'application.name' => 'name', @@ -94,6 +96,8 @@ class General extends Component 'application.custom_labels' => 'Custom labels', 'application.dockerfile_target_build' => 'Dockerfile target build', 'application.settings.is_static' => 'Is static', + 'application.docker_compose_custom_start_command' => 'Docker compose custom start command', + 'application.docker_compose_custom_build_command' => 'Docker compose custom build command', ]; public function mount() { @@ -195,7 +199,8 @@ class General extends Component public function submit($showToaster = true) { try { - if ($this->application->build_pack === 'dockercompose' && ($this->initialDockerComposeLocation !== $this->application->docker_compose_location || $this->initialDockerComposePrLocation !== $this->application->docker_compose_pr_location)) { + ray($this->initialDockerComposeLocation, $this->application->docker_compose_location); + if ($this->application->build_pack === 'dockercompose' && $this->initialDockerComposeLocation !== $this->application->docker_compose_location) { $this->loadComposeFile(); } $this->validate(); diff --git a/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php b/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php new file mode 100644 index 000000000..e9e1031b8 --- /dev/null +++ b/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php @@ -0,0 +1,33 @@ +string('docker_compose_custom_start_command')->nullable(); + $table->string('docker_compose_custom_build_command')->nullable(); + + + + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('applications', function (Blueprint $table) { + $table->dropColumn('docker_compose_custom_start_command'); + $table->dropColumn('docker_compose_custom_build_command'); + }); + } +}; diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index ce4fd10a2..963a30ca4 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -126,37 +126,57 @@
@endif @endif -
- - @if ($application->build_pack === 'dockerfile' && !$application->dockerfile) - - @endif - @if ($application->build_pack === 'dockercompose') - - - {{-- --}} - @endif - @if ($application->build_pack === 'dockerfile') - - @endif - @if ($application->could_set_build_commands()) - @if ($application->settings->is_static) - - @else - + @if ($application->build_pack === 'dockercompose') +
+
+ + +
+
The following commands are for advanced use cases. Only modify them if you know what are + you doing.
+
+ + + {{-- --}} +
+
+ @else +
+ + @if ($application->build_pack === 'dockerfile' && !$application->dockerfile) + @endif - @endif -
+ + @if ($application->build_pack === 'dockerfile') + + @endif + @if ($application->could_set_build_commands()) + @if ($application->settings->is_static) + + @else + + @endif + @endif +
+ @endif + @endif @if ($application->build_pack === 'dockercompose') Reload Compose File From 62c38c98597709c2ec78ab680c37879177efc864 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 18 Dec 2023 14:01:25 +0100 Subject: [PATCH 04/15] wip: swarm --- app/Console/Kernel.php | 8 ++- app/Jobs/ApplicationDeploymentJob.php | 60 ++++++++++++------- app/Jobs/ContainerStatusJob.php | 10 ++-- app/Livewire/Project/Application/General.php | 2 +- app/Livewire/Project/Application/Heading.php | 4 ++ app/Livewire/Project/Application/Previews.php | 12 ++-- app/Livewire/Project/Application/Swarm.php | 51 ++++++++++++++++ app/Livewire/Project/New/Select.php | 38 ++++++++++-- app/Livewire/Project/Shared/Storages/Add.php | 38 ++++++++---- app/Livewire/Server/Form.php | 4 +- app/Livewire/Server/New/ByIp.php | 5 ++ app/Models/Server.php | 10 +++- bootstrap/helpers/proxy.php | 10 +++- ..._12_18_093514_add_swarm_related_things.php | 36 +++++++++++ .../components/applications/navbar.blade.php | 46 +++++++------- .../views/components/server/navbar.blade.php | 45 +++++++------- .../application/configuration.blade.php | 9 +++ .../project/application/general.blade.php | 16 +++-- .../project/application/swarm.blade.php | 24 ++++++++ .../livewire/project/new/select.blade.php | 8 +++ .../project/shared/storages/add.blade.php | 22 +++++-- .../views/livewire/server/form.blade.php | 24 ++++++-- .../views/livewire/server/new/by-ip.blade.php | 15 ++++- .../livewire/server/proxy/show.blade.php | 4 +- 24 files changed, 387 insertions(+), 114 deletions(-) create mode 100644 app/Livewire/Project/Application/Swarm.php create mode 100644 database/migrations/2023_12_18_093514_add_swarm_related_things.php create mode 100644 resources/views/livewire/project/application/swarm.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e24d657a9..2a8e857e2 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -56,16 +56,20 @@ class Kernel extends ConsoleKernel $servers = Server::all()->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4'); $own = Team::find(0)->servers; $servers = $servers->merge($own); + $containerServers = $servers->where('settings.is_swarm_worker', false); } else { $servers = Server::all()->where('ip', '!=', '1.2.3.4'); + $containerServers = $servers->where('settings.is_swarm_worker', false); } - foreach ($servers as $server) { - $schedule->job(new ServerStatusJob($server))->everyTenMinutes()->onOneServer(); + foreach ($containerServers as $server) { $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); if ($server->isLogDrainEnabled()) { $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); } } + foreach ($servers as $server) { + $schedule->job(new ServerStatusJob($server))->everyTenMinutes()->onOneServer(); + } } private function instance_auto_update($schedule) { diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index d684473ad..263eb35f6 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -217,19 +217,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ($this->server->isProxyShouldRun()) { dispatch(new ContainerStatusJob($this->server)); } - if ($this->application->docker_registry_image_name && $this->application->build_pack !== 'dockerimage') { + if ($this->application->docker_registry_image_name && $this->application->build_pack !== 'dockerimage' && !$this->application->destination->server->isSwarm()) { $this->push_to_docker_registry(); - if ($this->server->isSwarm()) { - $this->application_deployment_queue->addLogEntry("Creating / updating stack."); - $this->execute_remote_command( - [ - executeInDocker($this->deployment_uuid, "cd {$this->workdir} && docker stack deploy --with-registry-auth -c docker-compose.yml {$this->application->uuid}") - ], - [ - "echo 'Stack deployed. It may take a few minutes to fully available in your swarm.'" - ] - ); - } } $this->next(ApplicationDeploymentStatus::FINISHED->value); $this->application->isConfigurationChanged(true); @@ -301,6 +290,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted "echo -n 'Image pushed to docker registry.'" ]); } catch (Exception $e) { + if ($this->application->destination->server->isSwarm()) { + throw $e; + } $this->execute_remote_command( ["echo -n 'Failed to push image to docker registry. Please check debug logs for more information.'"], ); @@ -604,7 +596,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private function rolling_update() { if ($this->server->isSwarm()) { - // Skip this. + $this->push_to_docker_registry(); + $this->application_deployment_queue->addLogEntry("Rolling update started."); + $this->execute_remote_command( + [ + executeInDocker($this->deployment_uuid, "docker stack deploy --with-registry-auth -c {$this->workdir}{$this->docker_compose_location} {$this->application->uuid}") + ], + ); + $this->application_deployment_queue->addLogEntry("Rolling update completed."); } else { if (count($this->application->ports_mappings_array) > 0) { $this->execute_remote_command( @@ -703,10 +702,20 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->add_build_env_variables_to_dockerfile(); $this->build_image(); $this->stop_running_container(); - $this->execute_remote_command( - ["echo -n 'Starting preview deployment.'"], - [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true], - ); + if ($this->application->destination->server->isSwarm()) { + ray("{$this->workdir}{$this->docker_compose_location}"); + $this->push_to_docker_registry(); + $this->execute_remote_command( + [ + executeInDocker($this->deployment_uuid, "docker stack deploy --with-registry-auth -c {$this->workdir}{$this->docker_compose_location} {$this->application->uuid}-{$this->pull_request_id}") + ], + ); + } else { + $this->execute_remote_command( + ["echo -n 'Starting preview deployment.'"], + [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true], + ); + } } private function create_workdir() { @@ -970,13 +979,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted data_forget($docker_compose, 'services.' . $this->container_name . '.cpu_shares'); $docker_compose['services'][$this->container_name]['deploy'] = [ - 'placement' => [ - 'constraints' => [ - 'node.role == worker' - ] - ], 'mode' => 'replicated', - 'replicas' => 1, + 'replicas' => data_get($this->application, 'swarm_replicas', 1), 'update_config' => [ 'order' => 'start-first' ], @@ -995,6 +999,16 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted ] ] ]; + if (data_get($this->application, 'settings.is_swarm_only_worker_nodes')) { + $docker_compose['services'][$this->container_name]['deploy']['placement'] = [ + 'constraints' => [ + 'node.role == worker' + ] + ]; + } + if ($this->pull_request_id !== 0) { + $docker_compose['services'][$this->container_name]['deploy']['replicas'] = 1; + } } else { $docker_compose['services'][$this->container_name]['labels'] = $labels; } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 9989ed8cb..c0d0e7ad9 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -46,7 +46,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted }; if ($this->server->isSwarm()) { $containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this->server, false); - $containerReplicase = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false); + $containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false); } else { // Precheck for containers $containers = instant_remote_process(["docker container ls -q"], $this->server, false); @@ -54,15 +54,15 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted return; } $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false); - $containerReplicase = null; + $containerReplicates = null; } if (is_null($containers)) { return; } $containers = format_docker_command_output_to_json($containers); - if ($containerReplicase) { - $containerReplicase = format_docker_command_output_to_json($containerReplicase); - foreach ($containerReplicase as $containerReplica) { + if ($containerReplicates) { + $containerReplicates = format_docker_command_output_to_json($containerReplicates); + foreach ($containerReplicates as $containerReplica) { $name = data_get($containerReplica, 'Name'); $containers = $containers->map(function ($container) use ($name, $containerReplica) { if (data_get($container, 'Spec.Name') === $name) { diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 996774e0b..39cb15b27 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -113,7 +113,7 @@ class General extends Component $this->application->isConfigurationChanged(true); } $this->isConfigurationChanged = $this->application->isConfigurationChanged(); - $this->customLabels = $this->application->parseContainerLabels(); + $this->customLabels = $this->application->parseContainerLabels(); $this->initialDockerComposeLocation = $this->application->docker_compose_location; $this->checkLabelUpdates(); } diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php index 3db5fc9c4..c8fbcca2b 100644 --- a/app/Livewire/Project/Application/Heading.php +++ b/app/Livewire/Project/Application/Heading.php @@ -73,6 +73,10 @@ class Heading extends Component $this->dispatch('error', 'Please load a Compose file first.'); return; } + if ($this->application->destination->server->isSwarm() && is_null($this->application->docker_registry_image_name)) { + $this->dispatch('error', 'Please set a Docker image name first.'); + return; + } $this->setDeploymentUuid(); queue_application_deployment( application_id: $this->application->id, diff --git a/app/Livewire/Project/Application/Previews.php b/app/Livewire/Project/Application/Previews.php index 0fc1acf5e..31707aa3d 100644 --- a/app/Livewire/Project/Application/Previews.php +++ b/app/Livewire/Project/Application/Previews.php @@ -72,10 +72,14 @@ class Previews extends Component public function stop(int $pull_request_id) { try { - $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id); - foreach ($containers as $container) { - $name = str_replace('/', '', $container['Names']); - instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false); + if ($this->application->destination->server->isSwarm()) { + instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $this->application->destination->server); + } else { + $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id); + foreach ($containers as $container) { + $name = str_replace('/', '', $container['Names']); + instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false); + } } ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first()->delete(); $this->application->refresh(); diff --git a/app/Livewire/Project/Application/Swarm.php b/app/Livewire/Project/Application/Swarm.php new file mode 100644 index 000000000..5f89f4934 --- /dev/null +++ b/app/Livewire/Project/Application/Swarm.php @@ -0,0 +1,51 @@ + 'required', + 'application.swarm_placement_constraints' => 'nullable', + 'application.settings.is_swarm_only_worker_nodes' => 'required', + ]; + public function mount() { + if ($this->application->swarm_placement_constraints) { + $this->swarm_placement_constraints = base64_decode($this->application->swarm_placement_constraints); + } + } + public function instantSave() { + try { + $this->validate(); + $this->application->settings->save(); + $this->dispatch('success', 'Swarm settings updated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function submit() { + try { + $this->validate(); + if ($this->swarm_placement_constraints) { + $this->application->swarm_placement_constraints = base64_encode($this->swarm_placement_constraints); + } else { + $this->application->swarm_placement_constraints = null; + } + $this->application->save(); + + $this->dispatch('success', 'Swarm settings updated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function render() + { + return view('livewire.project.application.swarm'); + } +} diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 635e0de51..b205467bf 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -15,12 +15,15 @@ class Select extends Component public string $type; public string $server_id; public string $destination_uuid; + public Countable|array|Server $allServers = []; public Countable|array|Server $servers = []; public Collection|array $standaloneDockers = []; public Collection|array $swarmDockers = []; public array $parameters; public Collection|array $services = []; public Collection|array $allServices = []; + public bool $isDatabase = false; + public bool $includeSwarm = true; public bool $loadingServices = true; public bool $loading = false; @@ -96,19 +99,43 @@ class Select extends Component $this->loadingServices = false; } } + public function instantSave() + { + if ($this->includeSwarm) { + $this->servers = $this->allServers; + } else { + $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false); + } + } public function setType(string $type) { - $this->type = $type; if ($this->loading) return; $this->loading = true; + $this->type = $type; + switch ($type) { + case 'postgresql': + case 'mysql': + case 'mariadb': + case 'redis': + case 'mongodb': + $this->isDatabase = true; + $this->includeSwarm = false; + $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false); + break; + } + if (str($type)->startsWith('one-click-service')) { + $this->isDatabase = true; + $this->includeSwarm = false; + $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false); + } if ($type === "existing-postgresql") { $this->current_step = $type; return; } - if (count($this->servers) === 1) { - $server = $this->servers->first(); - $this->setServer($server); - } + // if (count($this->servers) === 1) { + // $server = $this->servers->first(); + // $this->setServer($server); + // } if (!is_null($this->server)) { $foundServer = $this->servers->where('id', $this->server->id)->first(); if ($foundServer) { @@ -142,5 +169,6 @@ class Select extends Component public function loadServers() { $this->servers = Server::isUsable()->get(); + $this->allServers = $this->servers; } } diff --git a/app/Livewire/Project/Shared/Storages/Add.php b/app/Livewire/Project/Shared/Storages/Add.php index b1f467b34..e2e84c358 100644 --- a/app/Livewire/Project/Shared/Storages/Add.php +++ b/app/Livewire/Project/Shared/Storages/Add.php @@ -2,22 +2,26 @@ namespace App\Livewire\Project\Shared\Storages; +use App\Models\Application; use Livewire\Component; class Add extends Component { public $uuid; public $parameters; + public $isSwarm = false; public string $name; public string $mount_path; - public string|null $host_path = null; + public ?string $host_path = null; - protected $listeners = ['clearAddStorage' => 'clear']; - protected $rules = [ + public $rules = [ 'name' => 'required|string', 'mount_path' => 'required|string', 'host_path' => 'string|nullable', ]; + + protected $listeners = ['clearAddStorage' => 'clear']; + protected $validationAttributes = [ 'name' => 'name', 'mount_path' => 'mount', @@ -27,17 +31,31 @@ class Add extends Component public function mount() { $this->parameters = get_route_parameters(); + $applicationUuid = $this->parameters['application_uuid']; + $application = Application::where('uuid', $applicationUuid)->first(); + if (!$application) { + abort(404); + } + if ($application->destination->server->isSwarm()) { + $this->isSwarm = true; + $this->rules['host_path'] = 'required|string'; + } } public function submit() { - $this->validate(); - $name = $this->uuid . '-' . $this->name; - $this->dispatch('addNewVolume', [ - 'name' => $name, - 'mount_path' => $this->mount_path, - 'host_path' => $this->host_path, - ]); + try { + $this->validate($this->rules); + $name = $this->uuid . '-' . $this->name; + $this->dispatch('addNewVolume', [ + 'name' => $name, + 'mount_path' => $this->mount_path, + 'host_path' => $this->host_path, + ]); + $this->dispatch('closeStorageModal'); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function clear() diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 480028ede..943be4458 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -25,7 +25,7 @@ class Form extends Component 'server.settings.is_cloudflare_tunnel' => 'required|boolean', 'server.settings.is_reachable' => 'required', 'server.settings.is_swarm_manager' => 'required|boolean', - // 'server.settings.is_swarm_worker' => 'required|boolean', + 'server.settings.is_swarm_worker' => 'required|boolean', 'wildcard_domain' => 'nullable|url', ]; protected $validationAttributes = [ @@ -37,7 +37,7 @@ class Form extends Component 'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', 'server.settings.is_reachable' => 'Is reachable', 'server.settings.is_swarm_manager' => 'Swarm Manager', - // 'server.settings.is_swarm_worker' => 'Swarm Worker', + 'server.settings.is_swarm_worker' => 'Swarm Worker', ]; public function mount() diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index 3470e27f8..98e7a99a7 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -22,6 +22,8 @@ class ByIp extends Component public string $user = 'root'; public int $port = 22; public bool $is_swarm_manager = false; + public bool $is_swarm_worker = false; + protected $rules = [ 'name' => 'required|string', @@ -30,6 +32,7 @@ class ByIp extends Component 'user' => 'required|string', 'port' => 'required|integer', 'is_swarm_manager' => 'required|boolean', + 'is_swarm_worker' => 'required|boolean', ]; protected $validationAttributes = [ 'name' => 'Name', @@ -38,6 +41,7 @@ class ByIp extends Component 'user' => 'User', 'port' => 'Port', 'is_swarm_manager' => 'Swarm Manager', + 'is_swarm_worker' => 'Swarm Worker', ]; public function mount() @@ -77,6 +81,7 @@ class ByIp extends Component ], ]); $server->settings->is_swarm_manager = $this->is_swarm_manager; + $server->settings->is_swarm_worker = $this->is_swarm_worker; $server->settings->save(); $server->addInitialNetwork(); return $this->redirectRoute('server.show', $server->uuid, navigate: true); diff --git a/app/Models/Server.php b/app/Models/Server.php index a5577f6c1..59046831f 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -72,7 +72,7 @@ class Server extends BaseModel static public function isUsable() { - return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_usable', true); + return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_swarm_worker', false); } static public function destinationsByServer(string $server_id) @@ -380,6 +380,14 @@ class Server extends BaseModel { return data_get($this, 'settings.is_swarm_manager') || data_get($this, 'settings.is_swarm_worker'); } + public function isSwarmManager() + { + return data_get($this, 'settings.is_swarm_manager'); + } + public function isSwarmWorker() + { + return data_get($this, 'settings.is_swarm_worker'); + } public function validateConnection() { $server = Server::find($this->id); diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index b40edd1d2..0ff3d1344 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -80,14 +80,18 @@ function generate_default_proxy_configuration(Server $server) $networks = collect($server->swarmDockers)->map(function ($docker) { return $docker['network']; })->unique(); + if ($networks->count() === 0) { + $networks = collect(['coolify-overlay']); + } } else { $networks = collect($server->standaloneDockers)->map(function ($docker) { return $docker['network']; })->unique(); + if ($networks->count() === 0) { + $networks = collect(['coolify']); + } } - if ($networks->count() === 0) { - $networks = collect(['coolify']); - } + $array_of_networks = collect([]); $networks->map(function ($network) use ($array_of_networks) { $array_of_networks[$network] = [ diff --git a/database/migrations/2023_12_18_093514_add_swarm_related_things.php b/database/migrations/2023_12_18_093514_add_swarm_related_things.php new file mode 100644 index 000000000..0f44f35ec --- /dev/null +++ b/database/migrations/2023_12_18_093514_add_swarm_related_things.php @@ -0,0 +1,36 @@ +integer('swarm_replicas')->default(1); + $table->text('swarm_placement_constraints')->nullable(); + }); + Schema::table('application_settings', function (Blueprint $table) { + $table->boolean('is_swarm_only_worker_nodes')->default(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('applications', function (Blueprint $table) { + $table->dropColumn('swarm_replicas'); + $table->dropColumn('swarm_placement_constraints'); + }); + Schema::table('application_settings', function (Blueprint $table) { + $table->dropColumn('is_swarm_only_worker_nodes'); + }); + } +}; diff --git a/resources/views/components/applications/navbar.blade.php b/resources/views/components/applications/navbar.blade.php index 38bff68e2..a1b4af91d 100644 --- a/resources/views/components/applications/navbar.blade.php +++ b/resources/views/components/applications/navbar.blade.php @@ -19,24 +19,26 @@
@if ($application->build_pack === 'dockercompose' && is_null($application->docker_compose_raw))
Please load a Compose file.
- @elseif ($application->destination->server->isSwarm() && str($application->docker_registry_image_name)->isEmpty()) - Swarm Deployments requires a Docker Image in a Registry. @else - + @if (!$application->destination->server->isSwarm()) + + @endif @if ($application->status !== 'exited') - + @if (!$application->destination->server->isSwarm()) + + @endif @if ($application->build_pack !== 'dockercompose') - @if (isDev()) + {{-- @if (isDev()) - @endif + @endif --}} @endif - @if (isDev()) + {{-- @if (isDev()) - @endif + @endif --}} @endif @endif
diff --git a/resources/views/components/server/navbar.blade.php b/resources/views/components/server/navbar.blade.php index f1e4715d1..b6e8d127f 100644 --- a/resources/views/components/server/navbar.blade.php +++ b/resources/views/components/server/navbar.blade.php @@ -2,7 +2,7 @@

Server

- @if ($server->proxyType() !== 'NONE') + @if ($server->proxyType() !== 'NONE' && $server->isFunctional() && !$server->isSwarmWorker()) @endif
@@ -20,25 +20,30 @@ ]) }}">
- - - - - - - - - + @if (!$server->isSwarmWorker()) + + + + + + + + + + @endif +
- + @if ($server->proxyType() !== 'NONE' && $server->isFunctional() && !$server->isSwarmWorker()) + + @endif
diff --git a/resources/views/livewire/project/application/configuration.blade.php b/resources/views/livewire/project/application/configuration.blade.php index ecfb74779..5d2936649 100644 --- a/resources/views/livewire/project/application/configuration.blade.php +++ b/resources/views/livewire/project/application/configuration.blade.php @@ -5,6 +5,11 @@
General + @if ($application->destination->server->isSwarm()) + Swarm + Configuration + @endif Advanced @if ($application->build_pack !== 'static') @@ -13,6 +18,7 @@ href="#">Environment Variables @endif + @if ($application->git_based()) Source @@ -56,6 +62,9 @@
+
+ +
diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 963a30ca4..6c50dec1d 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -70,8 +70,11 @@ @if ($application->build_pack !== 'dockercompose')

Docker Registry

@if ($application->destination->server->isSwarm()) -
Docker Swarm requires the image to be available in a registry. More info here.
+ @if ($application->build_pack !== 'dockerimage') +
Docker Swarm requires the image to be available in a registry. More info here.
+ @endif @else @if ($application->build_pack !== 'dockerimage')
Push the built image to a docker registry. More info
-
The following commands are for advanced use cases. Only modify them if you know what are +
The following commands are for advanced use cases. Only modify them if you + know what are you doing.
@endif - + @if (!$application->destination->server->isSwarm()) + + @endif
Reset to Coolify Generated Labels diff --git a/resources/views/livewire/project/application/swarm.blade.php b/resources/views/livewire/project/application/swarm.blade.php new file mode 100644 index 000000000..2954c9e68 --- /dev/null +++ b/resources/views/livewire/project/application/swarm.blade.php @@ -0,0 +1,24 @@ +
+
+
+

Swarm Configuration

+ + Save + +
+ {{--
Advanced Swarm Configuration
--}} +
+
+ + +
+ +
+
+ +
diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index e176cd379..ae638b8ee 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -202,6 +202,14 @@
  • Select a Server
  • Select a Destination
  • + @if ($isDatabase) +
    + +
    + @endif
    @forelse($servers as $server)
    diff --git a/resources/views/livewire/project/shared/storages/add.blade.php b/resources/views/livewire/project/shared/storages/add.blade.php index 3c46e43fb..f1d927e02 100644 --- a/resources/views/livewire/project/shared/storages/add.blade.php +++ b/resources/views/livewire/project/shared/storages/add.blade.php @@ -1,14 +1,28 @@ diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 049b1735f..e9f2d3d38 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -35,8 +35,10 @@
    - + @if (!$server->settings->is_swarm_worker) + + @endif
    @@ -53,10 +55,20 @@ helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.Coolify does not install/setup Cloudflare (cloudflared) on your server." id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" /> @endif - - {{-- --}} + @if ($server->settings->is_swarm_worker) + + @else + + @endif + @if ($server->settings->is_swarm_manager) + + @else + + @endif
    diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index 787270aee..23bc9f983 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -26,8 +26,19 @@ @endforeach
    - + @if ($is_swarm_worker) + + @else + + @endif + @if ($is_swarm_manager) + + @else + + @endif
    Save New Server diff --git a/resources/views/livewire/server/proxy/show.blade.php b/resources/views/livewire/server/proxy/show.blade.php index 33b30448e..a10113754 100644 --- a/resources/views/livewire/server/proxy/show.blade.php +++ b/resources/views/livewire/server/proxy/show.blade.php @@ -3,7 +3,9 @@
    - + @if ($server->proxyType() !== 'NONE' && $server->isFunctional()) + + @endif
    From 802a0f76843b084d90e70cda5f531bdda3262ad2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 18 Dec 2023 14:17:48 +0100 Subject: [PATCH 05/15] fix: do not push dockerimage --- app/Jobs/ApplicationDeploymentJob.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 263eb35f6..8f6a45578 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -596,7 +596,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private function rolling_update() { if ($this->server->isSwarm()) { - $this->push_to_docker_registry(); + if ($this->build_pack !== 'dockerimage') { + $this->push_to_docker_registry(); + } $this->application_deployment_queue->addLogEntry("Rolling update started."); $this->execute_remote_command( [ From 8ae385b9f9611a082912ef4ced3d0a3829a68bfd Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 18 Dec 2023 14:34:04 +0100 Subject: [PATCH 06/15] fix: add alpha to swarm --- .../views/components/forms/checkbox.blade.php | 2 +- .../views/livewire/server/form.blade.php | 33 +++++++++++-------- .../views/livewire/server/new/by-ip.blade.php | 15 ++++++--- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index 8cff88f48..98141b044 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -2,7 +2,7 @@
    diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index 23bc9f983..b1cb6a7e8 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -25,19 +25,24 @@ @endif @endforeach -
    +
    @if ($is_swarm_worker) + helper="For more information, please read the documentation here." + label="Is it a Swarm Manager?(alpha)" /> @else + helper="For more information, please read the documentation here." + label="Is it a Swarm Manager?(alpha)" /> @endif @if ($is_swarm_manager) + helper="For more information, please read the documentation here." + label="Is it a Swarm Worker?(alpha)" /> @else - + @endif
    From 70c662daf88223d0aa7da9d9e2421497e508fb84 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 18 Dec 2023 17:13:22 +0100 Subject: [PATCH 07/15] disable swarm for the next release --- resources/views/livewire/destination/new/docker.blade.php | 2 +- resources/views/livewire/server/form.blade.php | 4 ++-- resources/views/livewire/server/new/by-ip.blade.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/views/livewire/destination/new/docker.blade.php b/resources/views/livewire/destination/new/docker.blade.php index 2fe0c6340..dc9a48b00 100644 --- a/resources/views/livewire/destination/new/docker.blade.php +++ b/resources/views/livewire/destination/new/docker.blade.php @@ -12,7 +12,7 @@ @endforeach - + {{-- --}} Save Destination diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 3d244f649..6219a5136 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -54,7 +54,7 @@ - @if ($server->settings->is_swarm_worker) + {{-- @if ($server->settings->is_swarm_worker) @@ -71,7 +71,7 @@ - @endif + @endif --}} @endif
    diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index b1cb6a7e8..3723ccfab 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -25,7 +25,7 @@ @endif @endforeach -
    + {{--
    @if ($is_swarm_worker) @endif -
    +
    --}} Save New Server From ef595dd4c262ed43bc87c54f5deeb0a2d26b1447 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 12:24:43 +0100 Subject: [PATCH 08/15] fix: server not found --- app/Models/Server.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Models/Server.php b/app/Models/Server.php index 59046831f..04638ba53 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -391,6 +391,9 @@ class Server extends BaseModel public function validateConnection() { $server = Server::find($this->id); + if (!$server) { + return false; + } if ($server->skipServer()) { return false; } From 798acb8ee5d1f349f10fa7bf3ca0359d83b19c41 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 13:47:12 +0100 Subject: [PATCH 09/15] add swarm server grouping fixes for swarm --- app/Actions/Proxy/CheckProxy.php | 5 +++- app/Livewire/Project/New/Select.php | 2 +- app/Livewire/Server/New/ByIp.php | 17 ++++++++--- ...2_19_124111_add_swarm_cluster_grouping.php | 28 +++++++++++++++++ .../views/components/status/index.blade.php | 2 +- .../livewire/project/new/select.blade.php | 2 +- .../views/livewire/server/form.blade.php | 16 +++++----- .../views/livewire/server/new/by-ip.blade.php | 30 ++++++++++++++----- 8 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php index 32673abc9..ccefa8681 100644 --- a/app/Actions/Proxy/CheckProxy.php +++ b/app/Actions/Proxy/CheckProxy.php @@ -21,7 +21,10 @@ class CheckProxy $status = getContainerStatus($server, 'coolify-proxy_traefik'); $server->proxy->set('status', $status); $server->save(); - return false; + if ($status === 'running') { + return false; + } + return true; } else { $status = getContainerStatus($server, 'coolify-proxy'); if ($status === 'running') { diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index b205467bf..80a41d7c7 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -123,7 +123,7 @@ class Select extends Component $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false); break; } - if (str($type)->startsWith('one-click-service')) { + if (str($type)->startsWith('one-click-service') || str($type)->startsWith('docker-compose-empty') || str($type)->startsWith('docker-image')) { $this->isDatabase = true; $this->includeSwarm = false; $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false); diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index 98e7a99a7..1849cdfbc 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -23,8 +23,9 @@ class ByIp extends Component public int $port = 22; public bool $is_swarm_manager = false; public bool $is_swarm_worker = false; + public $selected_swarm_cluster = null; - + public $swarm_managers = []; protected $rules = [ 'name' => 'required|string', 'description' => 'nullable|string', @@ -48,6 +49,10 @@ class ByIp extends Component { $this->name = generate_random_name(); $this->private_key_id = $this->private_keys->first()->id; + $this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true); + if ($this->swarm_managers->count() > 0) { + $this->selected_swarm_cluster = $this->swarm_managers->first()->id; + } } public function setPrivateKey(string $private_key_id) @@ -57,7 +62,7 @@ class ByIp extends Component public function instantSave() { - $this->dispatch('success', 'Application settings updated!'); + // $this->dispatch('success', 'Application settings updated!'); } public function submit() @@ -67,7 +72,7 @@ class ByIp extends Component if (is_null($this->private_key_id)) { return $this->dispatch('error', 'You must select a private key'); } - $server = Server::create([ + $payload = [ 'name' => $this->name, 'description' => $this->description, 'ip' => $this->ip, @@ -79,7 +84,11 @@ class ByIp extends Component "type" => ProxyTypes::TRAEFIK_V2->value, "status" => ProxyStatus::EXITED->value, ], - ]); + ]; + if ($this->is_swarm_worker) { + $payload['swarm_cluster'] = $this->selected_swarm_cluster; + } + $server = Server::create($payload); $server->settings->is_swarm_manager = $this->is_swarm_manager; $server->settings->is_swarm_worker = $this->is_swarm_worker; $server->settings->save(); diff --git a/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php b/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php new file mode 100644 index 000000000..668acb6fe --- /dev/null +++ b/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php @@ -0,0 +1,28 @@ +integer('swarm_cluster')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('servers', function (Blueprint $table) { + $table->dropColumn('swarm_cluster'); + }); + } +}; diff --git a/resources/views/components/status/index.blade.php b/resources/views/components/status/index.blade.php index 050025f94..08d6b3cc2 100644 --- a/resources/views/components/status/index.blade.php +++ b/resources/views/components/status/index.blade.php @@ -1,6 +1,6 @@ @if (Str::of($status)->startsWith('running')) -@elseif(Str::of($status)->startsWith('restarting')) +@elseif(Str::of($status)->startsWith('restarting') || Str::of($status)->startsWith('starting')) @else diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index ae638b8ee..0d999aed6 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -205,7 +205,7 @@ @if ($isDatabase)
    here." label="Include Swarm Clusters" />
    diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 6219a5136..a96ff4296 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -54,26 +54,28 @@ - {{-- @if ($server->settings->is_swarm_worker) + @if ($server->isSwarm()) +
    Swarm support is in alpha version.
    + @endif + @if ($server->settings->is_swarm_worker) + label="Is it a Swarm Manager?" /> @else + label="Is it a Swarm Manager?" /> @endif @if ($server->settings->is_swarm_manager) + label="Is it a Swarm Worker?" /> @else - @endif --}} + label="Is it a Swarm Worker?" /> + @endif @endif -
    diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index 3723ccfab..3b958c0b3 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -25,26 +25,40 @@ @endif @endforeach - {{--
    +
    +
    Swarm support is in alpha version.
    @if ($is_swarm_worker) + label="Is it a Swarm Manager?" /> @else - + label="Is it a Swarm Manager?" /> @endif @if ($is_swarm_manager) + label="Is it a Swarm Worker?" /> @else - + label="Is it a Swarm Worker?" /> @endif -
    --}} + @if ($is_swarm_worker) +
    + + @foreach ($swarm_managers as $server) + @if ($loop->first) + + @else + + @endif + @endforeach + +
    + @endif +
    Save New Server From 7952202435352b16c6022b37eb73d77b84f882ea Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 14:19:23 +0100 Subject: [PATCH 10/15] fix: do not autovalidate server on mount --- app/Livewire/Server/Form.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 943be4458..d81d69e8f 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -44,9 +44,6 @@ class Form extends Component { $this->wildcard_domain = $this->server->settings->wildcard_domain; $this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage; - if (!$this->server->isFunctional()) { - $this->validateServer(); - } } public function serverRefresh($install = true) { From 0126286731791d6833c745cf9b2c82c620c29901 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 15:16:08 +0100 Subject: [PATCH 11/15] fix: server update schedule --- app/Jobs/ContainerStatusJob.php | 18 ++++++---- app/Models/Server.php | 52 ++++++++++++---------------- app/Notifications/Server/Revived.php | 2 +- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index c0d0e7ad9..bacfcb739 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -17,33 +17,37 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Arr; -use Illuminate\Support\Sleep; class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public $tries = 5; + public function backoff(): int + { + return isDev() ? 1 : 5; + } public function middleware(): array { - return [(new WithoutOverlapping($this->server->id))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))]; } public function uniqueId(): int { - return $this->server->id; + return $this->server->uuid; } public function __construct(public Server $server) { - $this->handle(); + // $this->handle(); } public function handle() { + if (!$this->server->isServerReady($this->tries)) { + throw new \RuntimeException('Server is not ready.'); + }; try { - if (!$this->server->isServerReady()) { - return; - }; if ($this->server->isSwarm()) { $containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this->server, false); $containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false); diff --git a/app/Models/Server.php b/app/Models/Server.php index 04638ba53..7bd791d11 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -12,7 +12,6 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Process; -use Illuminate\Support\Sleep; use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Illuminate\Support\Str; @@ -150,30 +149,35 @@ class Server extends BaseModel } return false; } - public function isServerReady() + public function isServerReady($tries) { - $serverUptimeCheckNumber = $this->unreachable_count; - $serverUptimeCheckNumberMax = 8; + $serverUptimeCheckNumber = $this->unreachable_count + 1; + $serverUptimeCheckNumberMax = $tries ?? 3; - $currentTime = now()->timestamp; - $runtime = 50; + ray('server: ' . $this->name); + ray('serverUptimeCheckNumber: ' . $serverUptimeCheckNumber); + ray('serverUptimeCheckNumberMax: ' . $serverUptimeCheckNumberMax); - $isReady = false; - // Run for 50 seconds max and check every 5 seconds for 8 times - while ($currentTime + $runtime > now()->timestamp) { - ray('serverUptimeCheckNumber: ' . $serverUptimeCheckNumber); + $result = $this->validateConnection(); + if ($result) { + if ($this->unreachable_notification_sent === true) { + $this->update(['unreachable_notification_sent' => false]); + } + return true; + } else { if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) { + // Reached max number of retries if ($this->unreachable_notification_sent === false) { ray('Server unreachable, sending notification...'); $this->team?->notify(new Unreachable($this)); $this->update(['unreachable_notification_sent' => true]); } - $this->settings()->update([ - 'is_reachable' => false, - ]); - $this->update([ - 'unreachable_count' => 0, - ]); + if ($this->settings->is_reachable === true) { + $this->settings()->update([ + 'is_reachable' => false, + ]); + } + foreach ($this->applications() as $application) { $application->update(['status' => 'exited']); } @@ -190,23 +194,13 @@ class Server extends BaseModel $db->update(['status' => 'exited']); } } - $isReady = false; - break; - } - $result = $this->validateConnection(); - // ray('validateConnection: ' . $result); - if (!$result) { - $serverUptimeCheckNumber++; + } else { $this->update([ - 'unreachable_count' => $serverUptimeCheckNumber, + 'unreachable_count' => $this->unreachable_count + 1, ]); - Sleep::for(5)->seconds(); - continue; } - $isReady = true; - break; + return false; } - return $isReady; } public function getDiskUsage() { diff --git a/app/Notifications/Server/Revived.php b/app/Notifications/Server/Revived.php index 400ef8377..3e5a99425 100644 --- a/app/Notifications/Server/Revived.php +++ b/app/Notifications/Server/Revived.php @@ -54,7 +54,7 @@ class Revived extends Notification implements ShouldQueue public function toDiscord(): string { - $message = "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"; + $message = "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"; return $message; } public function toTelegram(): array From ba769f5fb768c048a3623b7677dfbf177bdf90da Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 15:36:59 +0100 Subject: [PATCH 12/15] fix --- app/Jobs/ContainerStatusJob.php | 2 +- app/Models/Server.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index bacfcb739..15dad0a06 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -45,7 +45,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted public function handle() { if (!$this->server->isServerReady($this->tries)) { - throw new \RuntimeException('Server is not ready.'); + throw new \RuntimeException('Server is not reachable.'); }; try { if ($this->server->isSwarm()) { diff --git a/app/Models/Server.php b/app/Models/Server.php index 7bd791d11..285ce01db 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -149,10 +149,10 @@ class Server extends BaseModel } return false; } - public function isServerReady($tries) + public function isServerReady(int $tries = 3) { $serverUptimeCheckNumber = $this->unreachable_count + 1; - $serverUptimeCheckNumberMax = $tries ?? 3; + $serverUptimeCheckNumberMax = $tries; ray('server: ' . $this->name); ray('serverUptimeCheckNumber: ' . $serverUptimeCheckNumber); From e2e3ad0358c9d6f2531f5fdfe6920707ee6853b3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 15:41:53 +0100 Subject: [PATCH 13/15] get branchname gh actions --- .github/workflows/development-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/development-build.yml b/.github/workflows/development-build.yml index 681cbda3a..312162c21 100644 --- a/.github/workflows/development-build.yml +++ b/.github/workflows/development-build.yml @@ -29,7 +29,7 @@ jobs: file: docker/prod-ssu/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} aarch64: runs-on: [self-hosted, arm64] permissions: @@ -50,7 +50,7 @@ jobs: file: docker/prod-ssu/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64 + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 merge-manifest: runs-on: ubuntu-latest permissions: @@ -72,7 +72,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Create & publish manifest run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - uses: sarisia/actions-status-discord@v1 if: always() with: From a745f568f3101d524f2f29fad9ecf3c52845574d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 15:44:01 +0100 Subject: [PATCH 14/15] gh actions update --- .github/workflows/development-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/development-build.yml b/.github/workflows/development-build.yml index 312162c21..8e32279e8 100644 --- a/.github/workflows/development-build.yml +++ b/.github/workflows/development-build.yml @@ -2,7 +2,7 @@ name: Development Build (v4) on: push: - branches: ["next"] + branches-ignore: ["main"] paths-ignore: - .github/workflows/coolify-helper.yml - docker/coolify-helper/Dockerfile From f75effe022180cd9bdbbafbb8b6dd7d5b1ecbc7a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 19 Dec 2023 15:44:41 +0100 Subject: [PATCH 15/15] fix --- .github/workflows/development-build.yml | 92 ++++++++++++------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/.github/workflows/development-build.yml b/.github/workflows/development-build.yml index 8e32279e8..7d9b730c4 100644 --- a/.github/workflows/development-build.yml +++ b/.github/workflows/development-build.yml @@ -2,7 +2,7 @@ name: Development Build (v4) on: push: - branches-ignore: ["main"] + branches-ignore: ["main", "v3"] paths-ignore: - .github/workflows/coolify-helper.yml - docker/coolify-helper/Dockerfile @@ -31,49 +31,49 @@ jobs: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} aarch64: - runs-on: [self-hosted, arm64] - permissions: - contents: read - packages: write - steps: - - uses: actions/checkout@v3 - - name: Login to ghcr.io - uses: docker/login-action@v2 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image and push to registry - uses: docker/build-push-action@v3 - with: - context: . - file: docker/prod-ssu/Dockerfile - platforms: linux/aarch64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 + runs-on: [self-hosted, arm64] + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v3 + - name: Login to ghcr.io + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build image and push to registry + uses: docker/build-push-action@v3 + with: + context: . + file: docker/prod-ssu/Dockerfile + platforms: linux/aarch64 + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 merge-manifest: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - needs: [amd64, aarch64] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Login to ghcr.io - uses: docker/login-action@v2 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Create & publish manifest - run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - - uses: sarisia/actions-status-discord@v1 - if: always() - with: - webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + needs: [amd64, aarch64] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to ghcr.io + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Create & publish manifest + run: | + docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}