Migrate from Docker Compose to Bahriya
A docker-compose.yml describes several services that run together on one host: your app, maybe a worker, a database, a cache, and the wiring between them. Bahriya runs the same services, but each one is deployed and scaled individually across the regions you choose — there is no single compose up that brings the whole stack up at once. This guide maps a compose file onto Bahriya resources and walks the move.
A docker-compose.yml describes several services that run together on one host: your app, maybe a worker, a database, a cache, and the wiring between them. Bahriya runs the same services, but each one is deployed and scaled individually across the regions you choose — there is no single compose up that brings the whole stack up at once. This guide maps a compose file onto Bahriya resources and walks the move.
What maps to what
| Docker Compose | Bahriya |
|---|---|
A service that serves traffic | An HTTP container |
A service that runs in the background | A worker container |
| A scheduled task | A cron job |
build: / image: | The image you build and push to a registry |
ports: | The port you declare with --port |
environment: (non-sensitive) | Environment variables |
environment: (sensitive) / secrets: | Secrets (encrypted, injected as env vars) |
depends_on: a database service | An external database via a connection secret |
depends_on: a cache service | Bahriya Memcached, or an external cache via a secret |
volumes: | Ephemeral or persistent storage |
| Compose network / service names | Explicit connection strings held as secrets |
The key difference
Compose treats the file as one unit — every service starts together and they reach each other by service name on a shared network. On Bahriya you deploy each service as its own container. That means two things:
- There is no automatic service discovery by name. Where one service talked to another as
db:5432orcache:11211, you supply an explicit address — a database's network address stored as a secret, or a Bahriya Memcached endpoint. - Each container has its own regions, resources, and scaling. Deploy them one at a time; the platform-managed add-ons (database, cache) are not containers you run yourself.
1. Take stock of the compose file
Go through each service and decide its Bahriya shape:
- Your app service — an HTTP container if it exposes a port, a worker if it does not.
- A queue consumer or background job — a worker container.
- A
cron-style service — a cron job. - A database service (
postgres,mysql,mongo) — not a container you deploy. Provision a database elsewhere and connect over the network. - A cache service (
memcached,redis) — Bahriya Memcached for Memcached, or an external cache reached via a secret.
2. Build and push each app image
For every service you will run as a container, build its image and push it to a registry:
docker build -t ghcr.io/myorg/api:v1.0.0 .
docker push ghcr.io/myorg/api:v1.0.0If your compose service used build:, that build context and Dockerfile carry straight over.
3. Ports
A compose ports: mapping like "8080:8080" tells you the port your app listens on. Declare that container port with --port (default 8080) and bind your server to 0.0.0.0. Bahriya provides the public HTTPS hostname — you do not map host ports yourself.
4. Environment and secrets
Split each service's environment: block:
- Non-sensitive entries become plain environment variables.
- Sensitive entries, and anything under compose
secrets:, become secrets — created once, attached to the project, and wired to the variable name your app reads.
Replace inter-service references. Where the app read DATABASE_URL=postgres://db:5432/app, point it at the real address of your provisioned database, stored as a secret. Where it read a cache host of cache, use your Bahriya Memcached endpoint.
5. Volumes
A compose volumes: entry becomes storage on the container. Use ephemeral storage for scratch space that need not survive a restart, or persistent storage for data that must. Note that a database's data volume belongs to your external database, not to a Bahriya container.
6. Deploy each service
Deploy the services one at a time. From the Console follow Deploy Your First Container, or with Reis:
# The web service
reis container:create \
--type http \
--name "Web" \
--handle web \
--image ghcr.io/myorg/api:v1.0.0 \
--registry ghcr \
--port 8080 \
--healthcheck /healthz \
--regions falkenstein-1 \
--env APP_ENV=production \
--secrets DATABASE_URL=database-url
# A background worker from the same or a different image
reis container:create \
--type worker \
--name "Worker" \
--handle worker \
--image ghcr.io/myorg/worker:v1.0.0 \
--registry ghcr \
--regions falkenstein-1 \
--secrets DATABASE_URL=database-urlPut related services in the same project so they share secrets and configuration.
7. Point your domain and cut over
Your HTTP container is reachable at https://web.<region>.x.on.bahriya.app with automatic TLS. Test the whole stack against the default hostnames, then add your production domain to the public service, verify it, and move DNS across — see Custom Domain Setup.