Implement Keystone environment deployments
This commit is contained in:
205
app/Drivers/Laravel/LaravelRuntimeDriver.php
Normal file
205
app/Drivers/Laravel/LaravelRuntimeDriver.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
namespace App\Drivers\Laravel;
|
||||
|
||||
use App\Actions\Environments\BuildMigrationScript;
|
||||
use App\Data\Operations\Plan;
|
||||
use App\Data\Operations\PlannedStep;
|
||||
use App\Drivers\Concerns\RendersCompose;
|
||||
use App\Drivers\Driver;
|
||||
use App\Enums\SchedulerMode;
|
||||
use App\Enums\ServiceType;
|
||||
use App\Models\Service;
|
||||
|
||||
class LaravelRuntimeDriver extends Driver implements RendersCompose
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $containerName = null,
|
||||
public ?string $containerId = null,
|
||||
public ?Service $service = null,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
public function getOperationPlan(string $operationHash): Plan
|
||||
{
|
||||
return new Plan(steps: [
|
||||
new PlannedStep(
|
||||
name: 'Render Laravel Compose file',
|
||||
script: "mkdir -p /home/keystone/services/{$this->service?->id}",
|
||||
),
|
||||
new PlannedStep(
|
||||
name: 'Run migrations',
|
||||
script: $this->service
|
||||
? app(BuildMigrationScript::class)->execute($this->service)
|
||||
: 'true',
|
||||
),
|
||||
new PlannedStep(
|
||||
name: 'Start Laravel replica',
|
||||
script: "docker compose -f /home/keystone/services/{$this->service?->id}/compose.yml up -d",
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
public function serviceType(): ServiceType
|
||||
{
|
||||
return ServiceType::LARAVEL;
|
||||
}
|
||||
|
||||
public function versionTrack(): string
|
||||
{
|
||||
return 'php-8.4';
|
||||
}
|
||||
|
||||
public function defaultImage(): string
|
||||
{
|
||||
return 'serversideup/php:8.4-frankenphp';
|
||||
}
|
||||
|
||||
public function defaultPorts(): array
|
||||
{
|
||||
return [80];
|
||||
}
|
||||
|
||||
public function firewallRules(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function environmentSchema(): array
|
||||
{
|
||||
return [
|
||||
'APP_ENV' => 'string',
|
||||
'SERVER_NAME' => 'string',
|
||||
];
|
||||
}
|
||||
|
||||
public function resourceDefaults(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function updateBehavior(): string
|
||||
{
|
||||
return 'stateless_gateway_cutover';
|
||||
}
|
||||
|
||||
public function composeService(): array
|
||||
{
|
||||
$image = $this->service?->available_image_digest
|
||||
?: $this->service?->current_image_digest
|
||||
?: ($this->service?->config['image'] ?? $this->defaultImage());
|
||||
|
||||
$service = [
|
||||
'image' => $image,
|
||||
'restart' => 'unless-stopped',
|
||||
'environment' => $this->environmentExports(),
|
||||
];
|
||||
|
||||
if ($command = $this->service?->config['command'] ?? null) {
|
||||
$service['command'] = $command;
|
||||
}
|
||||
|
||||
if (! in_array('worker', $this->service?->process_roles ?? [], true)) {
|
||||
$service['healthcheck'] = [
|
||||
'test' => ['CMD-SHELL', 'curl -fsS http://localhost'.($this->service?->config['health_path'] ?? '/up').' || exit 1'],
|
||||
'interval' => '10s',
|
||||
'timeout' => '5s',
|
||||
'retries' => 5,
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->service?->default_cpu_limit) {
|
||||
$service['cpus'] = (string) $this->service->default_cpu_limit;
|
||||
}
|
||||
|
||||
if ($this->service?->default_memory_limit_mb) {
|
||||
$service['mem_limit'] = "{$this->service->default_memory_limit_mb}m";
|
||||
$service['memswap_limit'] = "{$this->service->default_memory_limit_mb}m";
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
public function composeVolumes(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function environmentExports(): array
|
||||
{
|
||||
$environment = $this->service?->environment?->variables()
|
||||
->pluck('value', 'key')
|
||||
->all() ?? [];
|
||||
|
||||
$environment = [
|
||||
...$environment,
|
||||
'APP_ENV' => $this->service?->environment?->name ?? 'production',
|
||||
'SERVER_NAME' => ':80',
|
||||
];
|
||||
|
||||
if ($this->shouldAutorunScheduler()) {
|
||||
$environment['AUTORUN_LARAVEL_SCHEDULER'] = 'true';
|
||||
}
|
||||
|
||||
return $environment;
|
||||
}
|
||||
|
||||
private function shouldAutorunScheduler(): bool
|
||||
{
|
||||
if (! in_array('scheduler', $this->service?->process_roles ?? [], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$environment = $this->service?->environment;
|
||||
|
||||
if (! $environment?->scheduler_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($environment->scheduler_target_service_id && $environment->scheduler_target_service_id !== $this->service?->id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $environment->scheduler_mode !== SchedulerMode::SINGLE
|
||||
|| (int) $this->service?->desired_replicas === 1;
|
||||
}
|
||||
|
||||
public function dockerfileTemplate(): string
|
||||
{
|
||||
$phpVersion = $this->service?->config['php_version'] ?? '8.4';
|
||||
$documentRoot = $this->service?->config['document_root'] ?? 'public';
|
||||
$jsBuildCommand = $this->service?->config['js_build_command'] ?? $this->service?->environment?->build_config['js_build_command'] ?? null;
|
||||
$jsPackageManager = $this->service?->config['js_package_manager'] ?? $this->service?->environment?->build_config['js_package_manager'] ?? 'bun';
|
||||
$jsBuildSteps = $this->jsBuildSteps($jsPackageManager, $jsBuildCommand);
|
||||
|
||||
return <<<DOCKERFILE
|
||||
FROM serversideup/php:{$phpVersion}-frankenphp
|
||||
|
||||
ENV SSL_MODE=off
|
||||
ENV AUTORUN_ENABLED=true
|
||||
ENV PHP_OPCACHE_ENABLE=1
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY --chown=www-data:www-data . .
|
||||
|
||||
RUN composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
|
||||
{$jsBuildSteps}
|
||||
|
||||
ENV SERVER_DOCUMENT_ROOT=/var/www/html/{$documentRoot}
|
||||
DOCKERFILE;
|
||||
}
|
||||
|
||||
private function jsBuildSteps(string $packageManager, ?string $buildCommand): string
|
||||
{
|
||||
if (! $buildCommand) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return match ($packageManager) {
|
||||
'npm' => "\nRUN npm ci && {$buildCommand}",
|
||||
default => "\nRUN curl -fsSL https://bun.sh/install | bash && export PATH=\"/root/.bun/bin:\$PATH\" && bun install --frozen-lockfile && {$buildCommand}",
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user