mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-19 07:35:25 +00:00
feat(container): support comma-separated roles
Allow s6 services to start for specific roles like horizon, scheduler, nightwatch, and flux while keeping all as the default.
This commit is contained in:
@@ -7,6 +7,7 @@ APP_URL=http://localhost
|
||||
APP_PORT=8000
|
||||
APP_DEBUG=true
|
||||
SSH_MUX_ENABLED=true
|
||||
COOLIFY_CONTAINER_ROLE=all
|
||||
|
||||
# PostgreSQL Database Configuration
|
||||
DB_DATABASE=coolify
|
||||
|
||||
@@ -32,13 +32,18 @@ You can find the installation script source [here](./scripts/install.sh).
|
||||
|
||||
## Container roles and Flux
|
||||
|
||||
The Coolify image can run different process roles with `COOLIFY_CONTAINER_ROLE`:
|
||||
The Coolify image can run different process roles with `COOLIFY_CONTAINER_ROLE`. The value can be a single role or a comma-separated list. If `all` is present anywhere in the list, every role starts.
|
||||
|
||||
- `all` (default): self-hosted mode; runs the web process, worker services, and Flux when configured.
|
||||
- `web`: web/API process only; s6 worker services and Flux sleep.
|
||||
- `web`: web/API process only; s6 worker services and Flux sleep unless they are also listed.
|
||||
- `worker`: Horizon, Laravel scheduler worker, and optional Nightwatch agent.
|
||||
- `horizon`: Horizon only.
|
||||
- `scheduler` or `scheduler-worker`: Laravel scheduler worker only.
|
||||
- `nightwatch` or `nightwatch-agent`: optional Nightwatch agent only.
|
||||
- `flux`: Flux only; used by Cloud/HA deployments that scale coold connection routers separately.
|
||||
|
||||
For example, `COOLIFY_CONTAINER_ROLE=web,flux` starts the web container plus Flux, while `COOLIFY_CONTAINER_ROLE=web,all` still starts all services.
|
||||
|
||||
Flux is installed from the coold nightly release into `/usr/local/bin/flux`. Containers running the `all` or `flux` role expose Flux on port `6443` and use these runtime variables:
|
||||
|
||||
```env
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|flux) ;;
|
||||
*)
|
||||
echo " INFO Flux is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role flux; then
|
||||
echo " INFO Flux is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^COOLIFY_FLUX_ENABLED=false' .env 2>/dev/null || [ "${COOLIFY_FLUX_ENABLED:-}" = "false" ]; then
|
||||
echo " INFO Flux is disabled, sleeping."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Horizon is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role horizon; then
|
||||
echo " INFO Horizon is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^HORIZON_ENABLED=false' .env 2>/dev/null; then
|
||||
echo " INFO Horizon is disabled, sleeping."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Nightwatch is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role nightwatch && ! coolify_container_has_role nightwatch-agent; then
|
||||
echo " INFO Nightwatch is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^NIGHTWATCH_ENABLED=true' .env 2>/dev/null; then
|
||||
echo " INFO Nightwatch is enabled, starting..."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Scheduler worker is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role scheduler && ! coolify_container_has_role scheduler-worker; then
|
||||
echo " INFO Scheduler worker is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^SCHEDULER_ENABLED=false' .env 2>/dev/null; then
|
||||
echo " INFO Scheduler is disabled, sleeping."
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
coolify_container_role_value() {
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
|
||||
printf '%s\n' "${role:-all}"
|
||||
}
|
||||
|
||||
coolify_container_has_role() {
|
||||
wanted_role="$1"
|
||||
roles="$(coolify_container_role_value | tr '[:upper:]' '[:lower:]' | tr ',' ' ')"
|
||||
|
||||
for role in $roles; do
|
||||
case "$role" in
|
||||
all|"$wanted_role")
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|flux) ;;
|
||||
*)
|
||||
echo " INFO Flux is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role flux; then
|
||||
echo " INFO Flux is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^COOLIFY_FLUX_ENABLED=false' .env 2>/dev/null || [ "${COOLIFY_FLUX_ENABLED:-}" = "false" ]; then
|
||||
echo " INFO Flux is disabled, sleeping."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Horizon is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role horizon; then
|
||||
echo " INFO Horizon is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^HORIZON_ENABLED=false' .env 2>/dev/null; then
|
||||
echo " INFO Horizon is disabled, sleeping."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Nightwatch is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role nightwatch && ! coolify_container_has_role nightwatch-agent; then
|
||||
echo " INFO Nightwatch is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^NIGHTWATCH_ENABLED=true' .env 2>/dev/null; then
|
||||
echo " INFO Nightwatch is enabled, starting..."
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
role="${role:-all}"
|
||||
. /etc/s6-overlay/scripts/container-role
|
||||
role="$(coolify_container_role_value)"
|
||||
|
||||
case "$role" in
|
||||
all|worker) ;;
|
||||
*)
|
||||
echo " INFO Scheduler worker is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
;;
|
||||
esac
|
||||
if ! coolify_container_has_role worker && ! coolify_container_has_role scheduler && ! coolify_container_has_role scheduler-worker; then
|
||||
echo " INFO Scheduler worker is disabled for role '$role', sleeping."
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
if grep -qE '^SCHEDULER_ENABLED=false' .env 2>/dev/null; then
|
||||
echo " INFO Scheduler is disabled, sleeping."
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
coolify_container_role_value() {
|
||||
role="${COOLIFY_CONTAINER_ROLE:-}"
|
||||
|
||||
if [ -z "$role" ]; then
|
||||
role="$(grep -E '^COOLIFY_CONTAINER_ROLE=' .env 2>/dev/null | tail -n1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
||||
fi
|
||||
|
||||
printf '%s\n' "${role:-all}"
|
||||
}
|
||||
|
||||
coolify_container_has_role() {
|
||||
wanted_role="$1"
|
||||
roles="$(coolify_container_role_value | tr '[:upper:]' '[:lower:]' | tr ',' ' ')"
|
||||
|
||||
for role in $roles; do
|
||||
case "$role" in
|
||||
all|"$wanted_role")
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
Generated
+2
-10
@@ -70,7 +70,6 @@
|
||||
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.29.7",
|
||||
"@babel/generator": "^7.29.7",
|
||||
@@ -1614,8 +1613,7 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.33",
|
||||
@@ -1650,7 +1648,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.12",
|
||||
"caniuse-lite": "^1.0.30001782",
|
||||
@@ -2296,7 +2293,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -2408,7 +2404,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
|
||||
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -2418,7 +2413,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
|
||||
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
@@ -2525,8 +2519,7 @@
|
||||
"version": "4.1.18",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.0",
|
||||
@@ -2600,7 +2593,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
|
||||
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Contracts\Process\ProcessResult;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
it('matches comma separated container roles and lets all override every service', function (string $roles, string $serviceRole) {
|
||||
$result = runContainerRoleHelper($roles, $serviceRole);
|
||||
|
||||
expect($result->successful())->toBeTrue();
|
||||
})->with([
|
||||
['worker,flux', 'worker'],
|
||||
['worker,flux', 'flux'],
|
||||
['web, all', 'flux'],
|
||||
['flux,all,worker', 'worker'],
|
||||
['horizon,scheduler,nightwatch,flux', 'horizon'],
|
||||
['horizon,scheduler,nightwatch,flux', 'scheduler'],
|
||||
['horizon,scheduler,nightwatch,flux', 'nightwatch'],
|
||||
]);
|
||||
|
||||
it('rejects services missing from the comma separated container roles', function () {
|
||||
$result = runContainerRoleHelper('web,flux', 'worker');
|
||||
|
||||
expect($result->failed())->toBeTrue();
|
||||
});
|
||||
|
||||
it('falls back to the container role from the local env file', function () {
|
||||
$directory = sys_get_temp_dir().'/coolify-container-role-'.bin2hex(random_bytes(4));
|
||||
mkdir($directory);
|
||||
file_put_contents($directory.'/.env', 'COOLIFY_CONTAINER_ROLE=worker,flux'.PHP_EOL);
|
||||
|
||||
$result = runContainerRoleHelper('', 'flux', $directory);
|
||||
|
||||
expect($result->successful())->toBeTrue();
|
||||
});
|
||||
|
||||
it('keeps production and development role helpers in sync', function () {
|
||||
expect(file_get_contents(base_path('docker/production/etc/s6-overlay/scripts/container-role')))
|
||||
->toBe(file_get_contents(base_path('docker/development/etc/s6-overlay/scripts/container-role')));
|
||||
});
|
||||
|
||||
function runContainerRoleHelper(string $roles, string $serviceRole, ?string $workingDirectory = null): ProcessResult
|
||||
{
|
||||
$script = base_path('docker/development/etc/s6-overlay/scripts/container-role');
|
||||
$command = sprintf(
|
||||
'. %s && coolify_container_has_role %s',
|
||||
escapeshellarg($script),
|
||||
escapeshellarg($serviceRole),
|
||||
);
|
||||
|
||||
return Process::path($workingDirectory ?? base_path())
|
||||
->env(['COOLIFY_CONTAINER_ROLE' => $roles])
|
||||
->run($command);
|
||||
}
|
||||
Reference in New Issue
Block a user