Features
Dependencies
Run databases, caches, and other services alongside your application.
Renamed from accessories
dependencies: was called accessories: until 0.4.4, and odysseus dependency was odysseus accessory. Both old spellings still work and will be removed in a later release. Only the command announces itself: odysseus accessory prints a notice telling you it was renamed, while accessories: in deploy.yml is accepted silently — so a config still using the old key gives you no signal at all. Nothing on your hosts changes when you rename the key — container names and the odysseus.service label are built from the service name plus the dependency's own name, so running containers are adopted rather than orphaned.
Overview
Dependencies are long-running services that support your application:
- Databases (PostgreSQL, MySQL, MongoDB)
- Caches (Redis, Memcached)
- Message queues (RabbitMQ)
- Search engines (Elasticsearch)
Odysseus manages these as Docker containers with independent lifecycles.
Configuration
Define dependencies in your deploy.yml:
dependencies:
db:
image: postgres:16
hosts:
- db.example.com
volumes:
- /var/lib/odysseus/myapp/postgres:/var/lib/postgresql/data
env:
clear:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: secretpassword
POSTGRES_DB: myapp_production
healthcheck:
cmd: pg_isready -U myapp
interval: 10
timeout: 5
redis:
image: redis:7-alpine
hosts:
- cache.example.com
volumes:
- /var/lib/odysseus/myapp/redis:/data
cmd: redis-server --appendonly yes
image
Docker image for the service.
hosts
The servers where this dependency should run. Required for each dependency.
hosts:
- db.example.com
- db-replica.example.com
volumes
Persistent storage mappings. Data persists across container restarts.
volumes:
- /host/path:/container/path
env
Environment variables for the service:
env:
clear:
POSTGRES_USER: myapp
POSTGRES_DB: myapp_production
cmd
Override the container's default command:
cmd: redis-server --appendonly yes --maxmemory 256mb
healthcheck
Container health check configuration:
healthcheck:
cmd: pg_isready -U myapp
interval: 10
timeout: 5
ports
Expose ports (optional, for external access):
ports:
- 5432:5432
Managing dependencies
Dependency commands read target hosts from the dependency's hosts configuration, similar to how deploy works.
Boot all dependencies
Start all dependencies on their configured hosts:
odysseus dependency boot-all
Boot specific dependency
Start a single dependency on all its configured hosts:
odysseus dependency boot --name db
Check status
View running dependencies across all hosts:
odysseus dependency status
Output:
Dependencies:
NAME HOST IMAGE STATUS HEALTH
db db.example.com postgres:16 running (healthy)
redis cache.example.com redis:7 running (healthy)
status lists what deploy.yml declares, not what is actually running on the host — see Remove below for why that distinction matters.
View logs
Logs require a server argument since they operate on a specific host:
odysseus dependency logs your-server --name db
odysseus dependency logs your-server --name db -f # Follow
odysseus dependency logs your-server --name db -n 200 # Last 200 lines
Restart
odysseus dependency restart --name db
Upgrade
Pull new image and restart:
odysseus dependency upgrade --name db
Remove
Stop and remove:
odysseus dependency remove --name db
Remove first, then edit deploy.yml
remove finds a dependency's containers through that dependency's own config block in deploy.yml. Delete the block first and remove can no longer find the container either — it answers Dependency 'redis' not found in config, and so does every other dependency command. Run remove, confirm it worked, and only then delete the block.
remove stops and removes the dependency's containers and does nothing else — it does not touch volumes. A named volume, and the data in it, survives a remove and is reused if you boot the dependency again. Deleting the data itself is a separate, deliberate step on the host:
docker volume rm myapp-db-data
boot-all only boots what deploy.yml currently lists; it never removes a dependency that has been dropped from the config, deliberately — a typo or a half-merged branch should not be able to take out a database that way. So a dependency whose block you deleted without running remove first keeps running on the host indefinitely, and it will not appear in dependency status, which lists what the config declares rather than what the host is actually running.
Execute commands
Run a command in the dependency container (requires server argument):
odysseus dependency exec your-server --name db --command "psql -U myapp myapp_production"
Interactive shell
odysseus dependency shell your-server --name db
Common configurations
PostgreSQL
dependencies:
db:
image: postgres:16
hosts:
- db.example.com
volumes:
- /var/lib/odysseus/myapp/postgres:/var/lib/postgresql/data
env:
clear:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: secretpassword
POSTGRES_DB: myapp_production
healthcheck:
cmd: pg_isready -U myapp
interval: 10
timeout: 5
MySQL
dependencies:
db:
image: mysql:8
hosts:
- db.example.com
volumes:
- /var/lib/odysseus/myapp/mysql:/var/lib/mysql
env:
clear:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp_production
MYSQL_USER: myapp
MYSQL_PASSWORD: userpassword
healthcheck:
cmd: mysqladmin ping -h localhost
interval: 10
timeout: 5
Redis
dependencies:
redis:
image: redis:7-alpine
hosts:
- cache.example.com
volumes:
- /var/lib/odysseus/myapp/redis:/data
cmd: redis-server --appendonly yes
healthcheck:
cmd: redis-cli ping
interval: 10
timeout: 5
Redis with password
dependencies:
redis:
image: redis:7-alpine
hosts:
- cache.example.com
volumes:
- /var/lib/odysseus/myapp/redis:/data
cmd: redis-server --appendonly yes --requirepass mypassword
Elasticsearch
dependencies:
elasticsearch:
image: elasticsearch:8.11.0
hosts:
- search.example.com
volumes:
- /var/lib/odysseus/myapp/elasticsearch:/usr/share/elasticsearch/data
env:
clear:
discovery.type: single-node
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
xpack.security.enabled: "false"
MongoDB
dependencies:
mongo:
image: mongo:7
hosts:
- db.example.com
volumes:
- /var/lib/odysseus/myapp/mongo:/data/db
env:
clear:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
Connecting from your app
Dependencies run on the same Docker network as your application. Connect using the dependency name as hostname.
Database URL
# secrets.yml
DATABASE_URL: postgres://myapp:secretpassword@db:5432/myapp_production
REDIS_URL: redis://redis:6379
In your app
# Rails database.yml
production:
url: <%= ENV['DATABASE_URL'] %>
// Node.js
const redis = require('redis')
const client = redis.createClient({ url: process.env.REDIS_URL })
Data persistence
Dependencies use Docker volumes for data persistence:
volumes:
- /var/lib/odysseus/myapp/postgres:/var/lib/postgresql/data
Data is stored on the host at /var/lib/odysseus/myapp/postgres.
Backup
SSH to your server and backup the volume:
# PostgreSQL dump
docker exec myapp-db pg_dump -U myapp myapp_production > backup.sql
# Copy from volume
tar -czf postgres-backup.tar.gz /var/lib/odysseus/myapp/postgres
Restore
# PostgreSQL restore
cat backup.sql | docker exec -i myapp-db psql -U myapp myapp_production
Best practices
1. Use health checks
Always configure health checks:
healthcheck:
cmd: pg_isready -U myapp
interval: 10
timeout: 5
2. Persistent storage
Map volumes for data that must survive restarts:
volumes:
- /var/lib/odysseus/myapp/postgres:/var/lib/postgresql/data
3. Secure credentials
Use secrets for passwords:
dependencies:
db:
env:
secret:
- POSTGRES_PASSWORD
4. Resource limits
Consider adding resource limits for production:
dependencies:
db:
options:
memory: 4g
cpus: 2
5. Regular backups
Schedule regular backups of your data volumes.