fix(deploy): keep short-lived containers out of build --add-host

BuildKit keys every RUN step on the --add-host names, so a container
that joins or leaves the network between two builds rebuilt all layers.
Leave out database backup and S3 import helpers, Sentinel, and the
proxy error page container.

Closes #12452

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-05 11:31:49 +01:00
co-authored by Claude Opus 5.5
parent 05e52fc41d
commit 6ab538d0f1
3 changed files with 37 additions and 4 deletions
+2
View File
@@ -45,6 +45,8 @@
- MCP tools that call REST routes remove response keys from `BuildsResponse::$sensitiveKeys` (for example `content`, `client_id`, `logs`) when the token has no `read:sensitive`, and `CallsRestApi::$blockedRestPaths` blocks some routes. Check both lists when you name the fields of a new API response or add an MCP tool for a route.
- To prove BuildKit cache behavior, use a new Dockerfile with a unique step for each experiment and repeat each build. Old cache records can make a changed input look cached. BuildKit keys `RUN` steps on the `--add-host` names and their order, but not on the IPs.
## Verify the complete user flow
- Do not use a passing unit test, a successful build, or a healthy process as proof for a reported UI failure.
- Verify the exact live flow, persisted state, relevant logs, and queue state when they affect the result.
+15 -4
View File
@@ -68,6 +68,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
*/
private const HELPER_DOCKER_CONFIG = '/root/.docker';
/**
* Name prefixes of the helpers that DatabaseBackupJob (S3 upload) and StartDatabaseImport
* (S3 download) run on a resource network for the duration of one backup or import.
*/
private const TEMPORARY_HELPER_CONTAINER_PREFIXES = ['backup-of-', 's3-restore-'];
/**
* System CA bundles of the supported server distributions, in the order that Go checks them.
*
@@ -363,9 +369,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
/**
* Build the --add-host flags for the containers on the destination network.
*
* Build helper containers are named after their deployment uuid and only live for the
* duration of that deployment. BuildKit keys every RUN layer on the --add-host set,
* so letting one in gives the next build a different set and forces a full rebuild.
* BuildKit keys every RUN layer on the host names of the --add-host set (not on the IPs), so a
* container that joins or leaves the network between two builds forces a full rebuild. The set
* leaves out the short-lived containers: build helpers (named after their deployment uuid),
* rolling update containers, and the backup and S3 import helpers. It also leaves out the proxy,
* Sentinel, and the proxy error page containers: no build uses them, and Coolify recreates them.
*/
private function addHostFlags(Collection $containers): string
{
@@ -377,7 +385,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$ips = collect([]);
foreach ($containers as $container) {
$containerName = data_get($container, 'Name');
if ($containerName === 'coolify-proxy') {
if (in_array($containerName, ['coolify-proxy', 'coolify-sentinel', Server::PROXY_ERROR_PAGE_CONTAINER], true)) {
continue;
}
if (isGeneratedContainerName($containerName)) {
@@ -386,6 +394,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
if ($buildHelperNames->contains($containerName)) {
continue;
}
if (str($containerName)->startsWith(self::TEMPORARY_HELPER_CONTAINER_PREFIXES)) {
continue;
}
$containerIp = data_get($container, 'IPv4Address');
if ($containerName && $containerIp) {
$ips->put($containerName, str($containerIp)->before('/')->value());
@@ -34,3 +34,23 @@ it('keeps the --add-host set stable whether or not a build helper is running', f
->toBe(addHostFlagsFor([$database]))
->toBe('--add-host postgres-main:10.0.1.3');
});
it('keeps database backup and S3 import helpers out of --add-host', function () {
$database = ['Name' => 'postgres-main', 'IPv4Address' => '10.0.1.3/24'];
expect(addHostFlagsFor([
$database,
['Name' => 'backup-of-bk7f2c9d0a1e4b5c6d7e8f9a0', 'IPv4Address' => '10.0.1.11/24'],
['Name' => 's3-restore-k4b2x9q1', 'IPv4Address' => '10.0.1.12/24'],
]))->toBe(addHostFlagsFor([$database]))
->toBe('--add-host postgres-main:10.0.1.3');
});
it('keeps the Coolify proxy, Sentinel, and error page containers out of --add-host', function () {
expect(addHostFlagsFor([
['Name' => 'coolify-proxy', 'IPv4Address' => '10.0.1.2/24'],
['Name' => 'coolify-sentinel', 'IPv4Address' => '10.0.1.3/24'],
['Name' => 'coolify-proxy-error-pages', 'IPv4Address' => '10.0.1.4/24'],
['Name' => 'postgres-main', 'IPv4Address' => '10.0.1.5/24'],
]))->toBe('--add-host postgres-main:10.0.1.5');
});