Features

Accessories

Run databases, caches, and other services alongside your application.


Overview

Accessories 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 accessories in your deploy.yml:

accessories:
  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 accessory should run. Required for each accessory.

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 accessories

Accessory commands read target hosts from the accessory's hosts configuration, similar to how deploy works.

Boot all accessories

Start all accessories on their configured hosts:

odysseus accessory boot-all

Boot specific accessory

Start a single accessory on all its configured hosts:

odysseus accessory boot --name db

Check status

View running accessories across all hosts:

odysseus accessory status

Output:

Accessories:
  NAME    HOST              IMAGE         STATUS             HEALTH
  db      db.example.com    postgres:16   running (healthy)
  redis   cache.example.com redis:7       running (healthy)

View logs

Logs require a server argument since they operate on a specific host:

odysseus accessory logs your-server --name db
odysseus accessory logs your-server --name db -f  # Follow
odysseus accessory logs your-server --name db -n 200  # Last 200 lines

Restart

odysseus accessory restart --name db

Upgrade

Pull new image and restart:

odysseus accessory upgrade --name db

Remove

Stop and remove:

odysseus accessory remove --name db

Execute commands

Run a command in the accessory container (requires server argument):

odysseus accessory exec your-server --name db --command "psql -U myapp myapp_production"

Interactive shell

odysseus accessory shell your-server --name db

Common configurations

PostgreSQL

accessories:
  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

accessories:
  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

accessories:
  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

accessories:
  redis:
    image: redis:7-alpine
    hosts:
      - cache.example.com
    volumes:
      - /var/lib/odysseus/myapp/redis:/data
    cmd: redis-server --appendonly yes --requirepass mypassword

Elasticsearch

accessories:
  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

accessories:
  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

Accessories run on the same Docker network as your application. Connect using the accessory 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

Accessories 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:

accessories:
  db:
    env:
      secret:
        - POSTGRES_PASSWORD

4. Resource limits

Consider adding resource limits for production:

accessories:
  db:
    options:
      memory: 4g
      cpus: 2

5. Regular backups

Schedule regular backups of your data volumes.

Previous
Secrets management