Attachments Configuration
Attach service dependencies (databases, caches, queues) to your applications.
Configuration
[attachments]
"app.mydomain.com" = ["postgres:latest", "redis:latest"]
"api.mydomain.com" = ["postgres:latest"]
Syntax
[attachments]
"<domain-or-group>" = ["<image>:<tag>", "<image>:<tag>"]
| Component | Description |
|---|---|
domain-or-group |
Route domain or network group name |
image:tag |
Service images to deploy alongside the app |
How Attachments Work
When you define attachments:
- Gordon deploys attachment containers to the same network as your app
- Services are accessible by their image name (before the colon)
- Attachments start before your main application
- Attachments persist across app updates
┌───────────────────────────────────────────────────┐
│ Network: gordon-app-mydomain-com │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ App │───>│ postgres │ │ redis │ │
│ │ :3000 │ │ :5432 │ │ :6379 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
└───────────────────────────────────────────────────┘
Service Discovery
Attachments are accessible by their image name within the network:
[attachments]
"app.mydomain.com" = ["postgres:latest", "redis:latest"]
In your application:
// Connect using simple hostnames
const db = await pg.connect("postgresql://postgres:5432/mydb");
const cache = await redis.connect("redis://redis:6379");
Persistent Storage
Use Dockerfile VOLUME directives for persistent data:
# postgres.Dockerfile
FROM postgres:15
VOLUME ["/var/lib/postgresql/data"]
ENV POSTGRES_DB=myapp
ENV POSTGRES_USER=app
ENV POSTGRES_PASSWORD=secret
Build and push to Gordon:
docker build -f postgres.Dockerfile -t my-postgres:latest .
docker push registry.mydomain.com/my-postgres:latest
Use in attachments:
[attachments]
"app.mydomain.com" = ["my-postgres:latest"]
Shared Attachments with Network Groups
Share services between multiple apps using network groups:
[network_groups]
"backend" = ["app.mydomain.com", "api.mydomain.com"]
[attachments]
"backend" = ["shared-postgres:latest", "shared-redis:latest"]
Both app.mydomain.com and api.mydomain.com can access the shared services.
Per-App vs Shared Attachments
Per-App Attachments
Each app gets its own isolated service instances:
[attachments]
"app.mydomain.com" = ["postgres:latest"] # App's own postgres
"api.mydomain.com" = ["postgres:latest"] # API's own postgres
Shared Attachments
Multiple apps share the same service instances:
[network_groups]
"backend" = ["app.mydomain.com", "api.mydomain.com"]
[attachments]
"backend" = ["postgres:latest", "redis:latest"] # Shared by both
Mixed Approach
[network_groups]
"backend" = ["app.mydomain.com", "api.mydomain.com"]
[attachments]
"backend" = ["redis:latest"] # Shared cache
"app.mydomain.com" = ["postgres:latest"] # App's own database
"api.mydomain.com" = ["postgres:latest"] # API's own database
Examples
Web App with Database
[routes]
"app.mydomain.com" = "myapp:latest"
[attachments]
"app.mydomain.com" = ["postgres:15", "redis:7-alpine"]
Microservices with Shared Queue
[routes]
"orders.mydomain.com" = "orders-service:latest"
"inventory.mydomain.com" = "inventory-service:latest"
"notifications.mydomain.com" = "notifications-service:latest"
[network_groups]
"services" = ["orders.mydomain.com", "inventory.mydomain.com", "notifications.mydomain.com"]
[attachments]
"services" = ["rabbitmq:3-management"]
"orders.mydomain.com" = ["orders-db:latest"]
"inventory.mydomain.com" = ["inventory-db:latest"]
Custom Service Images
Build custom service images with your configuration:
# my-postgres.Dockerfile
FROM postgres:15
VOLUME ["/var/lib/postgresql/data"]
ENV POSTGRES_DB=production
ENV POSTGRES_USER=appuser
# Password should come from env file
# my-redis.Dockerfile
FROM redis:7-alpine
VOLUME ["/data"]
CMD ["redis-server", "--appendonly", "yes"]
[attachments]
"app.mydomain.com" = ["my-postgres:latest", "my-redis:latest"]
Container Naming
Attachment containers are named:
gordon-<domain>-<image-name>- Example:
gordon-app-mydomain-com-postgres
Labels
Gordon adds labels to attachment containers:
| Label | Value |
|---|---|
gordon.managed |
true |
gordon.attachment |
true |
gordon.attached-to |
Domain or group name |