Capítulo 8: Comunicación Host-Guest

Por: Artiko
firecrackervsockmmdshost-guestmetadataipc

Capítulo 8: Comunicación Host-Guest

Firecracker ofrece dos canales de comunicación entre el host y el guest, independientes de la red TCP/IP normal:

CanalPropósitoProtocolo
vsockIPC bidireccional de alto rendimientoSockets Unix-like
MMDSInyección de metadatos host→guestHTTP (similar a EC2 IMDS)

vsock: IPC Bidireccional

VirtIO Socket (vsock) es un canal de comunicación directo entre host y guest que no atraviesa la pila de red. Es ideal para:

Configurar vsock

API_SOCKET="/tmp/firecracker.socket"

curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "guest_cid": 3,
    "uds_path": "./vsock.sock"
  }' \
  "http://localhost/vsock"

Comunicarse via vsock desde el host

El host se conecta al socket Unix vsock.sock. El protocolo de Firecracker usa un handshake de texto:

# Instalar socat para pruebas
sudo apt-get install -y socat

# Conectar al puerto 1234 del guest
# El formato es: CONNECT <puerto>\n
echo "CONNECT 1234" | socat - UNIX-CONNECT:./vsock.sock

Configurar el listener en el guest

Dentro del guest Linux, usa la librería vsock estándar. Ejemplo con socat:

# Dentro del guest (instalar socat)
# Escuchar en puerto vsock 1234
socat - VSOCK-LISTEN:1234,fork

# O con ncat (si disponible)
ncat --vsock -l 1234

Ejemplo: agente de monitoreo

# host-agent.sh — recolecta métricas del guest
send_vsock() {
  local port="$1"
  local message="$2"
  (echo "CONNECT ${port}"; echo "${message}") \
    | socat - UNIX-CONNECT:./vsock.sock
}

# Solicitar métricas al agente del guest
send_vsock 9090 '{"action": "get_metrics"}'

MMDS: Servicio de Metadatos

El MicroVM Metadata Service (MMDS) es el equivalente al Instance Metadata Service (IMDS) de EC2. Permite al host inyectar datos de configuración que el guest puede leer via HTTP en 169.254.169.254.

Configurar MMDS

# 1. Habilitar MMDS y asociarlo a una interfaz de red
curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "version": "V2",
    "network_interfaces": ["eth0"],
    "ipv4_address": "169.254.169.254"
  }' \
  "http://localhost/mmds/config"

# 2. Cargar datos en el MMDS
curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "latest": {
      "meta-data": {
        "instance-id": "vm-abc123",
        "hostname": "worker-1",
        "region": "us-east-1"
      },
      "user-data": "#!/bin/bash\necho hello"
    }
  }' \
  "http://localhost/mmds"

Versiones de MMDS

VersiónSeguridadAutenticación
V1BásicaSin token (deprecated)
V2RecomendadaToken de sesión (TTL configurable)

Consultar MMDS desde el guest (V2)

# Dentro del guest

# 1. Obtener token de sesión (TTL en segundos)
TOKEN=$(curl -s -X PUT \
  --header "X-metadata-token-ttl-seconds: 21600" \
  "http://169.254.169.254/latest/api/token")

# 2. Usar el token para leer metadatos
curl -s \
  --header "X-metadata-token: ${TOKEN}" \
  "http://169.254.169.254/latest/meta-data/instance-id"

# 3. Leer user-data
curl -s \
  --header "X-metadata-token: ${TOKEN}" \
  "http://169.254.169.254/latest/user-data"

Actualizar MMDS en caliente

El contenido del MMDS puede actualizarse mientras la VM corre:

# Actualizar datos existentes (PATCH actualiza parcialmente)
curl -s -X PATCH \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "latest": {
      "meta-data": {
        "status": "active",
        "updated-at": "2026-04-04T10:00:00Z"
      }
    }
  }' \
  "http://localhost/mmds"

Caso de uso: inyección de secretos

# Inyectar un secreto al arranque (desde el orchestrator)
curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "latest": {
      "meta-data": {
        "instance-id": "'"${INSTANCE_ID}"'"
      },
      "credentials": {
        "db-password": "'"${DB_PASSWORD}"'",
        "api-key": "'"${API_KEY}"'"
      }
    }
  }' \
  "http://localhost/mmds"

El guest lo lee al inicio:

# Init script del guest
TOKEN=$(curl -s -X PUT -H "X-metadata-token-ttl-seconds: 60" \
  http://169.254.169.254/latest/api/token)

DB_PASS=$(curl -s -H "X-metadata-token: ${TOKEN}" \
  http://169.254.169.254/credentials/db-password)

export DATABASE_URL="postgresql://user:${DB_PASS}@db:5432/app"

Referencia