Setup and usage

Setup

You need to have the devcontainers/cli command line tool installed into your execution path. For that you need a working node/npm setup. Then you can install the tool with

npm install -g @devcontainers/cli

Of course you also need a working docker installation and probably also docker. Alternatively you can also use podman.

Usage

Activate devcontainer-mode

In order to use devcontainers you should activate devcontainer-mode. It is a global major mode that recognizes if a project needs or supports devcontainers and then automatically forwards commands to the devcontainer.

Commands

There are couple of commands to start and stop devcontainers. They are pretty straight forward.

Launching the devcontainer devcontainer-up

devcontainer-up starts the devcontainer of the current project. Usually you would use it to start the devcontainer, when you start working on a project after relaunching your computer. You’ll get a notification in the echo area as soon as the container is launched. In order to examine failures you can examine the buffer *devcontainer startup*.

If the startup of the container needs secrets to access resources like package dependencies you can define a file where these secrets are stored in devcontainer-startup-secrets-file.

If there is no image for the container available on your system it is built according the the project’s devcontainer definition. Note that this command does not rebuild the container. Nothing will be updated. The software state will be the same as when the container has been built lastly.

Restarting the container

devcontainer-restart stops and restart the devcontainer of the current project without rebuilding it. There is actually one rare use case and that is when the container reached a state which can only or easiest be reset by a reastart.

devcontainer-rebuild-and-restart stops the current project’s devcontainer, deletes its docker images and rebuilds it. This is useful, when you for example changed the Dockerfile of your devcontainer. However, it also does not rebuild or update the containers that are defined as other services in docker-compose.yml in the project’s devcontainer definition.

Starting programs inside the devcontainer

devcontainer-execute-command executes an arbitrary command inside the devcontainer. This is meant for long running, non-interactive commands like running a server or some kind of batch job. When called interactively it prompts for a command.

devcontainer-execute-command-interactive execute an arbitrary command inside the devcontainer interactively. This is meant for interactive commands that you would run in a terminal. When called interactively it prompts for a command.

devcontainer-term provides a terminal for a shell inside the container. By default it tries to launch the bash shell. You can customize that by the devcontainer-term-shell. If you experience wired control sequences in your terminal you might want to adjust the TERM variable inside the container using

(setq devcontainer-term-environment '(("TERM" . "xterm-256color")))

Forwarding commands that are not using compile

If you need to forward some process call into the devcontainer which is not done by the compile command of Emacs, you can use devcontainer-advise-command to prepend the devcontainer exec call in front of your command. If you are not sure if devcontainer is always available you can use the following call, which modifies your command if devcontainer is available and if the command modification is advisable.

(funcall (or (symbol-function 'devcontainer-advise-command) #'identity) command)

Using TRAMP

An alternative way of using the package is to edit the files inside the container itself using Emacs’ builtin TRAMP facility. There are pros and cons to it. In order to use it, you can let devcontainer-mode deactivated and use the function devcontainer-tramp-dired to open a dired window inside the container. Then you can open files of your project inside the container.

If devcontainer-mode is activated it refrains from advising compile functions, if the current buffer is a file inside the devcontainer.

Customizations of the devcontainer

Devcontainers can demand customizations to the user’s IDE. That is useful to ensure that all the IDEs of all the teams members are aligned. Whereas in the VSCode world you can also request extension packages to be installed when working on the devcontainer driven project, this Emacs package only allows you to set Emacs variables and call Emacs functions when opening a file that belongs to a devcontainer driven project.

Customizations are defined in the customization section of devcontainer.json file. For every IDE supporting devcontainers can there can be a subsection. To set variables for buffers of the project you can use the emacs subsection. In order to set the variable fill-column you can use the following example.

{
    ...
    "customizations": {
        "emacs": {
            "fill-column": 79
        }
    }
}

Also mode specific settings are possible. The following example sets fill-column to 79 for text-mode, to 88 for python-mode and to 80 for all other modes.

{
    ...
    "customizations": {
        "emacs": {
	    "modes": {
		"text-mode": {
		    "fill-column": 79
		},
		"python-mode": {
		    "fill-column": 88
		}
            },
	    "fill-column": 80
	}
    }
}

Note that derived modes are also affected from those settings if they don’t override it. In the above example the fill-column is also set to 79 in markdown-mode as markdown-mode is a derived mode of text-mode.

In order to perform commands as customization you can use lisp commands as variable name and letting the value null like so:

{
    ...
    "customizations": {
        "emacs": {
	    "(auto-fill-mode -1)": null
        }
    }
}

So theoretically you could perform complicated lisp code there and even install packages. However it is strongly discouraged to do anything more than setting variables and ensuring that minor modes are switched on or off.

This customization mechanism in principle allows authors of the project to perform any lisp code on you Emacs. That is a potential security risk. So you can decide if you want to trust projects that you work on or not. You can do that setting devcontainer-apply-customization.