Container service
Container services run in the same network as the other container tasks. By default, they are started when a task needs them and stopped once no remaining task needs them.
Differences from Docker Compose
Container services are similar to Docker Compose services, but are better integrated with your tasks. They lack many of Compose's features, but a few aspects still make them appealing.
Seamless integration
Hammerkit is aware of the task dependency tree and can make decisions about the lifetime of a service. Depending on your setup, this can reduce CPU and memory usage.
It keeps things simple and removes the need for another tool that has to be started, and waited for, before you can run your task.
Reuse
Services can be included or referenced like tasks. This makes it possible to reuse services and their state across multiple build files and projects — for example, to run a single database for several projects and save CPU and memory.
Store/Restore
The store/restore commands work for services as well, exporting and importing their volume data.
This can be used to seed a database, or to back up and restore project data.
Ports
Services can expose ports to the host machine. This is useful for debugging or for connecting to a service from your machine.
Container tasks don't need published ports. They share a network with the services and can reach all of their ports.
services:
postgres:
image: postgres:16-alpine
ports:
- 5432:5432Healthcheck
A healthcheck checks whether a service is ready to be used. A task only starts once every service it needs is running and, if a healthcheck is defined, has passed it.
A healthcheck requires a command that can be used to test the readiness of a service.
The command is executed inside the service container.
To pass the healthcheck the command needs to return with an exit code of 0.
The following example contains a Postgres service.
It uses the pg_isready executable in a healthcheck,
which ensures the Postgres server is ready to accept connections.
services:
postgres:
image: postgres:16-alpine
healthcheck:
cmd: "pg_isready -U postgres"Without a healthcheck, a task may start before the service is ready.
Timing and failure
The healthcheck has a single field, cmd. There are intentionally no
interval, timeout or retries knobs:
- hammerkit runs
cmdinside the service container roughly once a second and treats the service as ready the first time it exits0; - each individual check has a short execution timeout (a couple of seconds), so a hanging check doesn't block forever — it just counts as "not ready yet" and is retried;
- a check that never passes keeps the dependent task waiting until you cancel
the run. There is no readiness deadline, so the
cmdmust be something that genuinely turns green once the service is usable (likepg_isready), not a command that can hang or always fail.
On Kubernetes, the same cmd is translated into readiness
and liveness probes on the deployment.
Volumes
Services start and stop depending on what tasks need. To persist data across restarts, use volumes.
services:
postgres:
image: postgres:16-alpine
volumes:
- "postgres-db:/var/lib/postgresql/data"Mounts
Mounts can be used to pass local files into the container. They are meant for local configuration and settings files.
Mounts are not recommended for frequently changing files. Syncing large directories on macOS/Windows uses a lot of CPU.
services:
postgres:
image: postgres:16-alpine
mounts:
- "./postgres.conf:/etc/postgresql/postgresql.conf"