services: list in .bellows.yaml. It is separate from environment:, and one file can have both.
Full example: Go with Postgres
.bellows.yaml
name. Here the tests connect to host db, port 5432.
Keys
Other keys are errors. A block list for
ports is also an error: write ports: [5432].
How you reach a service
Each service name resolves to127.0.0.1 for the agent, setup and your gates. Use the name (db) or localhost. Both work.
Services share one network namespace, so two services cannot listen on the same port. Bellows refuses a file where two services declare the same port. Nothing is published outside the task.
Limits
- At most 10 services per file.
- Service names must be unique.
- Every service runs hardened: all Linux capabilities dropped, no privilege escalation, and no way to turn that off. Declaring
unhardenedis an error. - There are no volumes, health checks,
depends_onor restart policies.
Why Postgres needs user
Stock Postgres starts as root, changes ownership of its data directory, then drops to its own user. A hardened container can’t do that, so it crash-loops. Set user: "999:999" so the image starts as the postgres user from the start. This is the uid of the Debian-based images. Check the uid your image uses if you pick another one. Redis and similar images that don’t need root usually need no user.
Startup and readiness
Services start beforesetup, so setup can migrate or seed a database. Bellows waits for each service container to be running. It does not check that the service accepts connections, because .bellows.yaml has no health checks.
A database can take a few seconds to accept connections after its container is running. setup is retried while it fails, so a migration step there rides out a slow start:
.bellows.yaml (excerpt)
setup first.
When a service fails
- If a service is dead before the gates run, Bellows restarts it and waits up to 5 minutes for it to be running again.
- If it does not come back, or never started, the task fails with the badge service failed.
- If a service dies while the agent is running a gate, the gate’s answer carries a note with the service’s exit code, reason and last log lines. The agent is told to stop and report it rather than install the service itself.
user: "999:999" or a missing POSTGRES_PASSWORD.
The panel is a record of the last attempt. Services are torn down when it ends.
Common errors
Task fails with “config error”
Task fails with “config error”
The plan was refused before anything launched. The message names the problem: a bad name or image, a port declared twice, more than 10 services, or the name
localhost.Connection refused or “no such host”
Connection refused or “no such host”
The service is still starting, or it died. Check the Services panel. Check that the host in your connection string is the service
name and the port is the one the image listens on.