Skip to content

Commit

Permalink
feat: #258 allow to build images with nixpacks
Browse files Browse the repository at this point in the history
  • Loading branch information
bohdan-shulha committed Nov 8, 2024
1 parent eafbc50 commit 22867a4
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace App\Events\NodeTasks\BuildImageWithNixpacks;

use App\Events\NodeTasks\BaseTaskEvent;

class BuildImageWithNixpacksCompleted extends BaseTaskEvent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace App\Events\NodeTasks\BuildImageWithNixpacks;

use App\Events\NodeTasks\BaseTaskEvent;

class BuildImageWithNixpacksFailed extends BaseTaskEvent {}
5 changes: 3 additions & 2 deletions app/Models/DeploymentData/AppSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Models\DeploymentData\AppSource\AppSourceType;
use App\Models\DeploymentData\AppSource\DockerSource;
use App\Models\DeploymentData\AppSource\GitWithDockerfileSource;
use App\Models\DeploymentData\AppSource\GitWithNixpacksSource;
use Spatie\LaravelData\Attributes\Validation\Enum;
use Spatie\LaravelData\Attributes\Validation\ProhibitedUnless;
use Spatie\LaravelData\Attributes\Validation\RequiredIf;
Expand All @@ -19,7 +20,7 @@ public function __construct(
public ?DockerSource $docker,
#[RequiredIf('type', AppSourceType::GitWithDockerfile), ProhibitedUnless('type', AppSourceType::GitWithDockerfile)]
public ?GitWithDockerfileSource $git,
// #[RequiredIf('type', AppSourceType::GitWithNixpacks), ProhibitedUnless('type', AppSourceType::GitWithNixpacks)]
// public ?GitWithNixpacksSource $nixpacks,
#[RequiredIf('type', AppSourceType::GitWithNixpacks), ProhibitedUnless('type', AppSourceType::GitWithNixpacks)]
public ?GitWithNixpacksSource $nixpacks,
) {}
}
16 changes: 16 additions & 0 deletions app/Models/DeploymentData/AppSource/GitWithNixpacksSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Models\DeploymentData\AppSource;

use App\Models\DeploymentData\Volume;
use Spatie\LaravelData\Data;

class GitWithNixpacksSource extends Data
{
public function __construct(
public string $repo,
public string $ref,
public string $nixpacksFilePath,
public ?Volume $volume,
) {}
}
202 changes: 120 additions & 82 deletions app/Models/DeploymentData/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Models\Deployment;
use App\Models\DeploymentData\AppSource\AppSourceType;
use App\Models\NodeTasks\BuildImageWithDockerfile\BuildImageWithDockerfileMeta;
use App\Models\NodeTasks\BuildImageWithNixpacks\BuildImageWithNixpacksMeta;
use App\Models\NodeTasks\DownloadS3File\DownloadS3FileMeta;
use App\Models\NodeTasks\LaunchService\LaunchServiceMeta;
use App\Models\NodeTasks\PullDockerImage\PullDockerImageMeta;
Expand Down Expand Up @@ -55,35 +56,11 @@ public function __construct(
if ($this->replicas > $maxInitialReplicas) {
$this->replicas = $maxInitialReplicas;
}

if ($this->source->type === AppSourceType::GitWithDockerfile) {
if (! $this->source->git->volume) {
$this->source->git->volume = Volume::validateAndCreate([
'id' => ResourceId::make('volume'),
'name' => 'data',
'dockerName' => $this->makeResourceName('vol_ptah_git'),
'path' => '/ptah/git',
]);
}
}

// if ($this->source->type === AppSourceType::GitWithNixpacks) {
// if (! $this->source->nixpacks->volume) {
// $this->source->nixpacks->volume = Volume::validateAndCreate([
// 'id' => ResourceId::make('volume'),
// 'name' => $this->dockerName.'_vol_ptah_nixpacks',
// 'dockerName' => $this->dockerName.'_vol_ptah_nixpacks',
// 'path' => '/nixpacks',
// ]);
// }
// }
}

public function asNodeTasks(Deployment $deployment, Process $process, bool $buildOrPull = true, ?int $desiredReplicas = null, ?Backup $backup = null): array
{
if (! $this->dockerName) {
$this->dockerName = $process->makeResourceName('wkr_'.$this->name);
}
$this->ensureVolumes($process);

$launchNow = is_null($desiredReplicas) ? $this->replicas > 0 : $desiredReplicas > 0;

Expand Down Expand Up @@ -164,14 +141,14 @@ public function asNodeTasks(Deployment $deployment, Process $process, bool $buil
'workerName' => $this->name,
]),
'payload' => [
'ReleaseCommand' => $this->getReleaseCommandPayload($deployment, $labels),
'ReleaseCommand' => $this->getReleaseCommandPayload($deployment, $process, $labels),
'SecretVars' => $this->getSecretVars($process),
'SwarmServiceSpec' => [
'Name' => $this->dockerName,
'Labels' => $labels,
'TaskTemplate' => [
'ContainerSpec' => [
'Image' => $this->getDockerImage(),
'Image' => $this->getDockerImage($process),
'Labels' => $labels,
'Command' => $command,
'Args' => $args,
Expand Down Expand Up @@ -241,91 +218,152 @@ public function asNodeTasks(Deployment $deployment, Process $process, bool $buil
return $tasks;
}

public function getDockerImage(): string
private function getDockerName(Process $process): string
{
if (! $this->dockerName) {
$this->dockerName = $process->makeResourceName('wkr_'.$this->name);
}

return $this->dockerName;
}

private function ensureVolumes(Process $process): void
{

if ($this->source->type === AppSourceType::GitWithDockerfile) {
if (! $this->source->git->volume) {
$this->source->git->volume = Volume::validateAndCreate([
'id' => ResourceId::make('volume'),
'name' => 'data',
'dockerName' => $this->makeResourceName($process, 'vol_ptah_git'),
'path' => '/ptah/git',
]);
}
}

if ($this->source->type === AppSourceType::GitWithNixpacks) {
if (! $this->source->nixpacks->volume) {
$this->source->nixpacks->volume = Volume::validateAndCreate([
'id' => ResourceId::make('volume'),
'name' => 'data',
'dockerName' => $this->makeResourceName($process, 'vol_ptah_nixpacks'),
'path' => '/ptah/nixpacks',
]);
}
}
}

public function getDockerImage(Process $process): string
{
return match ($this->source->type) {
AppSourceType::DockerImage => $this->source->docker->image,
AppSourceType::GitWithDockerfile => '127.0.0.1:5000/'.$this->dockerName.':'.$this->source->git->ref,
// AppSourceType::GitWithNixpacks => $this->source->nixpacks->dockerImage,
AppSourceType::GitWithDockerfile => '127.0.0.1:5000/'.$this->getDockerName($process).':'.$this->source->git->ref,
AppSourceType::GitWithNixpacks => '127.0.0.1:5000/'.$this->getDockerName($process).':'.$this->source->nixpacks->ref,
};
}

public function getBuildOrPullImageTasks(Deployment $deployment, Process $process): array
{
$labels = $process->resourceLabels($deployment);
// Something went wrong as we have to call ensureVolumes here
$this->ensureVolumes($process);

return match ($this->source->type) {
AppSourceType::DockerImage => $this->getPullImageTasks($deployment),
AppSourceType::GitWithDockerfile => $this->getBuildImageTasks($deployment, $process, $labels),
// AppSourceType::GitWithNixpacks => $this->getBuildImageFromNixpacksTask($deployment),
AppSourceType::DockerImage => $this->getPullImageTasks($deployment, $process),
AppSourceType::GitWithDockerfile => $this->getBuildImageWithDockerfileTasks($deployment, $process),
AppSourceType::GitWithNixpacks => $this->getBuildImageWithNixpacksTasks($deployment, $process),
};
}

protected function getPullRepoTask(Deployment $deployment, Process $process, array $labels): array
protected function getPullRepoTask(Deployment $deployment, Process $process, Volume $volume, string $repo, string $ref): array
{
$labels = $process->resourceLabels($deployment);

return [
'type' => NodeTaskType::PullGitRepo,
'meta' => PullGitRepoMeta::from([
'serviceId' => $deployment->service_id,
'deploymentId' => $deployment->id,
'process' => $process->name,
'worker' => $this->name,
'repo' => $this->source->git->repo,
'ref' => $this->source->git->ref,
'repo' => $repo,
'ref' => $ref,
]),
'payload' => [
'Repo' => $repo,
'Ref' => $ref,
'VolumeSpec' => $volume->asMount($labels),
'TargetDir' => "{$volume->path}/{$ref}",
],
];
}

protected function getBuildImageWithDockerfileTasks(Deployment $deployment, Process $process): array
{
$labels = $process->resourceLabels($deployment);

$tasks = [];

$tasks[] = $this->getPullRepoTask($deployment, $process, $this->source->git->volume, $this->source->git->repo, $this->source->git->ref);

$tasks[] = [
'type' => NodeTaskType::BuildImageWithDockerfile,
'meta' => BuildImageWithDockerfileMeta::from([
'dockerImage' => $this->getDockerImage($process),
'dockerfilePath' => $this->source->git->dockerfilePath,
]),
'payload' => [
'Repo' => $this->source->git->repo,
'Ref' => $this->source->git->ref,
'DockerImage' => $this->getDockerImage($process),
'WorkingDir' => "{$this->source->git->volume->path}/{$this->source->git->ref}",
'Dockerfile' => $this->source->git->dockerfilePath,
'VolumeSpec' => $this->source->git->volume->asMount($labels),
'TargetDir' => "/ptah/git/{$this->source->git->ref}",
],
];

$tasks = [
...$tasks,
...$this->getPullImageTasks($deployment, $process),
];

return $tasks;
}

protected function getBuildImageTasks(Deployment $deployment, Process $process, array $labels): array
protected function getBuildImageWithNixpacksTasks(Deployment $deployment, Process $process): array
{
return [
$this->getPullRepoTask($deployment, $process, $labels),
[
'type' => NodeTaskType::BuildImageWithDockerfile,
'meta' => BuildImageWithDockerfileMeta::from([
'dockerImage' => $this->getDockerImage(),
'dockerfilePath' => $this->source->git->dockerfilePath,
]),
'payload' => [
'DockerImage' => $this->getDockerImage(),
'WorkingDir' => "/ptah/git/{$this->source->git->ref}",
'Dockerfile' => $this->source->git->dockerfilePath,
'VolumeSpec' => $this->source->git->volume->asMount($labels),
],
$labels = $process->resourceLabels($deployment);

$tasks = [];

$tasks[] = $this->getPullRepoTask($deployment, $process, $this->source->nixpacks->volume, $this->source->nixpacks->repo, $this->source->nixpacks->ref);

$tasks[] = [
'type' => NodeTaskType::BuildImageWithNixpacks,
'meta' => BuildImageWithNixpacksMeta::from([
'dockerImage' => $this->getDockerImage($process),
'nixpacksFilePath' => $this->source->nixpacks->nixpacksFilePath,
]),
'payload' => [
'DockerImage' => $this->getDockerImage($process),
'WorkingDir' => "{$this->source->nixpacks->volume->path}/{$this->source->nixpacks->ref}",
'NixpacksFilePath' => $this->source->nixpacks->nixpacksFilePath,
'VolumeSpec' => $this->source->nixpacks->volume->asMount($labels),
],
// ...$this->getPullImageTasks($deployment),
];

$tasks = [
...$tasks,
...$this->getPullImageTasks($deployment, $process),
];

return $tasks;
}

// protected function getBuildImageFromNixpacksTasks(Deployment $deployment): array
// {
// return [
// $this->getPullRepoTask($deployment),
// [
// 'type' => NodeTaskType::BuildImageWithNixpacks,
// 'meta' => BuildImageWithNixpacksMeta::from([
// 'deploymentId' => $deployment->id,
// 'processName' => $this->dockerName,
// 'serviceId' => $deployment->service_id,
// 'serviceName' => $deployment->service->name,
// ]),
// ],
// ];
// }

protected function getPullImageTasks(Deployment $deployment): array
protected function getPullImageTasks(Deployment $deployment, Process $process): array
{
$dockerRegistry = $this->source->docker->registryId
$dockerRegistry = $this->source->docker?->registryId
? $deployment->service->swarm->data->findRegistry($this->source->docker->registryId)
: null;

if ($this->source->docker->registryId && is_null($dockerRegistry)) {
if ($this->source->docker?->registryId && is_null($dockerRegistry)) {
throw new Exception("Docker registry '{$this->source->docker->registryId}' not found");
}

Expand All @@ -339,14 +377,14 @@ protected function getPullImageTasks(Deployment $deployment): array
'type' => NodeTaskType::PullDockerImage,
'meta' => PullDockerImageMeta::from([
'deploymentId' => $deployment->id,
'processName' => $this->dockerName,
'processName' => $this->getDockerName($process),
'serviceId' => $deployment->service_id,
'serviceName' => $deployment->service->name,
'dockerImage' => $this->getDockerImage(),
'dockerImage' => $this->getDockerImage($process),
]),
'payload' => [
'AuthConfigName' => $authConfigName,
'Image' => $this->getDockerImage(),
'Image' => $this->getDockerImage($process),
'PullOptions' => (object) [],
],
];
Expand Down Expand Up @@ -393,7 +431,7 @@ private function getCommandAndArgs(): array
return [['sh'], ['-c', $this->command]];
}

private function getReleaseCommandPayload(Deployment $deployment, array $labels): array
private function getReleaseCommandPayload(Deployment $deployment, Process $process, array $labels): array
{
if (! $this->releaseCommand->command) {
return [
Expand All @@ -404,7 +442,7 @@ private function getReleaseCommandPayload(Deployment $deployment, array $labels)
}

// Always create a new config, as the command may be the same, but the image/entrypoint may be different.
$this->releaseCommand->dockerName = $this->makeResourceName('dpl_'.$deployment->id.'_rel_cmd');
$this->releaseCommand->dockerName = $this->makeResourceName($process, 'dpl_'.$deployment->id.'_rel_cmd');

return [
'ConfigName' => $this->releaseCommand->dockerName,
Expand Down Expand Up @@ -578,9 +616,9 @@ private function getBackupRestoreTask(Backup $backup, array $labels): array
];
}

private function makeResourceName(string $name): string
private function makeResourceName(Process $process, string $name): string
{
return dockerize_name($this->dockerName.'_'.$name);
return dockerize_name($this->getDockerName($process).'_'.$name);
}

public static function make(array $attributes): static
Expand Down
Loading

0 comments on commit 22867a4

Please sign in to comment.