From 2d7bbbe30089b8b75aa3ae51a544aac8f6e27827 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 29 Nov 2023 10:06:52 +0100 Subject: [PATCH] wip: swarm --- app/Actions/Proxy/StartProxy.php | 2 +- app/Actions/Server/InstallDocker.php | 16 ++++++-- app/Http/Livewire/Boarding/Index.php | 4 +- app/Http/Livewire/Server/Form.php | 8 ++-- app/Http/Livewire/Server/New/ByIp.php | 8 ++-- app/Jobs/ApplicationDeploymentJob.php | 15 ++++--- app/Jobs/ContainerStatusJob.php | 5 +++ app/Models/Server.php | 2 +- bootstrap/helpers/proxy.php | 40 ++++++++++++------- ...3_11_29_075937_change_swarm_properties.php | 30 ++++++++++++++ .../components/applications/navbar.blade.php | 2 + .../views/livewire/boarding/index.blade.php | 2 +- .../views/livewire/server/form.blade.php | 4 +- .../views/livewire/server/new/by-ip.blade.php | 2 +- scripts/upgrade.sh | 3 +- 15 files changed, 106 insertions(+), 37 deletions(-) create mode 100644 database/migrations/2023_11_29_075937_change_swarm_properties.php diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index b6f657b35..a99e47b25 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -30,7 +30,7 @@ public function handle(Server $server, bool $async = true): string|Activity "mkdir -p $proxy_path && cd $proxy_path", "echo 'Creating required Docker Compose file.'", "echo 'Starting coolify-proxy.'", - // "docker stack deploy -c docker-compose.yaml coolify-proxy", + "cd $proxy_path && docker stack deploy -c docker-compose.yml coolify-proxy", "echo 'Proxy started successfully.'" ]); } else { diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index a580c3473..79863d989 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -76,10 +76,20 @@ public function handle(Server $server) "echo 'Restarting Docker Engine...'", "systemctl enable docker >/dev/null 2>&1 || true", "systemctl restart docker", - "echo 'Creating default Docker network (coolify)...'", - "docker network create --attachable coolify >/dev/null 2>&1 || true", - "echo 'Done!'" ]); + if ($server->isSwarm()) { + $command = $command->merge([ + "docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true", + ]); + } else { + $command = $command->merge([ + "docker network create --attachable coolify >/dev/null 2>&1 || true", + ]); + $command = $command->merge([ + "echo 'Done!'", + ]); + } + return remote_process($command, $server); } } diff --git a/app/Http/Livewire/Boarding/Index.php b/app/Http/Livewire/Boarding/Index.php index 645b0da6a..67221d0c6 100644 --- a/app/Http/Livewire/Boarding/Index.php +++ b/app/Http/Livewire/Boarding/Index.php @@ -31,7 +31,7 @@ class Index extends Component public ?string $remoteServerHost = null; public ?int $remoteServerPort = 22; public ?string $remoteServerUser = 'root'; - public bool $isPartOfSwarm = false; + public bool $isSwarmManager = false; public ?Server $createdServer = null; public Collection $projects; @@ -183,7 +183,7 @@ public function saveServer() 'private_key_id' => $this->createdPrivateKey->id, 'team_id' => currentTeam()->id, ]); - $this->createdServer->settings->is_part_of_swarm = $this->isPartOfSwarm; + $this->createdServer->settings->is_swarm_manager = $this->isSwarmManager; $this->createdServer->settings->save(); $this->createdServer->addInitialNetwork(); $this->validateServer(); diff --git a/app/Http/Livewire/Server/Form.php b/app/Http/Livewire/Server/Form.php index 27dfaa8e2..efca800c2 100644 --- a/app/Http/Livewire/Server/Form.php +++ b/app/Http/Livewire/Server/Form.php @@ -24,7 +24,8 @@ class Form extends Component 'server.port' => 'required', 'server.settings.is_cloudflare_tunnel' => 'required|boolean', 'server.settings.is_reachable' => 'required', - 'server.settings.is_part_of_swarm' => 'required|boolean', + 'server.settings.is_swarm_manager' => 'required|boolean', + // 'server.settings.is_swarm_worker' => 'required|boolean', 'wildcard_domain' => 'nullable|url', ]; protected $validationAttributes = [ @@ -34,8 +35,9 @@ class Form extends Component 'server.user' => 'User', 'server.port' => 'Port', 'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', - 'server.settings.is_reachable' => 'is reachable', - 'server.settings.is_part_of_swarm' => 'is part of swarm' + 'server.settings.is_reachable' => 'Is reachable', + 'server.settings.is_swarm_manager' => 'Swarm Manager', + // 'server.settings.is_swarm_worker' => 'Swarm Worker', ]; public function mount() diff --git a/app/Http/Livewire/Server/New/ByIp.php b/app/Http/Livewire/Server/New/ByIp.php index 139705d94..858f4ffa1 100644 --- a/app/Http/Livewire/Server/New/ByIp.php +++ b/app/Http/Livewire/Server/New/ByIp.php @@ -21,7 +21,7 @@ class ByIp extends Component public string $ip; public string $user = 'root'; public int $port = 22; - public bool $is_part_of_swarm = false; + public bool $is_swarm_manager = false; protected $rules = [ 'name' => 'required|string', @@ -29,7 +29,7 @@ class ByIp extends Component 'ip' => 'required', 'user' => 'required|string', 'port' => 'required|integer', - 'is_part_of_swarm' => 'required|boolean', + 'is_swarm_manager' => 'required|boolean', ]; protected $validationAttributes = [ 'name' => 'Name', @@ -37,7 +37,7 @@ class ByIp extends Component 'ip' => 'IP Address/Domain', 'user' => 'User', 'port' => 'Port', - 'is_part_of_swarm' => 'Is part of swarm', + 'is_swarm_manager' => 'Swarm Manager', ]; public function mount() @@ -76,7 +76,7 @@ public function submit() "status" => ProxyStatus::EXITED->value, ], ]); - $server->settings->is_part_of_swarm = $this->is_part_of_swarm; + $server->settings->is_swarm_manager = $this->is_swarm_manager; $server->settings->save(); $server->addInitialNetwork(); return redirect()->route('server.show', $server->uuid); diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 02473e0a5..bd6d7436a 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -453,11 +453,16 @@ private function deploy_docker_compose_buildpack() if ($this->pull_request_id !== 0) { $networkId = "{$this->application->uuid}-{$this->pull_request_id}"; } - $this->execute_remote_command([ - "docker network create --attachable '{$networkId}' >/dev/null || true", "hidden" => true, "ignore_errors" => true - ], [ - "docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true - ]); + if ($this->server->isSwarm()) { + // TODO + } else { + $this->execute_remote_command([ + "docker network create --attachable '{$networkId}' >/dev/null || true", "hidden" => true, "ignore_errors" => true + ], [ + "docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true + ]); + } + $this->start_by_compose_file(); $this->application->loadComposeFile(isInit: false); } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index e30729299..30324baab 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -42,6 +42,11 @@ public function handle() if (!$this->server->isServerReady()) { return; }; + if ($this->server->isSwarm()) { + + } else { + + } $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false); if (is_null($containers)) { return; diff --git a/app/Models/Server.php b/app/Models/Server.php index 5e3762971..408106107 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -378,7 +378,7 @@ public function validateOS(): bool | Stringable } public function isSwarm() { - return data_get($this, 'settings.is_part_of_swarm'); + return data_get($this, 'settings.is_swarm_manager') || data_get($this, 'settings.is_swarm_worker'); } public function validateConnection() { diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 614988eca..76fa9cc5a 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -54,9 +54,15 @@ function connectProxyToNetworks(Server $server) function generate_default_proxy_configuration(Server $server) { $proxy_path = get_proxy_path(); - $networks = collect($server->standaloneDockers)->map(function ($docker) { - return $docker['network']; - })->unique(); + if ($server->isSwarm()) { + $networks = collect($server->swarmDockers)->map(function ($docker) { + return $docker['network']; + })->unique(); + } else { + $networks = collect($server->standaloneDockers)->map(function ($docker) { + return $docker['network']; + })->unique(); + } if ($networks->count() === 0) { $networks = collect(['coolify']); } @@ -66,6 +72,16 @@ function generate_default_proxy_configuration(Server $server) "external" => true, ]; }); + $labels = [ + "traefik.enable=true", + "traefik.http.routers.traefik.entrypoints=http", + "traefik.http.routers.traefik.middlewares=traefik-basic-auth@file", + "traefik.http.routers.traefik.service=api@internal", + "traefik.http.services.traefik.loadbalancer.server.port=8080", + // Global Middlewares + "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https", + "traefik.http.middlewares.gzip.compress=true", + ]; $config = [ "version" => "3.8", "networks" => $array_of_networks->toArray(), @@ -109,16 +125,7 @@ function generate_default_proxy_configuration(Server $server) "--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json", "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http", ], - "labels" => [ - "traefik.enable=true", - "traefik.http.routers.traefik.entrypoints=http", - "traefik.http.routers.traefik.middlewares=traefik-basic-auth@file", - "traefik.http.routers.traefik.service=api@internal", - "traefik.http.services.traefik.loadbalancer.server.port=8080", - // Global Middlewares - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https", - "traefik.http.middlewares.gzip.compress=true", - ], + "labels" => $labels, ], ], ]; @@ -128,8 +135,13 @@ function generate_default_proxy_configuration(Server $server) $config['services']['traefik']['command'][] = "--accesslog.bufferingsize=100"; } if ($server->isSwarm()) { + data_forget($config, 'services.traefik.container_name'); + data_forget($config, 'services.traefik.restart'); + data_forget($config, 'services.traefik.labels'); + $config['services']['traefik']['command'][] = "--providers.docker.swarmMode=true"; $config['services']['traefik']['deploy'] = [ + "labels" => $labels, "placement" => [ "constraints" => [ "node.role==manager", @@ -139,7 +151,7 @@ function generate_default_proxy_configuration(Server $server) } else { $config['services']['traefik']['command'][] = "--providers.docker=true"; } - $config = Yaml::dump($config, 4, 2); + $config = Yaml::dump($config, 12, 2); SaveConfiguration::run($server, $config); return $config; } diff --git a/database/migrations/2023_11_29_075937_change_swarm_properties.php b/database/migrations/2023_11_29_075937_change_swarm_properties.php new file mode 100644 index 000000000..6c0edc432 --- /dev/null +++ b/database/migrations/2023_11_29_075937_change_swarm_properties.php @@ -0,0 +1,30 @@ +renameColumn('is_part_of_swarm', 'is_swarm_manager'); + $table->boolean('is_swarm_worker')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('server_settings', function (Blueprint $table) { + $table->renameColumn('is_swarm_manager', 'is_part_of_swarm'); + $table->dropColumn('is_swarm_worker'); + }); + } +}; diff --git a/resources/views/components/applications/navbar.blade.php b/resources/views/components/applications/navbar.blade.php index d0cd565dc..9bd048e26 100644 --- a/resources/views/components/applications/navbar.blade.php +++ b/resources/views/components/applications/navbar.blade.php @@ -15,6 +15,8 @@
@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->status !== 'exited') diff --git a/resources/views/livewire/boarding/index.blade.php b/resources/views/livewire/boarding/index.blade.php index 9f8e47961..fb102c7c5 100644 --- a/resources/views/livewire/boarding/index.blade.php +++ b/resources/views/livewire/boarding/index.blade.php @@ -208,7 +208,7 @@ id="remoteServerUser" />
-
Check Connection diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index c124a6b25..528fd32c5 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -54,8 +54,10 @@ 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 410f27fa7..62268f2fe 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -26,7 +26,7 @@ @endforeach
-
diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh index 3c44308a0..af6463869 100644 --- a/scripts/upgrade.sh +++ b/scripts/upgrade.sh @@ -16,6 +16,7 @@ curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' > /data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env # Make sure coolify network exists -docker network create coolify 2>/dev/null +docker network create --attachable coolify 2>/dev/null +# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --pull always --remove-orphans --force-recreate"