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.

Previous
Secrets management