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,37 +126,57 @@
</div> </div>
@endif @endif
@endif @endif
<div class="flex flex-col gap-2 xl:flex-row"> @if ($application->build_pack === 'dockercompose')
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory" <div class="flex flex-col gap-2" wire:init='loadComposeFile(true)'>
helper="Directory to use as root. Useful for monorepos." /> <div class="flex gap-2">
@if ($application->build_pack === 'dockerfile' && !$application->dockerfile) <x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
<x-forms.input placeholder="/Dockerfile" id="application.dockerfile_location" helper="Directory to use as root. Useful for monorepos." />
label="Dockerfile Location" <x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_location"
helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>" /> label="Docker Compose Location"
@endif helper="It is calculated together with the Base Directory:<br><span class='text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
@if ($application->build_pack === 'dockercompose') </div>
<span wire:init='loadComposeFile(true)'></span> <div class="pt-4">The following commands are for advanced use cases. Only modify them if you know what are
<x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_location" you doing.</div>
label="Docker Compose Location" <div class="flex gap-2">
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 build"
{{-- <x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_pr_location" id="application.docker_compose_custom_build_command"
label="Docker Compose Location For Pull Requests" 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>"
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>" /> --}} label="Custom Build Command" />
@endif <x-forms.input placeholder="docker compose up -d"
@if ($application->build_pack === 'dockerfile') id="application.docker_compose_custom_start_command"
<x-forms.input id="application.dockerfile_target_build" label="Docker Build Stage Target" 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>"
helper="Useful if you have multi-staged dockerfile." /> label="Custom Start Command" />
@endif {{-- <x-forms.input placeholder="/docker-compose.yaml" id="application.docker_compose_pr_location"
@if ($application->could_set_build_commands()) label="Docker Compose Location For Pull Requests"
@if ($application->settings->is_static) 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>" /> --}}
<x-forms.input placeholder="/dist" id="application.publish_directory" </div>
label="Publish Directory" required /> </div>
@else @else
<x-forms.input placeholder="/" id="application.publish_directory" <div class="flex flex-col gap-2 xl:flex-row">
label="Publish Directory" /> <x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." />
@if ($application->build_pack === 'dockerfile' && !$application->dockerfile)
<x-forms.input placeholder="/Dockerfile" id="application.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>" />
@endif @endif
@endif
</div> @if ($application->build_pack === 'dockerfile')
<x-forms.input id="application.dockerfile_target_build" label="Docker Build Stage Target"
helper="Useful if you have multi-staged dockerfile." />
@endif
@if ($application->could_set_build_commands())
@if ($application->settings->is_static)
<x-forms.input placeholder="/dist" id="application.publish_directory"
label="Publish Directory" required />
@else
<x-forms.input placeholder="/" id="application.publish_directory"
label="Publish Directory" />
@endif
@endif
</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>