feat: custom docker compose commands

This commit is contained in:
Andras Bacsai 2023-12-17 20:56:12 +01:00
parent c6b8eabe10
commit 27c36bec83
4 changed files with 123 additions and 42 deletions

View File

@ -75,6 +75,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private $docker_compose_base64; private $docker_compose_base64;
private string $dockerfile_location = '/Dockerfile'; private string $dockerfile_location = '/Dockerfile';
private string $docker_compose_location = '/docker-compose.yml'; private string $docker_compose_location = '/docker-compose.yml';
private ?string $docker_compose_custom_start_command = null;
private ?string $docker_compose_custom_build_command = null;
private ?string $addHosts = null; private ?string $addHosts = null;
private ?string $buildTarget = null; private ?string $buildTarget = null;
private Collection $saved_outputs; private Collection $saved_outputs;
@ -432,6 +434,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
if (data_get($this->application, 'docker_compose_location')) { if (data_get($this->application, 'docker_compose_location')) {
$this->docker_compose_location = $this->application->docker_compose_location; $this->docker_compose_location = $this->application->docker_compose_location;
} }
if (data_get($this->application, 'docker_compose_custom_start_command')) {
$this->docker_compose_custom_start_command = $this->application->docker_compose_custom_start_command;
}
if (data_get($this->application, 'docker_compose_custom_build_command')) {
$this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command;
}
if ($this->pull_request_id === 0) { if ($this->pull_request_id === 0) {
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}."); $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}.");
} else { } else {
@ -454,7 +462,18 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
]); ]);
$this->save_environment_variables(); $this->save_environment_variables();
// Build new container to limit downtime. // Build new container to limit downtime.
$this->build_by_compose_file(); $this->application_deployment_queue->addLogEntry("Pulling & building required images.");
if ($this->docker_compose_custom_build_command) {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_build_command}"), "hidden" => true],
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
);
}
$this->stop_running_container(force: true); $this->stop_running_container(force: true);
$networkId = $this->application->uuid; $networkId = $this->application->uuid;
@ -488,7 +507,17 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
] ]
); );
} }
$this->start_by_compose_file(); // Start compose file
if ($this->docker_compose_custom_start_command) {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), "hidden" => true],
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
);
}
$this->application_deployment_queue->addLogEntry("New container started.");
} }
private function deploy_dockerfile_buildpack() private function deploy_dockerfile_buildpack()
{ {
@ -1258,15 +1287,9 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true],
); );
} else { } else {
if ($this->docker_compose_location) {
$this->execute_remote_command( $this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
); );
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true],
);
}
} }
$this->application_deployment_queue->addLogEntry("New images built."); $this->application_deployment_queue->addLogEntry("New images built.");
} }

View File

@ -64,6 +64,8 @@ class General extends Component
'application.custom_labels' => 'nullable', 'application.custom_labels' => 'nullable',
'application.dockerfile_target_build' => 'nullable', 'application.dockerfile_target_build' => 'nullable',
'application.settings.is_static' => 'boolean|required', 'application.settings.is_static' => 'boolean|required',
'application.docker_compose_custom_start_command' => 'nullable',
'application.docker_compose_custom_build_command' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
'application.name' => 'name', 'application.name' => 'name',
@ -94,6 +96,8 @@ class General extends Component
'application.custom_labels' => 'Custom labels', 'application.custom_labels' => 'Custom labels',
'application.dockerfile_target_build' => 'Dockerfile target build', 'application.dockerfile_target_build' => 'Dockerfile target build',
'application.settings.is_static' => 'Is static', 'application.settings.is_static' => 'Is static',
'application.docker_compose_custom_start_command' => 'Docker compose custom start command',
'application.docker_compose_custom_build_command' => 'Docker compose custom build command',
]; ];
public function mount() public function mount()
{ {
@ -195,7 +199,8 @@ class General extends Component
public function submit($showToaster = true) public function submit($showToaster = true)
{ {
try { try {
if ($this->application->build_pack === 'dockercompose' && ($this->initialDockerComposeLocation !== $this->application->docker_compose_location || $this->initialDockerComposePrLocation !== $this->application->docker_compose_pr_location)) { ray($this->initialDockerComposeLocation, $this->application->docker_compose_location);
if ($this->application->build_pack === 'dockercompose' && $this->initialDockerComposeLocation !== $this->application->docker_compose_location) {
$this->loadComposeFile(); $this->loadComposeFile();
} }
$this->validate(); $this->validate();

View File

@ -0,0 +1,33 @@
<?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('applications', function (Blueprint $table) {
$table->string('docker_compose_custom_start_command')->nullable();
$table->string('docker_compose_custom_build_command')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('docker_compose_custom_start_command');
$table->dropColumn('docker_compose_custom_build_command');
});
}
};

View File

@ -126,6 +126,32 @@
</div> </div>
@endif @endif
@endif @endif
@if ($application->build_pack === 'dockercompose')
<div class="flex flex-col gap-2" wire:init='loadComposeFile(true)'>
<div class="flex gap-2">
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." />
<x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_location"
label="Docker Compose Location"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
</div>
<div class="pt-4">The following commands are for advanced use cases. Only modify them if you know what are
you doing.</div>
<div class="flex gap-2">
<x-forms.input placeholder="docker compose build"
id="application.docker_compose_custom_build_command"
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} build</span>"
label="Custom Build Command" />
<x-forms.input placeholder="docker compose up -d"
id="application.docker_compose_custom_start_command"
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} up -d</span>"
label="Custom Start Command" />
{{-- <x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_pr_location"
label="Docker Compose Location For Pull Requests"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_pr_location, '/') }}</span>" /> --}}
</div>
</div>
@else
<div class="flex flex-col gap-2 xl:flex-row"> <div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory" <x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." /> helper="Directory to use as root. Useful for monorepos." />
@ -134,15 +160,7 @@
label="Dockerfile Location" label="Dockerfile Location"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>" /> helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>" />
@endif @endif
@if ($application->build_pack === 'dockercompose')
<span wire:init='loadComposeFile(true)'></span>
<x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_location"
label="Docker Compose Location"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
{{-- <x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_pr_location"
label="Docker Compose Location For Pull Requests"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_pr_location, '/') }}</span>" /> --}}
@endif
@if ($application->build_pack === 'dockerfile') @if ($application->build_pack === 'dockerfile')
<x-forms.input id="application.dockerfile_target_build" label="Docker Build Stage Target" <x-forms.input id="application.dockerfile_target_build" label="Docker Build Stage Target"
helper="Useful if you have multi-staged dockerfile." /> helper="Useful if you have multi-staged dockerfile." />
@ -158,6 +176,8 @@
@endif @endif
</div> </div>
@endif @endif
@endif
@if ($application->build_pack === 'dockercompose') @if ($application->build_pack === 'dockercompose')
<x-forms.button wire:click="loadComposeFile">Reload Compose File</x-forms.button> <x-forms.button wire:click="loadComposeFile">Reload Compose File</x-forms.button>
<x-forms.textarea rows="10" readonly id="application.docker_compose" <x-forms.textarea rows="10" readonly id="application.docker_compose"