toolbox(1)

πŸ’… NAME πŸ’…

toolbox β€” a script to start a toolbox container for system debugging 🧰✨

(it's toolbox(1) from the User Manual, bestie β€” part 1 of 2, keep scrolling)


🌸 SYNOPSIS 🌸

toolbox [[-h/--help] | [list|create [<name>]|enter [<name>]|run|stop
[<name>]] [-r/--root] [-u/--user] [-n/--nostop] [-S/--sandbox]
[-P/--no-pull] [[-R/--reg <registry>] [-I/--img <image>]|[-i/--image
<image_URI>]] [-X/--runtime <runtime_bin>] [[-t/--tag
<tag>]|[-c/--container <name>]] [command_to_run]]

✨ DESCRIPTION ✨

Okay so picture this: you're on a system using transactional-update, and the root filesystem is read-only πŸ”’. Which means installing tools to analyze problems in the currently running system? Not really possible β€” any reboot is always required. And that makes debugging basically impossible 😭.

Enter toolbox πŸ‘‘: a small script that launches a podman container in a rootless or rootfull state to bring in debugging or admin tools. Main character energy, honestly.

The root filesystem can be found at /media/root. And in a "user toolbox" (i.e., one started with toolbox -u), the user's home directory is available in the usual place (/home/$USER) 🏠.

The following options are available in toolbox:

  • -h or --help β€” shows the help message 🫢
  • -u or --user β€” run as the current user inside the container
  • -n or --nostop β€” do not stop the container on exit, which lets you have multiple sessions to the same toolbox (lowkey iconic)
  • -R or --reg <registry> β€” explicitly specify the registry to use
  • -I or --img <image> β€” explicitly specify the image to pull
  • -i or --image <image> β€” full URI of the image to pull (the alternative to -R -I)
  • -r or --root β€” runs podman via sudo as root
  • -t or --tag <tag> β€” add <tag> to the toolbox name
  • -c or --container <name> β€” fully replace the toolbox name with <name> (the alternative to -t)
  • --podman-args <args> β€” pass addition args to the podman command

The following variables can be overridden by setting them in ${HOME}/.toolboxrc:

  • REGISTRY β€” the registry to pull from. Default value is: registry.opensuse.org.
  • IMAGE β€” the image and tag from the registry to pull. Default value is: opensuse/toolbox.
  • TOOLBOX_NAME β€” the name to use for the local container. Default value is: toolbox-${USER}.
  • TOOLBOX_SHELL β€” standard shell if no other commands are given. Default value is: /bin/bash.

Example .toolboxrc file:

REGISTRY=my.special.registry.example.com
IMAGE=debug:latest
TOOLBOX_NAME=special-debug-container
TOOLBOX_SHELL=/bin/bash

If a config file is found, with REGISTRY and IMAGE defined, ${REGISTRY}/${IMAGE} is used, overriding the default ✨. If -R and/or -I (or -i) is/are used they override both the defaults and the content of REGISTRY and/or IMAGE from the config file. And heads up 🚨 β€” if an alternate image is used, the REGISTRY and/or IMAGE needs to be specified with every toolbox call. No skipping, bestie.


πŸŽ€ CONFIGURATION FILES πŸŽ€

Beside the user configuration file, there are two additional system wide configuration files:

  • /usr/share/toolbox/toolboxrc β€” distribution specific configuration file
  • /etc/toolboxrc β€” system specific configuration file created by a system administrator

The configuration files are read in the order: /usr/share/toolbox/toolboxrc, /etc/toolboxrc, /.toolboxrc. The last value is used. Order matters, periodt πŸ’…


πŸ¦‹ ALTERNATIVE COMMANDS πŸ¦‹

It is possible to interact with toolbox using a command based interface such as:

  • create β€” creates a toolbox, but does not "enter" inside of it
  • enter β€” enter a toolbox (creating it, if it does not exist, in our case)
  • run β€” run a command / start a program inside a toolbox
  • list β€” show existing toolboxes, although for now it is basically an alias to podman ps -a
  • stop β€” (it's in the synopsis, so it's a whole command, iykyk)

This commands imply user mode (-u) and uses a different container (toolbox-<user>-user vs. toolbox-<user>) πŸ‘€


🌈 ROOTLESS 🌈

By default a toolbox is a rootless container. Which means being root inside the toolbox itself does not map with being root on the host β€” think file permissions, access to special files, etc. All of that. Important caveat, ngl.

Rootless Usage Example

$ id
uid=1000(dario) gid=100(users) groups=100(users),496(wheel),1000(dario)
$ toolbox
Container 'toolbox-dario' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario')
toolbox-dario
Container started.
Entering container. To exit, type 'exit'.
toolbox-dario:/ # id
uid=0(root) gid=0(root) groups=0(root)
toolbox-dario:/ # ls -alF /media/root
total 88
drwxr-xr-x   1 65534 65534   256 Sep 12 10:33 ./
drwxr-xr-x   3 root  root     48 Jan 20 14:06 ../
drwxr-xr-x   1 65534 65534  1674 Dec 17 02:17 bin/
drwxr-xr-x   1 65534 65534   554 Jan 18 10:44 boot/
drwxr-xr-x  22 65534 65534  4300 Jan 19 22:22 dev/
toolbox-dario:/ # tcpdump -i em1
tcpdump: em1: You don't have permission to capture on that device
(socket: Operation not permitted)
toolbox-dario:/ # touch /media/root/etc/foo
touch: cannot touch '/media/root/etc/foo': Permission denied

See that? Root inside, but no host superpowers. It's giving "root in name only" πŸ’€


πŸ“ Rootless Usage Example, With User Setup πŸ“

In case a proper user environment is what one wants (e.g., for development), the -u (or --user) option can be used:

$ id -a
uid=1000(dario) gid=1000(dario) groups=1000(dario),...
$ toolbox -u
Container 'toolbox-dario-user' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario-user')
toolbox-dario-user
Container started.
Entering container. To exit, type 'exit'.
dario@toolbox-dario-user: > id
uid=1000(dario) gid=100(users) groups=100(users)
dario@toolbox-dario-user: > echo $HOME
/home/dario
dario@toolbox-dario-user: > ls -l /home
total 0
drwxr-xr-x 1 dario users 2290 Jan 20 14:33 dario

The user will have (paswordless) sudo access so, e.g., packages can be installed, etc:

$ ./toolbox -u
Container 'toolbox-dario-user' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario-user')
toolbox-dario-user
Container started.
Entering container. To exit, type 'exit'.
dario@toolbox-dario-user: > sudo zypper in gcc
Loading repository data...
Reading installed packages...
Resolving package dependencies...

The following 17 NEW packages are going to be installed:
  binutils cpp cpp9 gcc gcc9 glibc-devel libasan5 libatomic1 libgomp1 libisl22 libitm1 liblsan0 libmpc3 libtsan0 libubsan1 libxcrypt-devel linux-glibc-devel

17 new packages to install.
Overall download size: 42.6 MiB. Already cached: 0 B. After the operation, additional 179.7 MiB will be used.
Continue? [y/n/v/...? shows all options] (y):
dario@toolbox-dario-user: > which gcc
/usr/bin/gcc
dario@toolbox-dario-user: > sudo tcpdump -i em1
tcpdump: em1: You don't have permission to capture on that device
(socket: Operation not permitted)

Note the last bit πŸ‘€ β€” even with sudo, tcpdump still says no. That's the rootless thing doing its thing.


πŸ”₯ ROOTFUL πŸ”₯

In fact, toolbox called by a normal user will start the toolbox container but the root filesystem of the host cannot be modified, special devices cannot be accessed, etc. Running toolbox with sudo has the disadvantage, that the .toolboxrc in the root user home directory, and not the user's, is used. To run the toolbox container with root rights, toolbox --root (or -r) has to be used.

Rootfull Usage Example

$ id
uid=1000(dario) gid=100(users) groups=100(users),496(wheel),1000(dario)
$ toolbox -r
Spawning a container 'toolbox-dario' with image 'registry.opensuse.org/opensuse/toolbox'
08a8b984be2430a5d2cb38d55b26a93ddda3e5e5d183fbb75ac7287421a3f8be
toolbox-dario
Container created.
Entering container. To exit, type 'exit'.
toolbox-dario:/ # id
uid=0(root) gid=0(root) groups=0(root)
toolbox-dario:/ # ls -alF /media/root
total 88
drwxr-xr-x   1 root root   256 Sep 12 10:33 ./
drwxr-xr-x   1 root root     8 Jan 20 13:51 ../
drwxr-xr-x   1 root root  1674 Dec 17 02:17 bin/
drwxr-xr-x   1 root root   554 Jan 18 10:44 boot/
drwxr-xr-x  22 root root  4300 Jan 19 22:22 dev/
toolbox-dario:/ # tcpdump -i em1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on em1, link-type EN10MB (Ethernet), capture size 262144 bytes
13:54:52.843421 IP 192.168.0.9.46690 > 192.168.0.255.32412: UDP, length 21
13:54:52.843655 IP 192.168.0.9.59404 > 192.168.0.255.32414: UDP, length 21
toolbox-dario:/ # touch /media/root/etc/foo
toolbox-dario:/ # ls -la /media/root/etc/foo
-rw-r--r-- 1 root root 0 Jan 20 14:09 /media/root/etc/foo

Now that's the glow-up 🫢 β€” tcpdump actually captures, and the touch on /media/root/etc/foo slays instead of getting denied.


πŸ’œ ADVANCED USAGE πŸ’œ

bestie hold on β€” part 2 is loading, there's more coming ✨

πŸš€ Running a command/program inside a toolbox

So like, by default toolbox just yeets you into a shell inside the container. But bestie, you can also launch one specific command or program inside it instead β€” no shell detour, periodt:

$ toolbox -u sudo zypper in figlet
Container 'toolbox-dario-user' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario-user')
toolbox-dario-user
Container started.
Entering container. To exit, type 'exit'.
Loading repository data...
Reading installed packages...
Resolving package dependencies...

The following NEW package is going to be installed:
  figlet

1 new package to install.
Overall download size: 3.0 MiB. Already cached: 0 B. After the operation, additional 75.2 MiB will be used.
Continue? [y/n/v/...? shows all options] (y):
$ toolbox -u figlet Hey from toolbox!
Container 'toolbox-dario-user' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario-user')
toolbox-dario-user
Container started.
Entering container. To exit, type 'exit'.
 _   _               __
| | | | ___ _   _   / _|_ __ ___  _ __ ___
| |_| |/ _ \ | | | | |_| '__/ _ \| '_ ` _ \
|  _  |  __/ |_| | |  _| | | (_) | | | | | |
|_| |_|\___|\__, | |_| |_|  \___/|_| |_| |_|
            |___/
 _              _ _               _
| |_ ___   ___ | | |__   _____  _| |
| __/ _ \ / _ \| | '_ \ / _ \ \/ / |
| || (_) | (_) | | |_) | (_) \>  \<|_|
 \__\___/ \___/|_|_.__/ \___/_/\_(_)

Lowkey obsessed with that ASCII art ngl πŸ˜­πŸ’–

And fr fr, the command you run could even be a shell. But if you wanna use a different shell than the default one inside the toolbox, you can also just change the value of the TOOLBOX_SHELL variable in the config file. Easy.


🎨 CUSTOM IMAGE

toolbox ships with an openSUSE-based userspace environment called opensuse/toolbox by default, but bestie you can swap it for literally any container image πŸ’… Just override the environment variables in $HOME/.toolboxrc:

# cat  /.toolboxrc
REGISTRY=registry.opensuse.org
IMAGE=opensuse/toolbox:latest

Or, alternatively, use the -R and -I parameters like this:

$ toolbox -u -R registry.opensuse.org -I opensuse/tumbleweed:latest
Spawning a container 'toolbox-dario-user' with image 'registry.opensuse.org/opensuse/tumbleweed:latest'
b9b79fda84f1022112c0841f6b3711511a640391a9379adb4257b81a26887c0f
toolbox-dario-user
Setting up user 'dario' (with 'sudo' access) inside the container...
(NOTE that, if 'sudo' and related packages are not present in the image already,
this may take some time. But this will only happen now that the toolbox is being created)
Container created.
Entering container. To exit, type 'exit'.
dario@toolbox-dario-user: \> exit
dario@toolbox-dario-user: \>
exit
dario@Wayrath: /Documents/Work/Dario/SUSE\> podman ps -a
CONTAINER ID  IMAGE                                             COMMAND     CREATED             STATUS                      PORTS   NAMES
b9b79fda84f1  registry.opensuse.org/opensuse/tumbleweed:latest  sleep +Inf  About a minute ago  Exited (143) 3 seconds ago          toolbox-dario-user

Or you can just drop the full URI under the -i parameter, like toolbox -u -i registry.opensuse.org/opensuse/tumbleweed:latest. Chef's kiss πŸ§‘β€πŸ³πŸ’‹


🫧 Multiple Toolboxes

Okay so sometimes you want multiple toolboxes, especially user ones β€” like, maybe you want a special user toolbox where you do all your virtualization dev work. Iconic, honestly. You do this by adding a tag to a toolbox name via the toolbox --tag <tag> option:

$ podman ps --all
CONTAINER ID  IMAGE                                                             COMMAND               CREATED             STATUS                         PORTS  NAMES
b20985e6de68  registry.opensuse.org/opensuse/toolbox:latest                     /bin/bash             57 seconds ago      Exited (0) 3 seconds ago              toolbox-dario-user
$ ./toolbox -u
Container 'toolbox-dario-user' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-dario-user')
toolbox-dario-user
Container started successfully. To exit, type 'exit'.
dario@toolbox-dario-user: \>
dario@toolbox-dario-user: \> exit
$ ./toolbox -u -t virt
Spawning a container 'toolbox-dario-user-virt' with image 'registry.opensuse.org/opensuse/toolbox'
0dbfbe02b0201bee9ae3a53c66db70ab621eae914c013e0b2e7a34837adde527
toolbox-dario-user-virt
Setting up user 'dario' (with 'sudo' access) inside the container...
(NOTE that, if 'sudo' and related packages are not present in the image already,
this may take some time. But this will only happen now that the toolbox is being created)
Container started successfully. To exit, type 'exit'.
dario@toolbox-dario-user-virt: \>
dario@toolbox-dario-user-virt: \> exit
CONTAINER ID  IMAGE                                                             COMMAND               CREATED         STATUS                    PORTS  NAMES
0dbfbe02b020  registry.opensuse.org/opensuse/toolbox:latest                     /bin/bash             8 minutes ago   Exited (0) 6 minutes ago         toolbox-dario-user-virt
b20985e6de68  registry.opensuse.org/opensuse/toolbox:latest                     /bin/bash             10 minutes ago  Exited (0) 7 minutes ago         toolbox-dario-user

Two toolboxes, zero chaos. That's the vibe 🌈


⌨️ Alternative (Command Based) UI

When you're using the command-based interface, these basic operations are what go down:

  • Creating a user toolbox and entering inside it (equivalent of toolbox -u): toolbox create toolbox enter
  • Running a command inside a toolbox (equivalent of toolbox -u /usr/bin/foo): toolbox run ls /home/
  • Creating (and entering) a toolbox tagged as devel (equivalent of toolbox -u -t devel): toolbox create -t devel toolbox enter -t devel
  • Creating (and entering) a toolbox called tbx-apps (equivalent of toolbox -u -c tbx-apps): toolbox create -c tbx-apps toolbox enter -c tbx-apps

And the -r option can be used together with commands too, like this:

  • Creating a toolbox running as root, with your user inside (equivalent of toolbox -u -r):
toolbox create -r
toolbox enter -r
  • Running a command inside a toolbox that runs as root on the host and has your user configured in it (equivalent of toolbox -u -r /usr/bin/foo): toolbox create -r toolbox run -r ls /home/
Heads up bestie: that last working mode has no equivalent in containers/toolbox, where a toolbox running as the root user on the host must be started with sudo πŸ’€

πŸ” Automatically enter toolbox on login

Set an /etc/passwd entry for one of the users to /usr/bin/toolbox:

useradd bob -m -s /usr/bin/toolbox

Now when you SSH into the system as that user, toolbox just… starts itself. Main character energy ✨

# ssh bob@hostname.example.com
Last login: Thu Oct  3 16:52:16 2019 from 192.168.107.1
Container 'toolbox-bob' already exists. Trying to start...
(To remove the container and start with a fresh toolbox, run: podman rm 'toolbox-bob')
toolbox-bob
Container started successfully. To exit, type 'exit'.
toolbox-bob:/ #

🩹 TROUBLESHOOTING

😭 Podman can't pull/run images with user

If you wanna run toolbox without root privileges, you may need to add a range of UID and GID for the user. So if /etc/subuid and /etc/subgid are empty or straight-up don't exist, these commands can be used:

echo "podman_user:100000:65536" > /etc/subuid
echo "podman_user:100000:65536" > /etc/subgid

πŸ–₯️ GUI application can't connect to display

This happens if the user runs the container as root β€” with sudo, for example β€” while logged in as a user to the desktop environment. The easiest way out? Use toolbox -u to set up a "rootless toolbox" container for those cases. Slay, problem solved 🫢


And that's the whole page, bestie β€” you ate that πŸ’… This beauty is from the microos-toolbox fam, toolbox(1), dated October 2024. Go forth and containerize, queen πŸ‘‘πŸ’–

πŸ“¦ where this page comes from