Apps multi-servicio (estilo compose)
Una app puede correr varios contenedores — ej. un frontend web más un cache o una base de datos internos. Es la versión de la plataforma de un stack de Compose: 1 app = N servicios, pero cuenta como una unidad en tu cuota.
¿Ya tenés un docker-compose.yml? Importalo
En el tab Multi-service del form de deploy, poné tu repo Git (y un token si es privado) y hacé click en Import from docker-compose.yml. La plataforma lee el compose y te rellena los servicios solos — builds/imágenes, puertos, environment, montajes de volúmenes nombrados, y cuál servicio es público. Revisás las filas y desplegás.
Credenciales generadas (seguro por defecto)
Las variables que parecen credenciales — nombres con PASS / PASSWORD / SECRET / TOKEN / KEY — reciben un valor fuerte generado, aunque tu compose tenga un default (esos defaults, como root o dev-token, son inseguros). El mismo ${VAR} mantiene un único valor entre servicios, así por ejemplo el password de la DB coincide entre tu db y tu backend.
Tras importar, el form muestra un recuadro 🔐 Generated credentials con un botón Download .env — se muestran una sola vez, así que guardalas. (Las credenciales de la DB también las recuperás después con Manage database.) Las vars no-secretas mantienen su default del compose.
Lo que no puede traer (y avisa)
Los bind mounts de host (./codigo:/app), porque la plataforma hornea el código en la imagen, y depends_on / healthcheck. El bind de un init-script de DB (schema.sql) también se descarta — cargá tu esquema una vez con Manage database. (Repos de GitHub.)
Reglas
- Pasás un array
services(al menos uno). - Al menos uno debe ser
public: true. Podés exponer varios (ej. un SPA y su API): el primer público tomahttps://<app>.cynchro.cloud, los extra recibenhttps://<app>-<servicio>.cynchro.cloud(override por servicio condomain). - Los servicios internos (
public:false) no se exponen a internet. Viven en una red privada por-app y son alcanzables por los otros servicios por suname(ej.http://cache:6379). Las vars de discovery (<SVC>_HOST,<SVC>_URL, …) se inyectan solas — ver el Despliegue full-stack. - Cada servicio puede usar su propia
image, o buildear desde unrepocompartido a nivel app. repo/branch/repoTokenquedan a nivel app (un repo para el stack);port/env/cpu/memory/ secrets son por servicio.
Ejemplo — web público + redis interno
curl -s -X POST $API/deploy \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{
"name": "shop",
"services": [
{ "name": "web", "image": "acme/storefront:1.0", "port": 8080, "public": true,
"env": { "REDIS_URL": "redis://cache:6379" } },
{ "name": "cache", "image": "redis:7-alpine", "port": 6379, "public": false }
]
}'
https://shop.cynchro.cloud→ el contenedor web.webalcanza acachepor la red privada enredis://cache:6379.cachees invisible desde internet.
Campos de cada servicio
| Campo | Requerido | Notas |
|---|---|---|
name | ✅ | DNS-safe; también es el hostname interno. |
image | ✅* | Imagen prearmada, O omitir para buildear desde el repo a nivel app. |
dockerfile / context | Cuando buildea desde repo (rutas relativas). | |
port | Default 80. Puerto donde escucha el servicio. | |
public | true para exponerlo (podés exponer más de uno). | |
domain | Override del hostname de este servicio público. | |
cpu / memory | Límites por servicio. | |
env | Env por servicio (cifrado at-rest). | |
envFrom / secretFiles | Referencias a Secrets por servicio. | |
buildArgs | Claves de env a hornear en build (--build-arg), ej. ["VITE_API_URL"]. | |
envFilePath | Renderiza el env de este servicio como un .env read-only en esta ruta, ej. /var/www/html/.env. | |
volumes | Rutas de montaje persistentes (absolutas), ej. ["/var/lib/mysql"] — para bases de datos. |
* Cada servicio necesita su propia image o un repo a nivel app para buildear.
Bases de datos (volúmenes persistentes)
La plataforma no lee el
docker-compose.ymlde tu repo — los servicios los declarás acá. Una base de datos necesita una ruta envolumespara que sus datos sobrevivan a los redeploys.
Agregá la base como un servicio interno con un montaje en volumes. Los otros servicios la alcanzan por nombre (ej. db). Los datos en un volumen sobreviven redeploys/restarts; se borran solo cuando borrás la app.
-d '{
"name": "myapp",
"services": [
{ "name":"web", "image":"myorg/web:1.0", "port":80, "public":true,
"env": { "DB_HOST":"db", "DB_USER":"root", "DB_PASS":"secret", "DB_NAME":"app" } },
{ "name":"db", "image":"mysql:8", "port":3306, "public":false,
"env": { "MYSQL_ROOT_PASSWORD":"secret", "MYSQL_DATABASE":"app" },
"volumes": ["/var/lib/mysql"] }
]
}'
Cargar un esquema: las imágenes oficiales mysql/postgres corren los scripts de /docker-entrypoint-initdb.d solo en un volumen nuevo y vacío. Dos opciones fáciles:
- Una vez, a mano: abrí el gestor de base de datos (botón Database), conectate a
db, y corré tuschema.sql. - Horneado en la imagen: agregá un
db/Dockerfilechico a tu repo (FROM mysql:8+COPY schema.sql /docker-entrypoint-initdb.d/01-schema.sql) y buildeá ese servicio desde el repo. El esquema se carga solo en el primer init.
Buildear todos los servicios desde un repo
-d '{
"name": "stack",
"repo": "https://github.com/acme/monorepo",
"services": [
{ "name":"api", "dockerfile":"api/Dockerfile", "context":"api", "port":3000, "public":true },
{ "name":"worker", "dockerfile":"worker/Dockerfile", "context":"worker", "port":0, "public":false }
]
}'
El repo se clona una vez y cada servicio se buildea desde su propio Dockerfile.
Ciclo de vida
Restart / stop / delete actúan sobre toda la app (todos sus contenedores). Borrarla también destruye la red privada. El self-healing vigila cada contenedor — si alguno cae, se redesplega la app.
→ Volver a lo básico: Desplegar desde Git · Inyectar config: Secrets