# Where things go

Where each object `install` creates lives on the router, which disk holds the image and the root, what the envlist carries, and the container settings install writes.

Source: https://jmrplens.github.io/mikroscope/install/layout/

This page answers where `install` puts things: the addresses, the disk that
holds the image and the container root, what goes into the envlist and nothing
else, and the settings the container is created with. Every value here is what
`mikroscope plan` prints for your flags, so the plan is the way to check it for
your router before anything is written.

## The objects and their defaults

| Object         | Default                                                                                                              | Flag                                         |
| -------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| veth + /30     | `veth-mikroscope`, `172.30.10.0/30` (router `.1`, agent `.2`)                                                        | `--veth`, `--subnet`                         |
| router address | `172.30.10.1/30` on the veth                                                                                         | derived from `--subnet`                      |
| image tar      | `<name>.tar`, uploaded with `scp`, **deleted right after extraction**; none at all with `--remote-image`             | `--disk`, `--ephemeral`, `--remote-image`    |
| container root | `mikroscope/<name>` on the internal flash                                                                            | `--disk tmpfs` for a RAM disk, `--ephemeral` |
| envlist        | `<name>-env`                                                                                                         | `--rate`, `--buffer`, `--port`, `--token`, … |
| tag            | `mikroscope:<name> (managed by mikroscope)` on every object that takes a comment; as `MIKROSCOPE_TAG` in the envlist | `--name`, default `mikroscope`               |

`--subnet` must be an IPv4 /30 given at its network address; the router takes
`.1` and the agent `.2`. `--name` is up to 32 characters and `--veth` up to 64,
letters, digits, `_`, `.` and `-`, starting with a letter or digit. The default
/30 and veth name were chosen not to collide with a hand-installed sampler on the
reference device; if `172.30.10.0/30` is in use on yours, pick another.

With `--disk`, the image and the root move together: `<disk>/<name>.tar` and
`<disk>/mikroscope/<name>`. The value is a RouterOS disk slot: empty for the
internal flash, `tmpfs`, `disk1`, `usb1` and so on.

## Persistent or ephemeral

**Persistent is the default**: the root on the internal flash,
`start-on-boot=yes`, and `restart-policy=on-failure` bounded to five retries
ten seconds apart, so a broken image cannot loop at boot.

**`--ephemeral`** puts the tar and the root on the router's tmpfs disk, if it has
one — the RB5009 does — with `start-on-boot=no`: zero flash writes, and nothing
survives a reboot. Verified on RB5009UG+S+, RouterOS 7.24.2, 2026-09-11:
`write-sect-since-reboot` read 58 279 before the install and 58 279 after the
removal — the same value, not a small increase. With `--ephemeral` on a router that has no tmpfs disk, `doctor`
reports it missing and names the command that adds one.

`--disk tmpfs` without `--ephemeral` also puts both on the tmpfs disk, but keeps
`start-on-boot=yes`; only `--ephemeral` changes the boot setting.

> **Untested**
>
> Reboot survival, in either mode: the reference router is production and is not rebooted for tests.

## Why the tar is deleted at install

RouterOS extracts the image when the container is added, so once the container
exists the tar has no further use. A tar left on the device is what `uninstall`
would later have to find in a `/file` index that lagged for minutes after a
container removal. So `install` waits up to 15 s for the container to appear,
then 3 s more, deletes the tar, and only then starts the container. It does not
check that the extraction finished; on the RB5009 a 1.8 MiB tar was extracted
within the same second as the add (RouterOS 7.24.2, 2026-09-11).

The container is created with `ignore-remote-image-change=yes`. With the
default `no`, RouterOS watched the image and, once the tar was removed, stopped
and removed the container and re-extracted it minutes later (RB5009UG+S+, RouterOS 7.24.2, 2026-09-11).

Until the tar is deleted, it and the root extracted from it share the disk,
which is why `doctor` asks for twice the image plus 4 MiB of free flash.

With `--remote-image` none of this happens. RouterOS pulls the layers itself,
no tar lands on the device, there is nothing to wait for and nothing to delete,
`doctor` asks for the 4 MiB alone, and `uninstall` has no file to account for —
the container's ownership count is the container and the envlist. The container
root still goes where `--disk` and `--ephemeral` say.

## What the envlist carries

The envlist holds the agent's configuration and the ownership marker, and
nothing else:

The entries install writes into the agent's envlist:

| Key | Written | From | Holds |
| --- | --- | --- | --- |
| `MIKROSCOPE_TAG` | always | `--name` | the ownership marker `mikroscope:<name> (managed by mikroscope)`, written first and removed last; the agent ignores it |
| `RATE_HZ` | always | `--rate`, default `10`, 1–100 | the sampler rate, in Hz |
| `BUFFER_S` | always | `--buffer`, default `300`, 10–3600 | the ring's length, in seconds |
| `PORT` | always | `--port`, default `9123`, 1–65535 | the agent's HTTP port |
| `ADDR` | always | `--subnet` | the agent's address, the `.2` of the /30; the agent binds only there |
| `MEM_LIMIT_MB` | always | `--mem-limit-mb`, default `40`, 8–1024 | the agent's Go soft memory limit, in MiB |
| `FLOOR_HZ` | only when above 0 | `--floor-hz`, default `0`, 0–1000 | one cadence for every level source, in Hz |
| `CAPTURE_MB` | always | `--capture-mb`, default `4`, 0–256 | the triggered-capture budget, in MiB; `0` turns captures off |
| `TRIGGERS` | only when set | `--triggers` | the trigger conditions; unset, the agent uses its default set |
| `TOKEN` | only when set | `--token` | the bearer token the agent requires, from `--token` or `MIKROSCOPE_TOKEN`, with or without `--expose` |

No sink address, no sink token and no API credential goes into it. Any RouterOS
user with `read` can list every container's envlist over the API (verified
on RB5009UG+S+, RouterOS 7.24.2, 2026-09-11), so what is written here is readable by all of them — the token
included, when you set one. The plan prints the envlist with the token masked as
`(token)`. [What runs where](/mikroscope/security/) says which credential lives
where; the agent reads more variables than `install` writes, and
[Environment variables](/mikroscope/reference/environment/) lists them.

## The container settings

The container is added with:

- `file=` the uploaded tar, or `remote-image=` the reference without its
  registry host when the router pulls it;
- `interface=` the veth, `root-dir=` the root, `envlist=` the envlist, and the tag
  as its comment;
- `logging=yes`, so what the agent prints reaches the router log;
- `start-on-boot=yes`, or `no` with `--ephemeral`;
- `restart-policy=on-failure restart-max-count=5 restart-interval=10s`;
- `memory-max=64M`, enforced as the container's cgroup limit (`--memory-max`);
- `privileged=yes` (`--privileged=false` to opt out), which drops the
  container's user namespace so the kernel log, `/proc/slabinfo` and the MTD ECC
  counters are readable, and does not widen its network or PID namespace —
  [What privileged buys](/mikroscope/limits/privileged/) has the detail;
- `ignore-remote-image-change=yes`, for the reason above.

The agent catches SIGTERM: RouterOS kills a container that does not,
immediately. It honours the default stop time of 10 s.

## Size the memory to the ring

`--memory-max` and `--mem-limit-mb` have to move with `--rate` and `--buffer`.
The ring holds `rate × buffer` lines of about 2.4 kB each; the Go soft limit
wants about twice that and has to sit comfortably under `memory-max`. The
agent's startup check counts 2 560 bytes a line plus `--capture-mb`: above
`memory-max` it refuses to start, and above half of `--mem-limit-mb` it warns. The defaults, 40 MiB under
`64M`, are sized for 10 Hz and a 300 s ring. The triggered-capture budget
counts against both limits in that check, as the ring does.

The measured runs used `--mem-limit-mb 40 --memory-max 64M` at 10 Hz, `--buffer 120 --mem-limit-mb 64 --memory-max 96M`
at 50 Hz and `--buffer 120 --mem-limit-mb 80 --memory-max 128M` at 100 Hz. What a tight limit costs is on
[The cost of the observer](/mikroscope/cost/); the runs themselves are on
[The rate ceiling](/mikroscope/cost/rate-ceiling/).

## See also

- [Installing the agent](/mikroscope/install/): the order these objects are created in, and how
  they are removed.
- [The rate ceiling](/mikroscope/cost/rate-ceiling/): what each rate costs with the memory flags
  above.
- [What privileged buys](/mikroscope/limits/privileged/): the one container setting that is a real
  privilege grant.
- [What runs where](/mikroscope/security/): what else can read the envlist.
