feat: add initial support for custom docker run commands
This commit is contained in:
parent
9e09c449cf
commit
5c29ecdf10
@ -1128,6 +1128,9 @@ private function generate_compose_file()
|
|||||||
|
|
||||||
data_forget($docker_compose, 'services.' . $this->container_name);
|
data_forget($docker_compose, 'services.' . $this->container_name);
|
||||||
|
|
||||||
|
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
||||||
|
$docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose);
|
||||||
|
|
||||||
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
||||||
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
|
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
|
||||||
|
@ -61,11 +61,12 @@ class General extends Component
|
|||||||
'application.docker_compose_pr' => 'nullable',
|
'application.docker_compose_pr' => 'nullable',
|
||||||
'application.docker_compose_raw' => 'nullable',
|
'application.docker_compose_raw' => 'nullable',
|
||||||
'application.docker_compose_pr_raw' => 'nullable',
|
'application.docker_compose_pr_raw' => 'nullable',
|
||||||
'application.custom_labels' => 'nullable',
|
|
||||||
'application.dockerfile_target_build' => 'nullable',
|
'application.dockerfile_target_build' => 'nullable',
|
||||||
'application.settings.is_static' => 'boolean|required',
|
|
||||||
'application.docker_compose_custom_start_command' => 'nullable',
|
'application.docker_compose_custom_start_command' => 'nullable',
|
||||||
'application.docker_compose_custom_build_command' => 'nullable',
|
'application.docker_compose_custom_build_command' => 'nullable',
|
||||||
|
'application.custom_labels' => 'nullable',
|
||||||
|
'application.custom_docker_run_options' => 'nullable',
|
||||||
|
'application.settings.is_static' => 'boolean|required',
|
||||||
'application.settings.is_raw_compose_deployment_enabled' => 'boolean|required',
|
'application.settings.is_raw_compose_deployment_enabled' => 'boolean|required',
|
||||||
'application.settings.is_build_server_enabled' => 'boolean|required',
|
'application.settings.is_build_server_enabled' => 'boolean|required',
|
||||||
];
|
];
|
||||||
@ -97,9 +98,10 @@ class General extends Component
|
|||||||
'application.docker_compose_pr_raw' => 'Docker compose raw',
|
'application.docker_compose_pr_raw' => 'Docker compose raw',
|
||||||
'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.custom_docker_run_options' => 'Custom docker run commands',
|
||||||
'application.docker_compose_custom_start_command' => 'Docker compose custom start command',
|
'application.docker_compose_custom_start_command' => 'Docker compose custom start command',
|
||||||
'application.docker_compose_custom_build_command' => 'Docker compose custom build command',
|
'application.docker_compose_custom_build_command' => 'Docker compose custom build command',
|
||||||
|
'application.settings.is_static' => 'Is static',
|
||||||
'application.settings.is_raw_compose_deployment_enabled' => 'Is raw compose deployment enabled',
|
'application.settings.is_raw_compose_deployment_enabled' => 'Is raw compose deployment enabled',
|
||||||
'application.settings.is_build_server_enabled' => 'Is build server enabled',
|
'application.settings.is_build_server_enabled' => 'Is build server enabled',
|
||||||
];
|
];
|
||||||
@ -249,6 +251,9 @@ public function submit($showToaster = true)
|
|||||||
$this->application->fqdn = $domains->implode(',');
|
$this->application->fqdn = $domains->implode(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data_get($this->application, 'custom_docker_run_options')) {
|
||||||
|
$this->application->custom_docker_run_options = str($this->application->custom_docker_run_options)->trim();
|
||||||
|
}
|
||||||
if (data_get($this->application, 'dockerfile')) {
|
if (data_get($this->application, 'dockerfile')) {
|
||||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||||
if ($port && !$this->application->ports_exposes) {
|
if ($port && !$this->application->ports_exposes) {
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
|
||||||
use App\Models\ServiceApplication;
|
use App\Models\ServiceApplication;
|
||||||
use App\Models\ServiceDatabase;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
@ -323,3 +321,89 @@ function isDatabaseImage(?string $image = null)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convert_docker_run_to_compose(?string $custom_docker_run_options = null)
|
||||||
|
{
|
||||||
|
preg_match_all('/(--\w+(?:-\w+)*)(?:\s|=)?([^\s-]+)?/', $custom_docker_run_options, $matches, PREG_SET_ORDER);
|
||||||
|
$list_options = collect([
|
||||||
|
'--cap-add',
|
||||||
|
'--cap-drop',
|
||||||
|
'--security-opt',
|
||||||
|
'--sysctl',
|
||||||
|
'--ulimit',
|
||||||
|
'--device'
|
||||||
|
]);
|
||||||
|
$mapping = collect([
|
||||||
|
'--cap-add' => 'cap_add',
|
||||||
|
'--cap-drop' => 'cap_drop',
|
||||||
|
'--security-opt' => 'security_opt',
|
||||||
|
'--sysctl' => 'sysctls',
|
||||||
|
'--device' => 'devices',
|
||||||
|
'--ulimit' => 'ulimits',
|
||||||
|
'--init' => 'init',
|
||||||
|
'--ulimit' => 'ulimits',
|
||||||
|
'--privileged' => 'privileged',
|
||||||
|
]);
|
||||||
|
$options = [];
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
$option = $match[1];
|
||||||
|
$value = isset($match[2]) && $match[2] !== '' ? $match[2] : true;
|
||||||
|
if ($list_options->contains($option)) {
|
||||||
|
$value = explode(',', $value);
|
||||||
|
}
|
||||||
|
if (array_key_exists($option, $options)) {
|
||||||
|
if (is_array($options[$option])) {
|
||||||
|
$options[$option][] = $value;
|
||||||
|
} else {
|
||||||
|
$options[$option] = [$options[$option], $value];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$options[$option] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$options = collect($options);
|
||||||
|
$compose_options = collect([]);
|
||||||
|
// Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
|
||||||
|
foreach ($options as $option => $value) {
|
||||||
|
if (!data_get($mapping, $option)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($option === '--ulimit') {
|
||||||
|
$ulimits = collect([]);
|
||||||
|
collect($value)->map(function ($ulimit) use ($ulimits){
|
||||||
|
$ulimit = explode('=', $ulimit);
|
||||||
|
$type = $ulimit[0];
|
||||||
|
$limits = explode(':', $ulimit[1]);
|
||||||
|
if (count($limits) == 2) {
|
||||||
|
$soft_limit = $limits[0];
|
||||||
|
$hard_limit = $limits[1];
|
||||||
|
$ulimits->put($type, [
|
||||||
|
'soft' => $soft_limit,
|
||||||
|
'hard' => $hard_limit
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$soft_limit = $ulimit[1];
|
||||||
|
$ulimits->put($type, [
|
||||||
|
'soft' => $soft_limit,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$compose_options->put($mapping[$option], $ulimits);
|
||||||
|
} else {
|
||||||
|
if ($list_options->contains($option)) {
|
||||||
|
if ($compose_options->has($mapping[$option])) {
|
||||||
|
$compose_options->put($mapping[$option], $options->get($mapping[$option]) . ',' . $value);
|
||||||
|
} else {
|
||||||
|
$compose_options->put($mapping[$option], $value);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$compose_options->put($mapping[$option], $value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$compose_options->forget($option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $compose_options->toArray();
|
||||||
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?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('custom_docker_run_options')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('custom_docker_run_options');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -130,7 +130,6 @@ class="underline" href="https://coolify.io/docs/docker/registry"
|
|||||||
@endif
|
@endif
|
||||||
@if ($application->could_set_build_commands())
|
@if ($application->could_set_build_commands())
|
||||||
@if ($application->build_pack === 'nixpacks')
|
@if ($application->build_pack === 'nixpacks')
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 xl:flex-row">
|
<div class="flex flex-col gap-2 xl:flex-row">
|
||||||
<x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
|
<x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
|
||||||
id="application.install_command" label="Install Command" />
|
id="application.install_command" label="Install Command" />
|
||||||
@ -194,6 +193,13 @@ class="underline" href="https://coolify.io/docs/docker/registry"
|
|||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
<div>The following options are for advanced use cases. Only modify them if you
|
||||||
|
know what are
|
||||||
|
you doing.</div>
|
||||||
|
<x-forms.input
|
||||||
|
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='text-white underline' href='https://coolify.io/docs/'>docs.</a>"
|
||||||
|
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
|
||||||
|
id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
Loading…
Reference in New Issue
Block a user