Skip to content

Latest commit

 

History

History
161 lines (110 loc) · 8.09 KB

README.md

File metadata and controls

161 lines (110 loc) · 8.09 KB

mkdev: consistent, isolated development

mkdev is a personal collection of OCI-compliant container image boilerplates for managing isolated development environments using GNU Make.

It enables a consistent, open, and extensible workflow by using Containerfile and Makefile as the standard points of entry. Dependencies and tools are packaged in a custom container, providing isolation and replicability of the development environment while still integrating with the $EDITOR on the host system.

"Don't let the development dependency hell mess with your files and processes. Containerize the development environment!" — Tower Guardian, in a new take.

release ci/cd conventional commits

Example of resources on host system:

  • GNU Make
  • Container Engine
  • $EDITOR
  • Git
  • OpenPGP subkeys (for signing and pushing commits)
  • Project source files

Example of resources on development container:

  • Language Runtime
  • Language Compiler
  • LSP
  • Linter
  • Test suite
  • Dependencies
  • Any other necessary SDK tooling
  • Project source files (binded from host using make start)

Requirements

Tip

Basic familiarity with container engines (e.g., Podman, Docker), OCI Image (Containerfile), and GNU Make is recommended.

  • Container Engine
  • GNU Make

Usage

Setup

  1. Create a .mkdev directory at the root of the project or environment. Only files within this path will be shared with the container.
  2. Copy the appropriate files from the boilerplates directory into the .mkdev directory—for example, the ansible-fedora development environment. Clone the mkdev repository to streamline this process.
  3. Move the Makefile from the .mkdev directory to the root of the project or environment.
  4. Edit the Makefile and adjust variables with changeme values. These variables are used for naming, managing, and running the container.

Per-project example

project/
├── .mkdev/
│   ├── Containerfile
│   ├── README.md
│   ├── dnf.txt
│   └── pip.txt
└── Makefile

Multi-project (omni) example

repositories/
├── .mkdev/
│   ├── Containerfile
│   ├── README.md
│   ├── apt.txt
│   ├── npm.txt
│   └── go.txt
├── project1/
├── project2/
├── project3/
└── Makefile

Commands

Default commands on host system

  • make dev: Build the container image defined in .mkdev/Containerfile.
  • make start: Start the mkdev container, passing the current working directory as a bind mount.
  • make stop: Stop the mkdev container.
  • make clean: Remove the mkdev container and its artifacts. Executes the distclean target first.
  • make serestore: Restore project files context on SELinux host systems.

Custom commands inside the container

  • make lint: Run linters.
  • make test: Run tests. Executes the lint target first.
  • make build: Build the project. Executes the test target first.
  • make run: Run the project. Executes the build target first.
  • make deploy: Deploy the project. Executes the build target first.
  • make debug: Run debugging tasks. Executes the test target first.
  • make distclean: Clean artifacts.

Workflow

asciicast

Side notes

Run and compose

If a project requires additional containers, enable it by uncommenting the compose command in the start target. Ensure that the same network is applied in both the run command and the container compose file.

Git and GPG

Since Git configuration and OpenPGP keys aren't shared with the containers, all Git operations and GPG signing must happen on the host system. This ensures sensitive information stays separate from the development environment, which is my preferred approach.

Per-project and multi-project (omni)

The main difference between the per-project and omni boilerplates is that the omni use a shared volume for the ~/.local directory in the container, where non-root packages and dependencies are installed. This allows dependencies to persist across container runs, eliminating the need to rebuild the image when project dependencies change or update.

For sharing and occasional contributions, the per-project approach offers an isolated development environment with all the necessary tools for ephemerally working on a specific project.

For personal and frequent use, the multi-project (omni) approach can be more beneficial, as it enables sharing common dependencies and tools across multiple projects. For example, a single omni container provides access to all my Git repositories and contains all the languages and tooling that I regularly use.

GNU Emacs

To run programs from containers in Emacs on host system, TRAMP needs to search the correct paths. Since the boilerplates define the least required access for non-root packages, TRAMP's default mechanism (getconf PATH + TRAMP standard paths) might not always locate the tools, so some additional parentheses are needed.

The following configuration adds ~/.local/bin, the default location for non-root programs in the boilerplates, to TRAMP’s search paths. It also includes tramp-own-remote-path, which adds the remote user’s assigned path on supported shells:

(add-to-list 'tramp-remote-path (expand-file-name ".local/bin" (getenv "HOME")))
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)

Helpful commands:

  • tramp-cleanup-all-buffers: Kills all remote buffers, useful for preventing TRAMP warnings when stopping containers.
  • tramp-cleanup-all-connections: Flushes all TRAMP objects (its caching), handy after changing configuration.
  • project-forget-project: Removes a directory from the project list, useful for preventing TRAMP warnings related to remote zombie projects.

Compatibility

Any IDE that supports opening files and executing binaries within a container's file system should work with the boilerplates. However, since Emacs is my preferred $EDITOR, the boilerplates are specifically created and tested with it in mind.

In worst-case scenarios, SSH protocol can also be used.

Contributing

In case of unexpected behavior, please open a bug report.

For matters requiring privacy, such as security-related reports or patches, check the security policy.

To contribute to mkdev boilerplates, see the project guidelines.

Mailing list

Email workflow is also available.

Feel free to send patches, questions, or discussions related to mkdev to the ~ttybitnik/general mailing list.

License

This project is licensed under the GNU General Public License v3.0 (GPL-3.0), unless an exception is made explicit in context. See the COPYING file for more information.

Be aware that the resulting container images may include other software subject to additional licenses, such as the base operating system, shells, and any direct or indirect dependencies of the software being contained. As with any built container image, it is the user's responsibility to ensure their use of the image complies with all relevant licenses for the software contained within.

The source code for this project is available at https://github.com/ttybitnik/mkdev.