Skip to content

Commit 3c3b390

Browse files
committed
feat: #261 remove unused images from the registry
1 parent 22867a4 commit 3c3b390

File tree

16 files changed

+272
-14
lines changed

16 files changed

+272
-14
lines changed

Diff for: app/Actions/HouseKeeping/PruneStaleDockerData.php

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace App\Actions\HouseKeeping;
4+
5+
use App\Models\NodeTaskGroup;
6+
use App\Models\NodeTaskGroupType;
7+
use App\Models\NodeTasks\PruneDockerRegistry\PruneDockerRegistryMeta;
8+
use App\Models\NodeTaskType;
9+
use App\Models\Scopes\TeamScope;
10+
use App\Models\Service;
11+
use Illuminate\Support\Str;
12+
13+
class PruneStaleDockerData
14+
{
15+
public function __invoke(): void
16+
{
17+
$imagesToKeep = [];
18+
19+
Service::withoutGlobalScope(TeamScope::class)->with(['latestDeployment'])->chunk(100, function (
20+
/* @var Service[] $services */
21+
$services
22+
) use (&$imagesToKeep) {
23+
foreach ($services as $service) {
24+
if (! isset($imagesToKeep[$service->swarm_id])) {
25+
$imagesToKeep[$service->swarm_id] = [
26+
'swarm_id' => $service->swarm_id,
27+
'team_id' => $service->team_id,
28+
'images' => [],
29+
];
30+
}
31+
32+
foreach ($service->latestDeployment->data->processes as $process) {
33+
foreach ($process->workers as $worker) {
34+
$image = $worker->getDockerImage($process);
35+
36+
if (Str::startsWith($image, 'registry.ptah.local:5050')) {
37+
$imagesToKeep[$service->swarm_id]['images'][] = $image;
38+
}
39+
}
40+
}
41+
}
42+
});
43+
44+
foreach ($imagesToKeep as $swarm) {
45+
if (count($swarm['images']) === 0) {
46+
continue;
47+
}
48+
49+
$taskGroup = NodeTaskGroup::create([
50+
'type' => NodeTaskGroupType::PruneDockerData,
51+
'swarm_id' => $swarm['swarm_id'],
52+
'team_id' => $swarm['team_id'],
53+
'invoker_id' => $swarm['team_id'],
54+
]);
55+
56+
$taskGroup->tasks()->create([
57+
'type' => NodeTaskType::PruneDockerRegistry,
58+
'meta' => PruneDockerRegistryMeta::from([]),
59+
'payload' => [
60+
'KeepImages' => $swarm['images'],
61+
],
62+
]);
63+
}
64+
}
65+
}

Diff for: app/Actions/Nodes/InitCluster.php

+17-8
Original file line numberDiff line numberDiff line change
@@ -313,19 +313,23 @@ private function getDockerRegistryProcessConfig(Node $node): array
313313
'startInterval' => 5,
314314
],
315315
'replicas' => 0,
316-
'command' => '/bin/registry garbage-collect /etc/docker/registry/config.yml',
316+
'command' => 'sh /ptah/prune_stale_data.sh',
317317
'launchMode' => LaunchMode::Cronjob->value,
318-
'crontab' => '0 * * * *',
318+
'crontab' => '30 0 * * *',
319319
],
320320
],
321-
'envVars' => [
321+
'envVars' => [],
322+
'secretVars' => [],
323+
'configFiles' => [
324+
[
325+
'path' => '/etc/docker/registry/config.yml',
326+
'content' => file_get_contents(resource_path('support/registry/config.yml')),
327+
],
322328
[
323-
'name' => 'REGISTRY_STORAGE_DELETE_ENABLED',
324-
'value' => 'true',
329+
'path' => '/ptah/prune_stale_data.sh',
330+
'content' => file_get_contents(resource_path('support/registry/prune_stale_data.sh')),
325331
],
326332
],
327-
'secretVars' => [],
328-
'configFiles' => [],
329333
'secretFiles' => [],
330334
'volumes' => [
331335
[
@@ -334,7 +338,12 @@ private function getDockerRegistryProcessConfig(Node $node): array
334338
'path' => '/var/lib/registry',
335339
],
336340
],
337-
'ports' => [],
341+
'ports' => [
342+
[
343+
'targetPort' => 5050,
344+
'publishedPort' => 5050,
345+
],
346+
],
338347
'caddy' => [],
339348
'fastcgiVars' => null,
340349
'redirectRules' => [],

Diff for: app/Console/Commands/PruneStaleDockerDataCommand.php

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Actions\HouseKeeping\PruneStaleDockerData;
6+
use Illuminate\Console\Command;
7+
8+
class PruneStaleDockerDataCommand extends Command
9+
{
10+
/**
11+
* The name and signature of the console command.
12+
*
13+
* @var string
14+
*/
15+
protected $signature = 'app:housekeeping:prune-stale-docker-data';
16+
17+
/**
18+
* The console command description.
19+
*
20+
* @var string
21+
*/
22+
protected $description = 'Prune stale docker data';
23+
24+
/**
25+
* Execute the console command.
26+
*/
27+
public function handle(PruneStaleDockerData $action): void
28+
{
29+
$action();
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace App\Events\NodeTasks\PruneDockerRegistry;
4+
5+
use App\Events\NodeTasks\BaseTaskEvent;
6+
7+
class PruneDockerRegistryCompleted extends BaseTaskEvent {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace App\Events\NodeTasks\PruneDockerRegistry;
4+
5+
use App\Events\NodeTasks\BaseTaskEvent;
6+
7+
class PruneDockerRegistryFailed extends BaseTaskEvent {}

Diff for: app/Jobs/PruneStaleDockerDataJob.php

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Jobs;
4+
5+
use App\Actions\HouseKeeping\PruneStaleDockerData;
6+
use Illuminate\Bus\Queueable;
7+
use Illuminate\Contracts\Queue\ShouldQueue;
8+
use Illuminate\Foundation\Bus\Dispatchable;
9+
use Illuminate\Queue\InteractsWithQueue;
10+
use Illuminate\Queue\SerializesModels;
11+
12+
class PruneStaleDockerDataJob implements ShouldQueue
13+
{
14+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
15+
16+
/**
17+
* Create a new job instance.
18+
*/
19+
public function __construct()
20+
{
21+
//
22+
}
23+
24+
/**
25+
* Execute the job.
26+
*/
27+
public function handle(PruneStaleDockerData $action): void
28+
{
29+
$action();
30+
}
31+
}

Diff for: app/Models/DeploymentData/Worker.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,12 @@ private function ensureVolumes(Process $process): void
255255

256256
public function getDockerImage(Process $process): string
257257
{
258+
$registry = 'registry.ptah.local:5050';
259+
258260
return match ($this->source->type) {
259261
AppSourceType::DockerImage => $this->source->docker->image,
260-
AppSourceType::GitWithDockerfile => '127.0.0.1:5000/'.$this->getDockerName($process).':'.$this->source->git->ref,
261-
AppSourceType::GitWithNixpacks => '127.0.0.1:5000/'.$this->getDockerName($process).':'.$this->source->nixpacks->ref,
262+
AppSourceType::GitWithDockerfile => $registry.'/'.$this->getDockerName($process).':'.$this->source->git->ref,
263+
AppSourceType::GitWithNixpacks => $registry.'/'.$this->getDockerName($process).':'.$this->source->nixpacks->ref,
262264
};
263265
}
264266

Diff for: app/Models/NodeTaskGroupType.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ enum NodeTaskGroupType: int
1414
case SelfUpgrade = 4;
1515
case UpdateDockerRegistries = 5;
1616
case UpdateS3Storages = 6;
17-
case __Unused__Safe_To_Re_Use__ = 7;
17+
case PruneDockerData = 7;
1818
case JoinSwarm = 8;
1919
case UpdateDirdConfig = 9;
2020
case LaunchService = 10;

Diff for: app/Models/NodeTaskType.php

+9
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
use App\Events\NodeTasks\JoinSwarm\JoinSwarmFailed;
3737
use App\Events\NodeTasks\LaunchService\LaunchServiceCompleted;
3838
use App\Events\NodeTasks\LaunchService\LaunchServiceFailed;
39+
use App\Events\NodeTasks\PruneDockerRegistry\PruneDockerRegistryCompleted;
40+
use App\Events\NodeTasks\PruneDockerRegistry\PruneDockerRegistryFailed;
3941
use App\Events\NodeTasks\PullDockerImage\PullDockerImageCompleted;
4042
use App\Events\NodeTasks\PullDockerImage\PullDockerImageFailed;
4143
use App\Events\NodeTasks\PullGitRepo\PullGitRepoCompleted;
@@ -92,6 +94,8 @@
9294
use App\Models\NodeTasks\JoinSwarm\JoinSwarmResult;
9395
use App\Models\NodeTasks\LaunchService\LaunchServiceMeta;
9496
use App\Models\NodeTasks\LaunchService\LaunchServiceResult;
97+
use App\Models\NodeTasks\PruneDockerRegistry\PruneDockerRegistryMeta;
98+
use App\Models\NodeTasks\PruneDockerRegistry\PruneDockerRegistryResult;
9599
use App\Models\NodeTasks\PullDockerImage\PullDockerImageMeta;
96100
use App\Models\NodeTasks\PullDockerImage\PullDockerImageResult;
97101
use App\Models\NodeTasks\PullGitRepo\PullGitRepoMeta;
@@ -141,6 +145,7 @@ enum NodeTaskType: int
141145
case PullGitRepo = 24;
142146
case BuildImageWithDockerfile = 25;
143147
case BuildImageWithNixpacks = 26;
148+
case PruneDockerRegistry = 27;
144149

145150
public function meta(): string
146151
{
@@ -172,6 +177,7 @@ public function meta(): string
172177
self::PullGitRepo => PullGitRepoMeta::class,
173178
self::BuildImageWithDockerfile => BuildImageWithDockerfileMeta::class,
174179
self::BuildImageWithNixpacks => BuildImageWithNixpacksMeta::class,
180+
self::PruneDockerRegistry => PruneDockerRegistryMeta::class,
175181
};
176182
}
177183

@@ -205,6 +211,7 @@ public function result(): string
205211
self::PullGitRepo => PullGitRepoResult::class,
206212
self::BuildImageWithDockerfile => BuildImageWithDockerfileResult::class,
207213
self::BuildImageWithNixpacks => BuildImageWithNixpacksResult::class,
214+
self::PruneDockerRegistry => PruneDockerRegistryResult::class,
208215
};
209216
}
210217

@@ -238,6 +245,7 @@ public function completed(): string
238245
self::PullGitRepo => PullGitRepoCompleted::class,
239246
self::BuildImageWithDockerfile => BuildImageWithDockerfileCompleted::class,
240247
self::BuildImageWithNixpacks => BuildImageWithNixpacksCompleted::class,
248+
self::PruneDockerRegistry => PruneDockerRegistryCompleted::class,
241249
};
242250
}
243251

@@ -271,6 +279,7 @@ public function failed(): string
271279
self::PullGitRepo => PullGitRepoFailed::class,
272280
self::BuildImageWithDockerfile => BuildImageWithDockerfileFailed::class,
273281
self::BuildImageWithNixpacks => BuildImageWithNixpacksFailed::class,
282+
self::PruneDockerRegistry => PruneDockerRegistryFailed::class,
274283
};
275284
}
276285
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\Models\NodeTasks\PruneDockerRegistry;
4+
5+
use App\Models\NodeTasks\AbstractTaskMeta;
6+
7+
class PruneDockerRegistryMeta extends AbstractTaskMeta
8+
{
9+
public function __construct(
10+
) {
11+
//
12+
}
13+
14+
public function formattedHtml(): string
15+
{
16+
return 'Prune Docker Registry';
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\Models\NodeTasks\PruneDockerRegistry;
4+
5+
use App\Models\NodeTasks\AbstractTaskResult;
6+
7+
class PruneDockerRegistryResult extends AbstractTaskResult
8+
{
9+
public function __construct(
10+
) {
11+
//
12+
}
13+
14+
public function formattedHtml(): string
15+
{
16+
return 'PruneDockerRegistry - Task Result';
17+
}
18+
}

Diff for: bootstrap/app.php

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use App\Http\Middleware\AdminAccess;
77
use App\Http\Middleware\HandleInertiaRequests;
88
use App\Jobs\CheckAgentUpdates;
9+
use App\Jobs\PruneStaleDockerDataJob;
910
use App\Models\Scopes\TeamScope;
1011
use App\Models\Service;
1112
use Illuminate\Console\Scheduling\Schedule;
@@ -72,13 +73,20 @@
7273
->onOneServer()
7374
->withoutOverlapping();
7475

76+
$schedule->job(PruneStaleDockerDataJob::class)
77+
->daily()
78+
->onOneServer()
79+
->withoutOverlapping();
80+
7581
Service::withoutGlobalScope(TeamScope::class)->with(['latestDeployment'])->chunk(100, function (
7682
/* @var Service[] $services */
7783
$services
7884
) use ($schedule) {
7985
foreach ($services as $service) {
8086
foreach ($service->latestDeployment->data->processes as $process) {
8187
foreach ($process->workers as $worker) {
88+
$imagesToKeep[] = $worker->getDockerImage($process);
89+
8290
if (! $worker->crontab) {
8391
continue;
8492
}

Diff for: config/billing.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
'quotas' => [
4444
'nodes' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
4545
'swarms' => ['limit' => 1, 'soft' => false, 'reset_period' => null],
46-
'services' => ['limit' => 30, 'soft' => false, 'reset_period' => null],
46+
'services' => ['limit' => 3, 'soft' => false, 'reset_period' => null],
4747
'deployments' => ['limit' => 20, 'soft' => false, 'reset_period' => 'daily'],
4848
],
4949
],

Diff for: resources/support/registry/config.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
version: 0.1
2+
log:
3+
fields:
4+
service: registry
5+
storage:
6+
cache:
7+
blobdescriptor: inmemory
8+
filesystem:
9+
rootdirectory: /var/lib/registry
10+
delete:
11+
enabled: true
12+
maintenance:
13+
uploadpurging:
14+
enabled: true
15+
age: 168h
16+
interval: 24h
17+
dryrun: false
18+
http:
19+
addr: 0.0.0.0:5050
20+
host: http://registry.ptah.local:5050
21+
net: tcp
22+
headers:
23+
X-Content-Type-Options: [nosniff]
24+
health:
25+
storagedriver:
26+
enabled: true
27+
interval: 10s
28+
threshold: 3

0 commit comments

Comments
 (0)