Capítulo 7: Snapshots

Por: Artiko
firecrackersnapshotsclonacionmicrovmestado

Capítulo 7: Snapshots

Los snapshots permiten guardar el estado completo de una microVM (CPU, memoria, dispositivos) y restaurarlo más tarde. Son fundamentales para el arranque ultrarrápido en plataformas serverless.

Tipos de snapshot

TipoDescripciónCuándo usar
FullEstado completo + toda la memoriaPrimera snapshot, restaurar a estado base
DiffSolo páginas de memoria modificadas desde la última snapshotCheckpoints frecuentes, ahorro de espacio

Requisitos para diff snapshots

Para usar snapshots de tipo Diff, debes habilitar el tracking de páginas sucias antes de arrancar la VM:

curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "vcpu_count": 2,
    "mem_size_mib": 1024,
    "track_dirty_pages": true
  }' \
  "http://localhost/machine-config"

Crear un snapshot (Full)

API_SOCKET="/tmp/firecracker.socket"
SNAPSHOT_DIR="./snapshots/vm1"
mkdir -p "${SNAPSHOT_DIR}"

# 1. Pausar la VM (obligatorio antes de crear snapshot)
curl -s -X PATCH \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{"state": "Paused"}' \
  "http://localhost/vm"

# 2. Crear el snapshot
curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data "{
    \"snapshot_type\": \"Full\",
    \"snapshot_path\": \"${SNAPSHOT_DIR}/snapshot\",
    \"mem_file_path\": \"${SNAPSHOT_DIR}/memory\"
  }" \
  "http://localhost/snapshot/create"

# 3. Resumir la VM (puede seguir ejecutándose)
curl -s -X PATCH \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{"state": "Resumed"}' \
  "http://localhost/vm"

Resultado: dos archivos en ./snapshots/vm1/:

Crear un snapshot Diff

# Solo si track_dirty_pages: true
curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "snapshot_type": "Diff",
    "snapshot_path": "./snapshots/vm1/snapshot-diff",
    "mem_file_path": "./snapshots/vm1/memory-diff"
  }' \
  "http://localhost/snapshot/create"

Un snapshot Diff solo contiene las páginas de RAM modificadas desde el último snapshot — puede ser mucho más pequeño que el Full.

Restaurar un snapshot

La restauración se hace en un nuevo proceso Firecracker (el anterior puede estar terminado):

# Nuevo socket para la VM restaurada
NEW_SOCKET="/tmp/firecracker-restored.sock"
rm -f "${NEW_SOCKET}"

# 1. Iniciar Firecracker sin config (en background)
firecracker --api-sock "${NEW_SOCKET}" &
FC_PID=$!

sleep 0.5  # Esperar a que el socket esté listo

# 2. Restaurar el snapshot
curl -s -X PUT \
  --unix-socket "${NEW_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "snapshot_path": "./snapshots/vm1/snapshot",
    "mem_backend": {
      "backend_path": "./snapshots/vm1/memory",
      "backend_type": "File"
    },
    "resume_vm": false
  }' \
  "http://localhost/snapshot/load"

# 3. Resumir la VM restaurada
curl -s -X PATCH \
  --unix-socket "${NEW_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{"state": "Resumed"}' \
  "http://localhost/vm"

La VM continúa exactamente desde donde la pausaste.

Clonación de VMs con snapshots

Puedes arrancar múltiples instancias del mismo snapshot. Cada una carga el archivo de memoria con MAP_PRIVATE (copy-on-write), por lo que comparten las páginas no modificadas sin duplicar RAM física.

# Arrancar 3 clones del mismo snapshot
for i in 1 2 3; do
  SOCKET="/tmp/fc-clone-${i}.sock"
  rm -f "${SOCKET}"
  
  firecracker --api-sock "${SOCKET}" &
  sleep 0.3
  
  curl -s -X PUT \
    --unix-socket "${SOCKET}" \
    --header "Content-Type: application/json" \
    --data '{
      "snapshot_path": "./snapshots/base/snapshot",
      "mem_backend": {
        "backend_path": "./snapshots/base/memory",
        "backend_type": "File"
      },
      "resume_vm": true
    }' \
    "http://localhost/snapshot/load"
    
  echo "Clone ${i} iniciado en ${SOCKET}"
done

Caso de uso: arranque ultrarrápido

El patrón usado en AWS Lambda:

sequenceDiagram
    participant B as Boot (una vez)
    participant S as Snapshot base
    participant C as Clone 1..N

    B->>S: Iniciar VM, ejecutar init, crear snapshot
    Note over S: Estado: app lista, esperando petición
    C->>S: Restaurar snapshot (< 125ms)
    Note over C: VM lista para atender peticiones
  1. Preparar: arranca una VM, ejecuta tu aplicación hasta que esté lista, crea snapshot
  2. Servir: cada invocación restaura el snapshot → la app ya está inicializada

Esto elimina el tiempo de boot del lenguaje de programación (JVM, Python, Node.js).

Limitaciones importantes

Seguridad: restaurar el mismo snapshot múltiples veces es inseguro en producción — los identificadores únicos (UUIDs, tokens criptográficos, semillas aleatorias) se duplican.

Soluciones:

El archivo de memoria (mem_file_path) debe existir y ser accesible durante toda la vida de la VM restaurada — no lo elimines mientras la VM corre.

Referencia