wip: swarm

This commit is contained in:
Andras Bacsai 2023-11-29 10:06:52 +01:00
parent 928b68043b
commit 2d7bbbe300
15 changed files with 106 additions and 37 deletions

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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()

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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()
{

View File

@ -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;
}

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('server_settings', function (Blueprint $table) {
$table->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');
});
}
};

View File

@ -15,6 +15,8 @@
<div class="flex-1"></div>
@if ($application->build_pack === 'dockercompose' && is_null($application->docker_compose_raw))
<div>Please load a Compose file.</div>
@elseif ($application->destination->server->isSwarm() && str($application->docker_registry_image_name)->isEmpty())
Swarm Deployments requires a Docker Image in a Registry.
@else
<x-applications.advanced :application="$application" />
@if ($application->status !== 'exited')

View File

@ -208,7 +208,7 @@
id="remoteServerUser" />
</div>
<div class="w-64">
<x-forms.checkbox type="checkbox" id="isPartOfSwarm"
<x-forms.checkbox type="checkbox" id="isSwarmManager"
label="Is it a Swarm Manager?" />
</div>
<x-forms.button type="submit">Check Connection</x-forms.button>

View File

@ -54,8 +54,10 @@
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
@endif
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_part_of_swarm"
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager"
label="Is it a Swarm Manager?" />
{{-- <x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker"
label="Is it a Swarm Worker?" /> --}}
</div>
</div>

View File

@ -26,7 +26,7 @@
@endforeach
</x-forms.select>
<div class="w-64">
<x-forms.checkbox type="checkbox" id="is_part_of_swarm"
<x-forms.checkbox type="checkbox" id="is_swarm_manager"
label="Is it a Swarm Manager?" />
</div>
<x-forms.button type="submit">

View File

@ -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"