fix(deployment): improve docker-compose domain handling and environment variable generation
This commit is contained in:
@@ -471,7 +471,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
$composeFile = $this->application->parse(pull_request_id: $this->pull_request_id, preview_id: data_get($this->preview, 'id'));
|
$composeFile = $this->application->parse(pull_request_id: $this->pull_request_id, preview_id: data_get($this->preview, 'id'));
|
||||||
$this->save_environment_variables();
|
$this->save_environment_variables();
|
||||||
if (! is_null($this->env_filename)) {
|
if (filled($this->env_filename)) {
|
||||||
$services = collect(data_get($composeFile, 'services', []));
|
$services = collect(data_get($composeFile, 'services', []));
|
||||||
$services = $services->map(function ($service, $name) {
|
$services = $services->map(function ($service, $name) {
|
||||||
$service['env_file'] = [$this->env_filename];
|
$service['env_file'] = [$this->env_filename];
|
||||||
@@ -480,7 +480,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
});
|
});
|
||||||
$composeFile['services'] = $services->toArray();
|
$composeFile['services'] = $services->toArray();
|
||||||
}
|
}
|
||||||
if (is_null($composeFile)) {
|
if (empty($composeFile)) {
|
||||||
$this->application_deployment_queue->addLogEntry('Failed to parse docker-compose file.');
|
$this->application_deployment_queue->addLogEntry('Failed to parse docker-compose file.');
|
||||||
$this->fail('Failed to parse docker-compose file.');
|
$this->fail('Failed to parse docker-compose file.');
|
||||||
|
|
||||||
@@ -887,10 +887,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
private function save_environment_variables()
|
private function save_environment_variables()
|
||||||
{
|
{
|
||||||
$envs = collect([]);
|
$envs = collect([]);
|
||||||
$local_branch = $this->branch;
|
|
||||||
if ($this->pull_request_id !== 0) {
|
|
||||||
$local_branch = "pull/{$this->pull_request_id}/head";
|
|
||||||
}
|
|
||||||
$sort = $this->application->settings->is_env_sorting_enabled;
|
$sort = $this->application->settings->is_env_sorting_enabled;
|
||||||
if ($sort) {
|
if ($sort) {
|
||||||
$sorted_environment_variables = $this->application->environment_variables->sortBy('key');
|
$sorted_environment_variables = $this->application->environment_variables->sortBy('key');
|
||||||
@@ -899,6 +895,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$sorted_environment_variables = $this->application->environment_variables->sortBy('id');
|
$sorted_environment_variables = $this->application->environment_variables->sortBy('id');
|
||||||
$sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('id');
|
$sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('id');
|
||||||
}
|
}
|
||||||
|
if ($this->build_pack === 'dockercompose') {
|
||||||
|
$sorted_environment_variables = $sorted_environment_variables->filter(function ($env) {
|
||||||
|
return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_');
|
||||||
|
});
|
||||||
|
$sorted_environment_variables_preview = $sorted_environment_variables_preview->filter(function ($env) {
|
||||||
|
return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_');
|
||||||
|
});
|
||||||
|
}
|
||||||
$ports = $this->application->main_port();
|
$ports = $this->application->main_port();
|
||||||
$coolify_envs = $this->generate_coolify_env_variables();
|
$coolify_envs = $this->generate_coolify_env_variables();
|
||||||
$coolify_envs->each(function ($item, $key) use ($envs) {
|
$coolify_envs->each(function ($item, $key) use ($envs) {
|
||||||
@@ -920,6 +924,22 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
|
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
|
||||||
$envs->push('HOST=0.0.0.0');
|
$envs->push('HOST=0.0.0.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->build_pack === 'dockercompose') {
|
||||||
|
$domains = collect(json_decode($this->application->docker_compose_domains)) ?? collect([]);
|
||||||
|
|
||||||
|
// Generate SERVICE_FQDN & SERVICE_URL for dockercompose
|
||||||
|
foreach ($domains as $forServiceName => $domain) {
|
||||||
|
$parsedDomain = data_get($domain, 'domain');
|
||||||
|
if (filled($parsedDomain)) {
|
||||||
|
$parsedDomain = str($parsedDomain)->explode(',')->first();
|
||||||
|
$coolifyUrl = str($parsedDomain)->after('://')->before(':')->prepend(str($parsedDomain)->before('://')->append('://'));
|
||||||
|
$coolifyFqdn = str($parsedDomain)->replace('http://', '')->replace('https://', '')->before(':');
|
||||||
|
$envs->push('SERVICE_URL_'.str($forServiceName)->upper().'='.$coolifyUrl->value());
|
||||||
|
$envs->push('SERVICE_FQDN_'.str($forServiceName)->upper().'='.$coolifyFqdn->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->env_filename = ".env-pr-$this->pull_request_id";
|
$this->env_filename = ".env-pr-$this->pull_request_id";
|
||||||
foreach ($sorted_environment_variables_preview as $env) {
|
foreach ($sorted_environment_variables_preview as $env) {
|
||||||
@@ -936,6 +956,21 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$envs->push('HOST=0.0.0.0');
|
$envs->push('HOST=0.0.0.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->build_pack === 'dockercompose') {
|
||||||
|
$domains = collect(json_decode(data_get($this->preview, 'docker_compose_domains'))) ?? collect([]);
|
||||||
|
|
||||||
|
// Generate SERVICE_FQDN & SERVICE_URL for dockercompose
|
||||||
|
foreach ($domains as $forServiceName => $domain) {
|
||||||
|
$parsedDomain = data_get($domain, 'domain');
|
||||||
|
if (filled($parsedDomain)) {
|
||||||
|
$parsedDomain = str($parsedDomain)->explode(',')->first();
|
||||||
|
$coolifyUrl = str($parsedDomain)->after('://')->before(':')->prepend(str($parsedDomain)->before('://')->append('://'));
|
||||||
|
$coolifyFqdn = str($parsedDomain)->replace('http://', '')->replace('https://', '')->before(':');
|
||||||
|
$envs->push('SERVICE_URL_'.str($forServiceName)->upper().'='.$coolifyUrl->value());
|
||||||
|
$envs->push('SERVICE_FQDN_'.str($forServiceName)->upper().'='.$coolifyFqdn->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($envs->isEmpty()) {
|
if ($envs->isEmpty()) {
|
||||||
$this->env_filename = null;
|
$this->env_filename = null;
|
||||||
@@ -1702,10 +1737,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
$this->create_workdir();
|
$this->create_workdir();
|
||||||
$ports = $this->application->main_port();
|
$ports = $this->application->main_port();
|
||||||
$onlyPort = null;
|
|
||||||
if (count($ports) > 0) {
|
|
||||||
$onlyPort = $ports[0];
|
|
||||||
}
|
|
||||||
$persistent_storages = $this->generate_local_persistent_volumes();
|
$persistent_storages = $this->generate_local_persistent_volumes();
|
||||||
$persistent_file_volumes = $this->application->fileStorages()->get();
|
$persistent_file_volumes = $this->application->fileStorages()->get();
|
||||||
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
|
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
|
||||||
@@ -2240,9 +2271,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
|
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function graceful_shutdown_container(string $containerName, int $timeout = 30)
|
private function graceful_shutdown_container(string $containerName)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$timeout = isDev() ? 1 : 30;
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true],
|
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true],
|
||||||
["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
|
["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||||
|
@@ -52,24 +52,38 @@ class ApplicationPreview extends BaseModel
|
|||||||
|
|
||||||
public function generate_preview_fqdn_compose()
|
public function generate_preview_fqdn_compose()
|
||||||
{
|
{
|
||||||
$domains = collect(json_decode($this->application->docker_compose_domains)) ?? collect();
|
$services = collect(json_decode($this->application->docker_compose_domains)) ?? collect();
|
||||||
foreach ($domains as $service_name => $domain) {
|
$docker_compose_domains = data_get($this, 'docker_compose_domains');
|
||||||
$domain = data_get($domain, 'domain');
|
$docker_compose_domains = json_decode($docker_compose_domains, true) ?? [];
|
||||||
$url = Url::fromString($domain);
|
|
||||||
$template = $this->application->preview_url_template;
|
foreach ($services as $service_name => $service_config) {
|
||||||
$host = $url->getHost();
|
$domain_string = data_get($service_config, 'domain');
|
||||||
$schema = $url->getScheme();
|
$service_domains = str($domain_string)->explode(',')->map(fn ($d) => trim($d));
|
||||||
$random = new Cuid2;
|
|
||||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
$preview_domains = [];
|
||||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
foreach ($service_domains as $domain) {
|
||||||
$preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
|
if (empty($domain)) {
|
||||||
$preview_fqdn = "$schema://$preview_fqdn";
|
continue;
|
||||||
$docker_compose_domains = data_get($this, 'docker_compose_domains');
|
}
|
||||||
$docker_compose_domains = json_decode($docker_compose_domains, true);
|
|
||||||
$docker_compose_domains[$service_name]['domain'] = $preview_fqdn;
|
$url = Url::fromString($domain);
|
||||||
$docker_compose_domains = json_encode($docker_compose_domains);
|
$template = $this->application->preview_url_template;
|
||||||
$this->docker_compose_domains = $docker_compose_domains;
|
$host = $url->getHost();
|
||||||
$this->save();
|
$schema = $url->getScheme();
|
||||||
|
$random = new Cuid2;
|
||||||
|
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||||
|
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||||
|
$preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
|
||||||
|
$preview_fqdn = "$schema://$preview_fqdn";
|
||||||
|
$preview_domains[] = $preview_fqdn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! empty($preview_domains)) {
|
||||||
|
$docker_compose_domains[$service_name]['domain'] = implode(',', $preview_domains);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->docker_compose_domains = json_encode($docker_compose_domains);
|
||||||
|
$this->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3147,6 +3147,9 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($command->value() === 'FQDN') {
|
if ($command->value() === 'FQDN') {
|
||||||
|
if ($isApplication && $resource->build_pack === 'dockercompose') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
|
$fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
|
||||||
if (str($fqdnFor)->contains('_')) {
|
if (str($fqdnFor)->contains('_')) {
|
||||||
$fqdnFor = str($fqdnFor)->before('_');
|
$fqdnFor = str($fqdnFor)->before('_');
|
||||||
@@ -3162,6 +3165,9 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
} elseif ($command->value() === 'URL') {
|
} elseif ($command->value() === 'URL') {
|
||||||
|
if ($isApplication && $resource->build_pack === 'dockercompose') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$fqdnFor = $key->after('SERVICE_URL_')->lower()->value();
|
$fqdnFor = $key->after('SERVICE_URL_')->lower()->value();
|
||||||
if (str($fqdnFor)->contains('_')) {
|
if (str($fqdnFor)->contains('_')) {
|
||||||
$fqdnFor = str($fqdnFor)->before('_');
|
$fqdnFor = str($fqdnFor)->before('_');
|
||||||
@@ -3651,9 +3657,28 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($isApplication) {
|
if ($isApplication) {
|
||||||
$domains = collect(json_decode($resource->docker_compose_domains)) ?? collect([]);
|
if ($isPullRequest) {
|
||||||
|
$preview = $resource->previews()->find($preview_id);
|
||||||
|
$domains = collect(json_decode(data_get($preview, 'docker_compose_domains'))) ?? collect([]);
|
||||||
|
} else {
|
||||||
|
$domains = collect(json_decode($resource->docker_compose_domains)) ?? collect([]);
|
||||||
|
}
|
||||||
$fqdns = data_get($domains, "$serviceName.domain");
|
$fqdns = data_get($domains, "$serviceName.domain");
|
||||||
if ($fqdns) {
|
// Generate SERVICE_FQDN & SERVICE_URL for dockercompose
|
||||||
|
if ($resource->build_pack === 'dockercompose') {
|
||||||
|
foreach ($domains as $forServiceName => $domain) {
|
||||||
|
$parsedDomain = data_get($domain, 'domain');
|
||||||
|
if (filled($parsedDomain)) {
|
||||||
|
$parsedDomain = str($parsedDomain)->explode(',')->first();
|
||||||
|
$coolifyUrl = str($parsedDomain)->after('://')->before(':')->prepend(str($parsedDomain)->before('://')->append('://'));
|
||||||
|
$coolifyFqdn = str($parsedDomain)->replace('http://', '')->replace('https://', '')->before(':');
|
||||||
|
$coolifyEnvironments->put('SERVICE_URL_'.str($forServiceName)->upper(), $coolifyUrl->value());
|
||||||
|
$coolifyEnvironments->put('SERVICE_FQDN_'.str($forServiceName)->upper(), $coolifyFqdn->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the domain is set, we need to generate the FQDNs for the preview
|
||||||
|
if (filled($fqdns)) {
|
||||||
$fqdns = str($fqdns)->explode(',');
|
$fqdns = str($fqdns)->explode(',');
|
||||||
if ($isPullRequest) {
|
if ($isPullRequest) {
|
||||||
$preview = $resource->previews()->find($preview_id);
|
$preview = $resource->previews()->find($preview_id);
|
||||||
@@ -3685,7 +3710,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$defaultLabels = defaultLabels(
|
$defaultLabels = defaultLabels(
|
||||||
id: $resource->id,
|
id: $resource->id,
|
||||||
name: $containerName,
|
name: $containerName,
|
||||||
@@ -3695,6 +3719,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
type: 'application',
|
type: 'application',
|
||||||
environment: $resource->environment->name,
|
environment: $resource->environment->name,
|
||||||
);
|
);
|
||||||
|
|
||||||
} elseif ($isService) {
|
} elseif ($isService) {
|
||||||
if ($savedService->serviceType()) {
|
if ($savedService->serviceType()) {
|
||||||
$fqdns = generateServiceSpecificFqdns($savedService);
|
$fqdns = generateServiceSpecificFqdns($savedService);
|
||||||
|
Reference in New Issue
Block a user