97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
+
-
+
+
-
-
-
+
+
+
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
|
That brings us to the related matter of…
[script]: https://help.mikrotik.com/docs/display/ROS/Scripting
# <a id="run"></a>There Is No “Run”
Although RouterOS 7.21 did add a `/container/run` command, it is not the same thing as `docker run`, shorthand for creating and starting a container in a single step. It requires you to `add` the container first, then `run` the named command inside the stopped container. This makes it closer to `docker exec` in behavior, which requires that you `docker create` a container from the OCI image first.
Although RouterOS 7.20 did add an [equivalent to Docker’s `exec` command](#exec), it still lacks a `run` equivalent, being shorthand for creating and starting a container in a single step. Moreover, the lack of Linux-like interactive terminal handling — covered [below](#terminal) — means a simple command like…
Moreover, the lack of Linux-like interactive terminal handling — covered [below](#terminal) — means a simple command like…
$ docker run --rm -it alpine:latest
…followed by…
sh-5.1# <do something inside the container>
sh-5.1# exit
…may end up expressed under RouterOS as…
> /container
> add remote-image=alpine:latest veth=veth1 entrypoint=sleep cmd=3600
> print
…wait until container extracts…
> add remote-image=alpine:latest veth=veth1 entrypoint=echo cmd=hi
> print interval=1
…wait until container downloads and extracts…
^C
> start 0
… wait for it to launch…
> shell 0
sh-5.1# <do something inside the container>
sh-5.1# exit
> stop 0
> remove 0
Whew! 😅
Prior to the enhancements to `/container/print` in RouterOS 7.20, the sequence could be even longer because you needed to manually give the command repeatedly until the runtime entered a settled state, else the `shell` command would fail.
Without that `interval=1` loop, the sequence can be even longer because you might need to manually give the `print` command repeatedly until you see the `S` flag appear, indicating that the runtime is ready to process the `shell` command.
RouterOS 7.20 also added the `interactive` and `tty` flags to `/container/run` which means you can change that sequence to:
What has _not_ changed in RouterOS 7.20 is the need for that “sleep 3600” hack. We need it in order to work around the lack of interactive mode in `container.npk`, without which containers of this type will start, do a whole lot of _nothing_, and then stop. We must give it some type of busy-work to keep it alive long enough to let us shell in and do our actual work. This sneaky scam is a common one for accomplishing that end, but it has the downside of requiring the user to predict how long you want the container to run before stopping; this version only lasts an hour.
> /container
> add remote-image=alpine:latest veth=veth1
> print interval=1
…wait until container downloads and extracts…
^C
> start 0
… wait for it to launch…
> run alpine cmd="echo hi"
hi
> stop 0
> remove 0
While that is a _bit_ shorter, keep in mind the one-liner it is replacing:
If you are imagining more complicated methods for keeping containers running in the background when they were designed to run interactively, you are next liable to fall into the trap that…
$ podman run alpine echo hi
# <a id="cmd"></a>The Host-Side Command Line Parser Is Not Bash
Because the RouterOS CLI isn’t a Bourne family shell, you do not get identical parsing as when typing `docker` commands into a Linux terminal. They added basic string splitting for the `cmd` argument in 7.20, so that this now works:
> /container add remote-image=docker.io/library/alpine name=alpine
|
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
|
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
|
-
+
-
+
-
-
+
-
-
+
-
|
$ docker exec CONTAINER ls -lR /etc
$ ssh myrouter '/container/shell cmd="ls -lR /etc" 0'
That is to say, they each pass a multi-argument command to `/bin/sh` inside the container, if it exists, which then parses the command and executes it within the container’s confines.
Prior releases lacked the `cmd` parameter, limiting you to an interactive `/container/shell` call.
Even under RouterOS 7.20, the following will fail:
RouterOS 7.21 enhanced that by adding the `/container/run` command:
> /container
> add remote-image=docker.io/library/alpine
> add remote-image=docker.io/library/alpine veth=veth1
> start 0
> shell cmd="ls -lR /etc"
> run alpine cmd="ls -lR /etc"
This container is configured with `/bin/sh` as its entrypoint. Couple that with the container creator’s assumption that you are running it under “`docker run -it`” or similar, and you have a recipe for trouble. RouterOS will dutifully run the shell on getting the `start` command, but the subsequent `shell` call will fail because there is no interactive terminal attached: lacking any source of input, the shell immediately exits, leaving no running container for the `shell` command to attach to. One must resort to [ugly hacks](#run) to work around this type of problem.
It is uncertain from the change logs where the `cmd` space-splitting was added, without which the runtime goes looking for a command literally named “`ls -lR /etc`”, but there remains the problem that the RouterOS CLI [is not Bash](#cmd).
Mind, that `shell` command _will_ work for a container that has a background process configured as its default entrypoint, since it remains running, avoiding the need for the ugly hack.
## <a id="export"></a>`export`/`save`
There is no way to produce a tarball of a running container’s filesystem or to save its state back to an [OCI] image tarball.
The [documented advice][imgtb] for getting such a tarball is to do this on the PC side via `docker` commands, then upload the tarball from the PC to the RouterOS device.
|