Ir al contenido

Instalación manual: terminal

Instala el agente orden a orden, en el terminal del router: para un router sin ningún ordenador que ejecute la CLI, o para ver y adaptar cada objeto. Las órdenes son las que ejecuta install, con marcadores en mayúsculas. Para las mismas órdenes con tus valores ya puestos, usa el Generador de scripts.

Elige un valor para cada marcador. Los valores por defecto son los que usa install:

Marcador Por defecto Significado
NAME mikroscope el nombre de la instalación
TAG mikroscope:NAME (managed by mikroscope) el comentario de cada objeto; conserva esta forma para que la CLI reconozca la instalación
VETH veth-mikroscope el nombre de la veth
NET/30 172.30.10.0/30 una /30 IPv4 en su dirección de red, sin usar en el router
GW_IP 172.30.10.1 el extremo del router en la /30: la dirección de red + 1
AGENT_IP 172.30.10.2 el extremo del agente en la /30: la dirección de red + 2
PORT 9123 el puerto HTTP del agente
IFACE_LIST LAN la lista de interfaces a la que se une la veth; none en el manifiesto si te saltas la pertenencia
ADDR_LIST LANs la lista de direcciones a la que se une la /30; none en el manifiesto si te saltas la pertenencia
ENVLIST NAME-env la envlist del contenedor
DISK vacío (flash interna) un slot de disco, como tmpfs o usb1; precede a las tres rutas de abajo
MANIFEST_DIR mikroscope DISK/mikroscope en un disco
MANIFEST_FILE mikroscope/NAME.manifest.txt el manifiesto de la instalación
ROOT_DIR mikroscope/NAME la raíz del contenedor
IMAGE_REF registry-1.docker.io/jmrplens/mikroscope-agent:1.6.1 la imagen que descarga el router (descarga del registro)
IMAGE_FILE NAME.tar el tar de imagen subido (ruta del tar); DISK/NAME.tar en un disco
RATE_HZ 10 la tasa de muestreo, 1–100 Hz
BUFFER_S 60 el anillo, 10–3600 s
MEM_LIMIT_MB 16 el límite de memoria de Go del agente, abajo
CAPTURE_MB 4 el presupuesto de capturas por disparo, 0–256 MiB; 0 las desactiva
MEMORY_MAX 64M el límite de memoria del contenedor
START_ON_BOOT yes no para una raíz en un disco en RAM, que un reinicio vacía
PRIVILEGED yes no pierde el log del kernel, las cuentas del slab, los contadores de la flash y la PMU
RESTART_MAX_COUNT 5 reinicios tras un fallo
RESTART_INTERVAL 10s la espera entre ellos
EXTRACT_TIMEOUT_S 120 cuánto esperar a que RouterOS extraiga el tar (ruta del tar)
FLOOR_HZ ninguno opcional: una sola cadencia para todas las fuentes de nivel
TRIGGERS ninguno opcional: las condiciones de disparo (Captura por disparo)
TOKEN ninguno opcional: el token que pide el agente; un secreto
CONTAINER_NAME vacío (lo pone RouterOS) opcional: el name= del contenedor
LAN_IP ninguno solo con --expose: la dirección LAN del router

Un valor por defecto vacío se queda vacío: en la flash interna la línea del manifiesto es disk=, y sin nombre de contenedor container-name=, sin nada tras el =.

MEM_LIMIT_MB es RATE_HZ × BUFFER_S × lo que ocupa una muestra en el anillo × 2,5, redondeado hacia arriba, como mínimo 16 y como máximo ¾ de MEMORY_MAX mientras eso deje sitio al anillo. Con un MEMORY_MAX de 64M da 16 a 10 Hz y 60 s, 25 a 50 Hz y 60 s, y 48 a 100 Hz y 60 s. El generador lo calcula por ti.

Comprueba el router. Lee la versión y la arquitectura, el paquete container y device mode:

/system/resource/print
/system/package/print where name="container"
/system/device-mode/print

version tiene que ser 7.24 o posterior y architecture-name uno de arm64, arm o x86_64; el paquete tiene que aparecer y no estar deshabilitado; device mode tiene que mostrar container: yes. Requisitos tiene los arreglos: el paso de device mode necesita pulsar el botón reset o mode, o cortar la alimentación, en menos de 5 minutos; en CHR, apaga y enciende la máquina virtual.

Comprueba las colisiones. Cada una de estas tiene que no imprimir nada, o una cuenta de 0:

/interface/veth/print where name="VETH"
/container/envs/print count-only where list="ENVLIST"
/ip/address/print where address in NET/30
/ip/route/print where dst-address in NET/30
/file/print where name="MANIFEST_FILE"

Y estas tienen que encontrar lo que nombras: la lista de interfaces, y el disco si usas uno.

/interface/list/print where name="IFACE_LIST"
/disk/print

Para una raíz en un disco en RAM, crea uno antes: /disk/add type=tmpfs tmpfs-max-size=64M slot=tmpfs, y usa DISK tmpfs y START_ON_BOOT no. Si el firewall descarta las respuestas del agente está en Listas del firewall.

El manifiesto enumera cada objeto que crean los pasos siguientes, para que mikroscope uninstall y la retirada de abajo los encuentren todos. Quita la línea object= de cualquier paso que te saltes; para una pertenencia a lista que te saltes, escribe además none tras su iface-list= o addr-list=.

:local m "mikroscope-manifest=1\nname=NAME\ntag=TAG\ndisk=DISK\nveth=VETH\nsubnet=NET/30\nport=PORT\niface-list=IFACE_LIST\naddr-list=ADDR_LIST\nexpose=\ncontainer-name=CONTAINER_NAME\nremote-image=IMAGE_REF\ntoken=no\ndir=MANIFEST_DIR\nfile=MANIFEST_FILE\nobject=/interface/veth name=VETH\nobject=/ip/address interface=VETH\nobject=/interface/list/member interface=VETH list=IFACE_LIST\nobject=/ip/firewall/address-list list=ADDR_LIST address=NET/30\nobject=/container/envs list=ENVLIST\nobject=/container interface=VETH\ndir=ROOT_DIR\n"; :if ([:len [/file/find name="MANIFEST_FILE"]] > 0) do={ /file/set [find name="MANIFEST_FILE"] contents=$m } else={ /file/add name="MANIFEST_FILE" contents=$m }

Léelo con :put [/file/get [find name="MANIFEST_FILE"] contents]. Script de RouterOS explica cada línea.

/interface/veth/add name="VETH" address=AGENT_IP/30 gateway=GW_IP comment="TAG"
/ip/address/add address=GW_IP/30 interface="VETH" comment="TAG"

Opcional. Dejan pasar las respuestas del agente por reglas raw del firewall que descartan según una lista de interfaces o de direcciones; sáltate cualquiera de las dos cuando ninguna regla tuya la necesite, y quita su línea object= del manifiesto y escribe none tras su iface-list= o addr-list=. Una pertenencia no se limita a mikroscope: cualquier otra regla que compare la lista afecta también a la veth o a la /30 (Listas del firewall).

/interface/list/member/add list="IFACE_LIST" interface="VETH" comment="TAG"
/ip/firewall/address-list/add list="ADDR_LIST" address=NET/30 comment="TAG"
/container/envs/add list="ENVLIST" key=MIKROSCOPE_TAG value="TAG"
/container/envs/add list="ENVLIST" key=RATE_HZ value="RATE_HZ"
/container/envs/add list="ENVLIST" key=BUFFER_S value="BUFFER_S"
/container/envs/add list="ENVLIST" key=PORT value="PORT"
/container/envs/add list="ENVLIST" key=ADDR value="AGENT_IP"
/container/envs/add list="ENVLIST" key=MEM_LIMIT_MB value="MEM_LIMIT_MB"
/container/envs/add list="ENVLIST" key=CAPTURE_MB value="CAPTURE_MB"

Añade las entradas opcionales que uses:

/container/envs/add list="ENVLIST" key=FLOOR_HZ value="FLOOR_HZ"
/container/envs/add list="ENVLIST" key=TRIGGERS value="TRIGGERS"
/container/envs/add list="ENVLIST" key=TOKEN value="TOKEN"

El valor de TOKEN se guarda en claro: trátalo como legible por cualquier usuario de RouterOS con read, y deja las demás credenciales fuera de la envlist.

/container/add remote-image="IMAGE_REF" interface="VETH" root-dir=ROOT_DIR envlist="ENVLIST" logging=yes start-on-boot=START_ON_BOOT restart-policy=on-failure restart-max-count=RESTART_MAX_COUNT restart-interval=RESTART_INTERVAL memory-max=MEMORY_MAX privileged=PRIVILEGED ignore-remote-image-change=yes comment="TAG"

RouterOS descarga la imagen de su propia arquitectura. El router tiene que llegar al registro y tener sitio en RAM para las capas.

Opcional: para llegar al agente en la dirección LAN del router, añade las dos reglas que escribe --expose (Exponer en la LAN). Necesitan un TOKEN en la envlist.

Escribe antes otra vez el manifiesto, para que las registre: expose=LAN_IP, token=yes y una línea object= por regla.

:local m "mikroscope-manifest=1\nname=NAME\ntag=TAG\ndisk=DISK\nveth=VETH\nsubnet=NET/30\nport=PORT\niface-list=IFACE_LIST\naddr-list=ADDR_LIST\nexpose=LAN_IP\ncontainer-name=CONTAINER_NAME\nremote-image=IMAGE_REF\ntoken=yes\ndir=MANIFEST_DIR\nfile=MANIFEST_FILE\nobject=/interface/veth name=VETH\nobject=/ip/address interface=VETH\nobject=/interface/list/member interface=VETH list=IFACE_LIST\nobject=/ip/firewall/address-list list=ADDR_LIST address=NET/30\nobject=/ip/firewall/nat chain=dstnat dst-address=LAN_IP dst-port=PORT protocol=tcp\nobject=/ip/firewall/filter chain=forward dst-address=AGENT_IP dst-port=PORT protocol=tcp\nobject=/container/envs list=ENVLIST\nobject=/container interface=VETH\ndir=ROOT_DIR\n"; :if ([:len [/file/find name="MANIFEST_FILE"]] > 0) do={ /file/set [find name="MANIFEST_FILE"] contents=$m } else={ /file/add name="MANIFEST_FILE" contents=$m }

Después añade las dos reglas:

/ip/firewall/nat/add chain=dstnat dst-address=LAN_IP protocol=tcp dst-port=PORT action=dst-nat to-addresses=AGENT_IP to-ports=PORT comment="TAG"
:local d [/ip/firewall/filter/find chain=forward action=drop]; :if ([:len $d] > 0) do={ /ip/firewall/filter/add chain=forward dst-address=AGENT_IP protocol=tcp dst-port=PORT connection-nat-state=dstnat action=accept comment="TAG" place-before=($d->0) } else={ /ip/firewall/filter/add chain=forward dst-address=AGENT_IP protocol=tcp dst-port=PORT connection-nat-state=dstnat action=accept comment="TAG" }
/container/start [find comment="TAG"]

En el router:

/container/print where comment="TAG"
/log/print where topics~"container"
:put ([/tool/fetch url="http://AGENT_IP:PORT/healthz" output=user as-value]->"data")

Tras una descarga del registro, RouterOS descarga y extrae la imagen antes de arrancar el contenedor. Hasta que el log muestra *** download/extract done, el contenedor muestra la marca E (DOWNLOADING/EXTRACTING) y la última orden imprime failure: Invalid argument: vuelve a ejecutar las tres.

Después el contenedor muestra la marca R (en marcha). El log termina con *** started /mikroscope-agent y la línea del propio agente, mikroscope-agent <version> …: kernel …, 10 Hz, ring 60 s, listening on AGENT_IP:PORT, …. La última orden imprime {"ok":true,…}. Desde un ordenador de la LAN del router, curl http://AGENT_IP:PORT/healthz responde lo mismo, y mikroscope status reconoce la instalación.

Ejecuta las retiradas, de la más nueva a la más antigua. La primera detiene y retira el contenedor, su raíz y su envlist; la última retira el manifiesto y el directorio MANIFEST_DIR cuando no queda nada más en él, y se detiene, conservando el manifiesto, si queda algún objeto con la etiqueta. Si expusiste el agente, retira antes sus dos reglas:

/ip/firewall/filter/remove [find chain=forward dst-address="AGENT_IP" dst-port="PORT" protocol="tcp" comment="TAG"]
/ip/firewall/nat/remove [find chain=dstnat dst-address="LAN_IP" dst-port="PORT" protocol="tcp" comment="TAG"]

Después el resto:

:local had [:len [/container/find comment="TAG"]]; :do { /container/stop [find comment="TAG"] } on-error={}; :local s 0; :while (([:len [/container/find comment="TAG" running]] + [:len [/container/find comment="TAG" stopping]]) > 0 && $s < 30) do={ :delay 1s; :set s ($s + 1) }; /container/remove [find comment="TAG"]; :local i 0; :while ([:len [/container/find comment="TAG"]] > 0 && $i < 20) do={ :delay 1s; :set i ($i + 1) }; :if ($had > 0) do={ :local r 0; :while ([:len [/file/find name="ROOT_DIR"]] > 0 && ([:len [/container/find root-dir="/ROOT_DIR"]] + [:len [/container/find root-dir="ROOT_DIR"]]) = 0 && $r < 10) do={ :delay 1s; :set r ($r + 1) }; :if ([:len [/file/find name="ROOT_DIR"]] > 0 && ([:len [/container/find root-dir="/ROOT_DIR"]] + [:len [/container/find root-dir="ROOT_DIR"]]) = 0) do={ :do { /file/remove [find name="ROOT_DIR"] } on-error={} } }; :if ([:len [/container/envs/find list="ENVLIST" key="MIKROSCOPE_TAG" value="TAG"]] > 0) do={ /container/envs/remove [find list="ENVLIST" key!="MIKROSCOPE_TAG"]; /container/envs/remove [/container/envs/find list="ENVLIST" key="MIKROSCOPE_TAG" value="TAG"] }
/ip/firewall/address-list/remove [find list="ADDR_LIST" address="NET/30" comment="TAG"]
/interface/list/member/remove [find interface="VETH" list="IFACE_LIST" comment="TAG"]
/ip/address/remove [find interface="VETH" comment="TAG"]
/interface/veth/remove [find name="VETH" comment="TAG"]
:if (([:len [/ip/firewall/address-list/find comment="TAG"]] + [:len [/interface/list/member/find comment="TAG"]] + [:len [/ip/firewall/nat/find comment="TAG"]] + [:len [/ip/firewall/filter/find comment="TAG"]] + [:len [/ip/firewall/raw/find comment="TAG"]] + [:len [/ip/firewall/mangle/find comment="TAG"]] + [:len [/ip/route/find comment="TAG"]] + [:len [/container/mounts/find comment="TAG"]] + [:len [/ip/address/find comment="TAG"]] + [:len [/interface/veth/find comment="TAG"]] + [:len [/interface/list/find comment="TAG"]] + [:len [/disk/find comment="TAG"]] + [:len [/container/find comment="TAG"]] + [:len [/container/envs/find list="ENVLIST" key="MIKROSCOPE_TAG" value="TAG"]]) > 0) do={ :error "mikroscope: objects tagged TAG remain, so MANIFEST_FILE stays" }; :if ([:len [/file/find name="MANIFEST_FILE"]] > 0) do={ :if ([:typeof [:find [/file/get [find name="MANIFEST_FILE"] contents] "\ntag=TAG\n"]] = "num") do={ :if ([:len [/file/find name="ROOT_DIR"]] > 0 && ([:len [/container/find root-dir="/ROOT_DIR"]] + [:len [/container/find root-dir="ROOT_DIR"]]) = 0) do={ :do { /file/remove [find name="ROOT_DIR"] } on-error={} }; /file/remove [find name="MANIFEST_FILE"] } }; :if ([:len [/file/find name~"^MANIFEST_DIR/"]] = 0) do={ /file/remove [find name="MANIFEST_DIR" type="directory"] }

Si todavía queda un tar porque la extracción agotó el tiempo, retíralo también: /file/remove [find name="IMAGE_FILE"]. Después comprueba que no queda nada; esto imprime 0:

:put ([:len [/interface/veth/find comment="TAG"]] + [:len [/ip/address/find comment="TAG"]] + [:len [/interface/list/member/find comment="TAG"]] + [:len [/ip/firewall/address-list/find comment="TAG"]] + [:len [/ip/firewall/nat/find comment="TAG"]] + [:len [/ip/firewall/filter/find comment="TAG"]] + [:len [/container/find comment="TAG"]] + [:len [/container/envs/find list="ENVLIST"]] + [:len [/file/find name="MANIFEST_FILE"]])

mikroscope uninstall --router … --yes hace lo mismo desde un ordenador con la CLI, y lo verifica: Actualizar y desinstalar.