Implement Keystone environment deployments
This commit is contained in:
@@ -2,15 +2,20 @@
|
||||
|
||||
namespace App\Drivers\Caddy;
|
||||
|
||||
use App\Data\Operations\Plan;
|
||||
use App\Data\Operations\PlannedStep;
|
||||
use App\Drivers\Concerns\RendersCompose;
|
||||
use App\Drivers\Concerns\SupportsSlices;
|
||||
use App\Drivers\GatewayDriver;
|
||||
use App\Data\Deployments\Plan;
|
||||
use App\Data\Deployments\PlannedStep as Step;
|
||||
use App\Enums\DeploymentStatus;
|
||||
use App\Enums\EnvironmentAttachmentRole;
|
||||
use App\Enums\ServiceType;
|
||||
use App\Models\Service;
|
||||
use App\Models\ServiceSlice;
|
||||
|
||||
class Caddy2Driver extends GatewayDriver
|
||||
class Caddy2Driver extends GatewayDriver implements RendersCompose, SupportsSlices
|
||||
{
|
||||
public ?string $containerName;
|
||||
|
||||
public ?string $containerId;
|
||||
|
||||
public function __construct(
|
||||
@@ -23,55 +28,112 @@ class Caddy2Driver extends GatewayDriver
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function getDeploymentPlan(string $deploymentHash): Plan
|
||||
public function getOperationPlan(string $operationHash): Plan
|
||||
{
|
||||
$previousDeployment = $this->service?->deployments()
|
||||
->where('status', DeploymentStatus::COMPLETED)
|
||||
->first();
|
||||
|
||||
return new Plan(steps: [
|
||||
new Step(
|
||||
name: 'Generate Caddyfile',
|
||||
script: function () {
|
||||
$script = collect();
|
||||
$script->push('cd ~');
|
||||
$script->push('test -d services || mkdir services');
|
||||
$script->push('cd services');
|
||||
$script->push("test -d {$this->service->id} || mkdir {$this->service->id}");
|
||||
$script->push("cd {$this->service->id}");
|
||||
return $script->join("\n");
|
||||
}
|
||||
new PlannedStep(
|
||||
name: 'Render Caddy Compose files',
|
||||
script: "mkdir -p /home/keystone/gateway /home/keystone/services/{$this->service?->id}",
|
||||
),
|
||||
new Step(
|
||||
name: 'Run the docker image',
|
||||
script: function () use ($previousDeployment, $deploymentHash) {
|
||||
$script = collect();
|
||||
if ($this->containerName && $previousDeployment) {
|
||||
$script->push("docker stop \"{$this->containerName}-{$previousDeployment->hash}\" || true");
|
||||
} elseif ($this->containerId) {
|
||||
$script->push('docker stop ' . $this->containerId . ' || true');
|
||||
}
|
||||
|
||||
$runCommand = 'docker run -d';
|
||||
if ($this->containerName) {
|
||||
$runCommand .= " --name \"{$this->containerName}-{$deploymentHash}\"";
|
||||
}
|
||||
$runCommand .= ' -p 80:80 -p 443:443 caddy:2';
|
||||
|
||||
$script->push($runCommand);
|
||||
|
||||
return $script->join(" && ");
|
||||
}
|
||||
new PlannedStep(
|
||||
name: 'Start Caddy gateway',
|
||||
script: "docker compose -f /home/keystone/services/{$this->service?->id}/compose.yml up -d",
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
public function buildCaddyfile(): string
|
||||
public function serviceType(): ServiceType
|
||||
{
|
||||
$caddyfile = "http://{$this->service->name} {\n";
|
||||
$caddyfile .= " reverse_proxy {$this->service->credentials['backend']}\n";
|
||||
$caddyfile .= "}\n";
|
||||
return ServiceType::CADDY;
|
||||
}
|
||||
|
||||
return $caddyfile;
|
||||
public function versionTrack(): string
|
||||
{
|
||||
return '2';
|
||||
}
|
||||
|
||||
public function defaultImage(): string
|
||||
{
|
||||
return 'caddy:2';
|
||||
}
|
||||
|
||||
public function defaultPorts(): array
|
||||
{
|
||||
return [80, 443];
|
||||
}
|
||||
|
||||
public function firewallRules(): array
|
||||
{
|
||||
return ['80/tcp', '443/tcp'];
|
||||
}
|
||||
|
||||
public function environmentSchema(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function resourceDefaults(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function updateBehavior(): string
|
||||
{
|
||||
return 'stateless_redeploy';
|
||||
}
|
||||
|
||||
public function composeService(): array
|
||||
{
|
||||
return [
|
||||
'image' => $this->service?->available_image_digest
|
||||
?: $this->service?->current_image_digest
|
||||
?: $this->defaultImage(),
|
||||
'restart' => 'unless-stopped',
|
||||
'ports' => ['80:80', '443:443'],
|
||||
'volumes' => [
|
||||
'/home/keystone/gateway/Caddyfile:/etc/caddy/Caddyfile:ro',
|
||||
"keystone_service_{$this->service?->id}_caddy_data:/data",
|
||||
"keystone_service_{$this->service?->id}_caddy_config:/config",
|
||||
],
|
||||
'healthcheck' => [
|
||||
'test' => ['CMD', 'caddy', 'version'],
|
||||
'interval' => '10s',
|
||||
'timeout' => '5s',
|
||||
'retries' => 5,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function composeVolumes(): array
|
||||
{
|
||||
return [
|
||||
"keystone_service_{$this->service?->id}_caddy_data" => null,
|
||||
"keystone_service_{$this->service?->id}_caddy_config" => null,
|
||||
];
|
||||
}
|
||||
|
||||
public function environmentExports(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function supportedSliceTypes(): array
|
||||
{
|
||||
return ['route'];
|
||||
}
|
||||
|
||||
public function environmentExportsForSlice(ServiceSlice $slice, ?EnvironmentAttachmentRole $role = null): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function provisionSliceScript(ServiceSlice $slice): string
|
||||
{
|
||||
return implode("\n", [
|
||||
'set -euo pipefail',
|
||||
'mkdir -p /home/keystone/gateway/Caddyfile.d',
|
||||
'test -f /home/keystone/gateway/Caddyfile || touch /home/keystone/gateway/Caddyfile',
|
||||
"test ! -e /home/keystone/gateway/Caddyfile.d/{$slice->id}.caddy || true",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user