Capítulo 8: Comunicación Host-Guest
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:
| Canal | Propósito | Protocolo |
|---|---|---|
| vsock | IPC bidireccional de alto rendimiento | Sockets Unix-like |
| MMDS | Inyección de metadatos host→guest | HTTP (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:
- RPCs internas entre el host y el agente del guest
- Transferencia de configuración en el arranque
- Recolección de métricas desde el guest
- Cualquier comunicación donde la red TCP/IP sea overhead innecesario
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"
guest_cid: Context ID del guest. Usa 3 o superior (1=hypervisor, 2=host son reservados)uds_path: Unix domain socket en el host para la comunicación
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ón | Seguridad | Autenticación |
|---|---|---|
| V1 | Básica | Sin token (deprecated) |
| V2 | Recomendada | Token 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"