# Copias de seguridad y restauración del volumen de un servicio

Un servicio que guarda datos tiene un **volumen**. Una copia de seguridad es una instantánea de ese volumen que haces bajo demanda, conservas y a la que puedes devolver el volumen. Son *tus* instantáneas. Aparte, Zaroz mantiene sus propias copias de recuperación ante desastres de la plataforma; no se listan aquí y no es de ellas de donde restauras.

Los ejemplos usan el ayudante de [Usar la API de Zaroz](/es/guides/api/overview). `{resource_id}` es el id del recurso volumen del servicio: lista los recursos con `GET /service-instances/{id}/resources` y elige el de tipo volumen. Solo pueden hacer copias los servicios cuyo producto tiene almacenamiento y cuyo clúster admite instantáneas; consulta la entrada `backups` de las [capacidades](/es/concepts/capabilities) del servicio. Un servicio sin almacenamiento responde `404`, igual que uno que no es tuyo.

## Hacer una copia

**curl**

```bash
B=/service-instances/$SERVICE/resources/$VOLUME/backups

curl -sS -X POST "$ZAROZ_API$B" -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"name": "before-upgrade"}'                         # 202: se ejecuta en segundo plano
curl -sS "$ZAROZ_API$B" -H "$AUTH"
```

```json
{
  "backups": [
    { "id": "…", "name": "before-upgrade", "status": "ready", "size_bytes": 482344960,
      "created_at": "2026-10-15T09:00:00Z", "completed_at": "2026-10-15T09:01:12Z",
      "restore_phase": null, "restore_started_at": null }
  ],
  "max_backups": 5
}
```

**TypeScript**

```ts
import { call } from "./zaroz";

const B = `/service-instances/${SERVICE}/resources/${VOLUME}/backups`;
await call("POST", B, { name: "before-upgrade" }); // sin nombre se usa uno con marca de tiempo

for (;;) {
  const { body } = await call("GET", B);
  const b = body.backups.find((x: any) => x.name === "before-upgrade");
  console.log(b.status, `${body.backups.length}/${body.max_backups}`);
  if (b.status === "ready" || b.status === "failed") break;
  await new Promise((r) => setTimeout(r, 5000));
}
```

**Python**

```python
import time
from zaroz import call

B = f"/service-instances/{SERVICE}/resources/{VOLUME}/backups"
call("POST", B, {"name": "before-upgrade"})  # sin nombre se usa uno con marca de tiempo

while True:
    _, body = call("GET", B)
    b = next(x for x in body["backups"] if x["name"] == "before-upgrade")
    print(b["status"], f"{len(body['backups'])}/{body['max_backups']}")
    if b["status"] in ("ready", "failed"):
        break
    time.sleep(5)
```

- Una copia empieza en `creating` y se puede restaurar en `ready`. Una `failed` sigue en la lista hasta que la borras.
- `max_backups` es el techo por volumen, publicado en el listado para que nunca lo fijes a mano. Pasado ese techo, crear responde un error de cuota: borra antes una antigua.
- No puedes iniciar una copia mientras otra copia o una restauración se ejecutan en el mismo volumen (`409`).
- Una copia es una instantánea del volumen tal como está en ese momento. Si necesitas una copia consistente a nivel de aplicación (una base de datos a mitad de transacción), deja de escribir antes o haz también el volcado propio de la base.

## Restaurar

**Restaurar es irreversible.** Los workloads que usan el volumen se detienen, los datos del volumen se revierten a la instantánea y después arrancan de nuevo: **se pierde todo cambio hecho desde la copia.** Si puedes querer recuperar el estado actual, haz antes una copia de él. La copia debe estar `ready`.

**curl**

```bash
curl -sS -X POST "$ZAROZ_API$B/$BACKUP/restore" -H "$AUTH"      # 202; consulta el listado
```

**TypeScript**

```ts
await call("POST", `${B}/${BACKUP_ID}/restore`);
for (;;) {
  const { body } = await call("GET", B);
  const b = body.backups.find((x: any) => x.id === BACKUP_ID);
  console.log(b.status, b.restore_phase);
  if (b.status === "ready" && !b.restore_phase) break;
  await new Promise((r) => setTimeout(r, 10_000));
}
```

**Python**

```python
call("POST", f"{B}/{BACKUP_ID}/restore")
while True:
    _, body = call("GET", B)
    b = next(x for x in body["backups"] if x["id"] == BACKUP_ID)
    print(b["status"], b["restore_phase"])
    if b["status"] == "ready" and not b["restore_phase"]:
        break
    time.sleep(10)
```

Mientras restaura, la copia muestra `status: "restoring"` y un `restore_phase` que pasa por `stopping_workloads`, `detaching_pre`, `maint_attaching`, `reverting`, `detaching_post`, `csi_retaining_pv`, `csi_recreating_pvc` y `restarting_workloads`. Tarda varios minutos; los volúmenes grandes más. No inicies otra copia ni restauración entretanto (`409`). Usa `restore_started_at` para mostrar "restaurando desde hace N minutos".

## Borrar una copia

```bash
curl -sS -X DELETE "$ZAROZ_API$B/$BACKUP" -H "$AUTH"      # 204
```

```ts
await call("DELETE", `${B}/${BACKUP_ID}`);
```

```python
call("DELETE", f"{B}/{BACKUP_ID}")
```

Una copia en `creating` o `restoring` no se puede borrar; espera a que esté `ready` o `failed`. Borrar elimina la instantánea subyacente.

## Cuánto ocupa el volumen

**curl**

```bash
curl -sS "$ZAROZ_API/service-instances/$SERVICE/resources/$VOLUME/volume" -H "$AUTH"
# {"capacity_bytes": 10737418240, "used_bytes": 2147483648, "used_fraction": 0.2,
#  "used_label": "2.0 GiB of 10 GiB", "mount_path": "/data", "last_backup_at": "2026-10-15T09:01:12Z"}
```

```ts
const v = await call("GET", `/service-instances/${SERVICE}/resources/${VOLUME}/volume`);
console.log(v.body.used_label, v.body.last_backup_at);
```

```python
_, v = call("GET", f"/service-instances/{SERVICE}/resources/{VOLUME}/volume")
print(v["used_label"], v["last_backup_at"])
```

`capacity_bytes` es el tamaño configurado (una cuota, siempre presente). `used_bytes` se mide dentro del clúster y es `null` cuando no se puede medir, así que muestra "desconocido" en lugar de cero. `last_backup_at` te dice si tu rutina funciona.

## Antes de fiarte

- Las copias pertenecen al volumen y a su suscripción. No las tomes como la única copia de nada que no puedas perder si puedes borrar o cancelar el servicio.
- Para guardar una copia **fuera** de Zaroz, copia los archivos (con las rutas de archivos o SFTP) o vuelca la base de datos al [almacenamiento de objetos](/es/storage/quick-start).
- Automatízalo: un trabajo nocturno que cree una copia, espere a `ready` y borre la más antigua al llegar a `max_backups` son unas pocas líneas del código anterior. Usa un [token](/es/api-tokens/getting-started) con `services.manage` limitado a ese servicio.
