Container-based development with toolboxcutter

Container-based development with toolboxcutter

Toolbx is a tool for Linux systems, specifically Fedora, that creates and manages development environment containers. Its purpose is to group development dependencies in a mutable container separate from the base operating system both for the benefit of separating concerns and allowing dev. environments to be reused and shared.

The toolbx project was originally named toolbox and the command reflects this.

Typical usage might look like this:

[user@hostname ~]$ toolbox create
Created container: fedora-toolbox-36
Enter with: toolbox enter
[user@hostname ~]$ toolbox enter

While this may provide the foundation of a compelling development workflow, I felt something was missing. From my perspective, a development environment is specific to the project being developed.

So, you could use toolbox like this:

[user@hostname ~]$ cd my-project
[user@hostname my-project]$ toolbox create my-project-toolbox
[user@hostname my-project]$ toolbox enter my-project-toolbox

And proceed to install dev. dependencies in your container, but I want a toolbox that can be created and recreated on-demand, from a Dockerfile, for example. It then makes sense to commit this dev. environment manifest to your project so that your environment's specifications follow your project's development. Ultimately, what I sought was a means to more easily manage per-project toolboxes, which prompted the creation of toolboxcutter.

toolboxcutter

toolboxcutter (invoked as tb) is a script that manages the lifecycle of per-project development containers using Dockerfiles.

It began life as a zsh function, but as its feature set expanded, I realized it had become a project of its own, so I ported it to a standalone bash script.

It's designed to be easy to use. Within a directory containing a toolbox-based Dockerfile, simply run tb and your toolbox will be entered, creating the container if necessary.

Install it on Fedora with these commands:

dnf copr enable jcrd/toolboxcutter
dnf install toolboxcutter

A complete overview of its functionality is given in its command-line usage message:

usage: tb [command]

With no command, enter toolbox.

commands:
  init IMAGE      Initialize Dockerfile based on IMAGE
  create [IMAGE]  Create container (from IMAGE if provided)
  recreate        Remove and recreate container
  build           Build image
    options:
      -n NAME       Name of image
      -c            Build without cache
  rebuild         Remove container and rebuild image
    options:
      -n NAME       Name of image
      -c            Build without cache
  stop            Stop container
  rm              Remove container
  rmi             Remove image
  rpkg            Build rpm via rpkg
    options:
      -n NAME       rpkg spec template name
      -e EXT        rpkg spec template extension
  rpkg-install    Build and install rpm via rpkg
    options:
      -n NAME       rpkg spec template name
      -e EXT        rpkg spec template extension
      -r NAME       Name of produced rpm to install
  run COMMAND     Run COMMAND in toolbox
  version         Show version

As tb is largely a wrapper around toolbox, most of its commands translate directly to their toolbox equivalents. These are supplemented with image and container management commands that would otherwise require invoking podman.

Building RPM packages

Unique to toolboxcutter is its ability to build RPM packages from rpkg SPEC template files. This feature has been instrumental in the development, testing, and dogfooding of my own projects while using Fedora. I believe it elevates tb to a truly powerful developer tool for these reasons:

  • Build dependencies need only exist in your project's container, minimizing pollution of your workstation's environment;

  • Most importantly, the development-packaging cycle is combined into a single fluid process, providing interactivity benefits similar to that of a read-eval-print loop.

This functionality depends on the availability of rpkg in the toolbox container itself, so your project's Dockerfile should install it. This is the Dockerfile for the base image I use:

FROM registry.fedoraproject.org/fedora-toolbox:36

RUN dnf install -y git-subtree
RUN dnf install -y make
RUN dnf install -y neovim
RUN dnf install -y rpkg # Install rpkg
RUN dnf install -y rpmdevtools
RUN dnf install -y zsh

CMD /usr/bin/zsh

Any images or containers derived from this can be used to build RPM packages provided a SPEC template. By default, tb looks for this file at spec/*.rpkg.spec in your project's root directory.

Here is toolboxcutter's own SPEC template file:

Documentation about the format of these templates is sparse and much of my knowledge was gleaned from existing files. Nevertheless—perhaps with a bit of trial and error—it is possible to run tb rpkg-install in your project's directory to produce an installable RPM package with your latest changes!