README
¶
Open Devcontainer
Open Devcontainer is an open source, spec-compliant implementation of Visual
Studio Code's Development Container toolkit. It aims to fully implement the
devcontainer.json specification, as well as providing additional developer
tooling that the VS Code Remote - Containers extension provides, such as SSH and
GPG forwarding and automatic dotfiles installation.
Status
This tool is in beta. It is stable enough for regular use in development, but its usage may change in the future.
Installation
Pre-built releases
There are pre-built releases for Linux, macOS, and Windows:
https://gitlab.com/smoores/open-devcontainer/-/releases
To install the latest release with wget:
$ PLATFORM=macos # or windows or linux
$ ARCH=amd64 # or arm64
$ wget -O odc https://gitlab.com/api/v4/projects/33929624/packages/generic/odc/latest/${PLATFORM}-${ARCH}
$ chmod +x ./odc
$ sudo install ./odc /usr/local/bin/ # or ~/.local/bin/, etc
For macOS users
If you download the odc binary with a web browser, the first time you run
odc on macOS, it may notify you that the package is "unsafe", because it isn't
signed with an Apple Developer ID. To allow macOS to run the program anyway,
open "System Settings", navigate to the "Privacy & Security" panel, and click
"Allow Anyway":

For more information about macOS's Gatekeeper, you can read this article.
Building from source
Assuming you have go installed:
$ git clone https://gitlab.com/smoores/open-devcontainer
$ cd open-devcontainer
$ go build -o odc main.go
$ sudo install ./odc /usr/local/bin/ # or ~/.local/bin/, etc
Usage
Open Devcontainer is an open source implementation
of the VS Code Devcontainer spec. It supports creating, maintaining,
and running container-based development environments.
Usage:
odc [command]
Available Commands:
attach Attach a tty to a running devcontainer
completion Generate the autocompletion script for the specified shell
exec Execute a command in a running container
help Help about any command
rm Remove a workspace's devcontainer
run Start a devcontainer for a workspace, creating it if needed
stop Stop a running devcontainer
Flags:
--config string config file (default is $HOME/.config/odc.json)
-h, --help help for odc
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
Use "odc [command] --help" for more information about a command.
Manifest files
Every odc command relies on a manifest file to identify the devcontainer to
operate on. Most commonly, these manifest files will live in
<project-root>/.devcontainer/devcontainer.json, and this is where odc looks
by default. This means that if you run odc from the project root, you likely
do not need to pass a --manifest flag, which is the expected use case.
Manifest files must follow the devcontainer.json specification.
Configuration
Any command line flags other than --manifest can be configured with a config
file instead. odc looks for config files in your $XDG_CONFIG_HOME directory
on XDG-compliant systems (this usually defaults to $HOME/.config on Linux
distros), and falls back to $HOME/.config on Linux and macOS. On Windows,
odc will look in C:\Users\<your username>\AppData\Roaming\ODC\Config.
odc uses Viper for config file parsing. This
means you can format your config file however you like: JSON, TOML, YAML, HCL,
envfile and Java properties config files are all supported.
For example, on a macOS system, using JSON config:
$HOME/.config/odc.json
{
"shell": "/usr/bin/fish"
}
Commands
run
Creates, starts, and sets up a new devcontainer for a
workspace. Containers are identified by a hash of the absolute
path to the manifest file for the workspace. If a container already
exists is or running, 'odc run' will skip those steps.
If provided, the 'run' command will clone and install a dotfiles
repo. This can be used for personalizing the devcontainer, since
dotfiles configuration is not part of the devcontainer.json manifest
itself. See https://dotfiles.github.io/ for more information about
dotfiles repos.
The '--sublime-text-compat' flag enables "Sublime Text Compatibility
Mode". This will override the workspaceFolder configuration, if there
is one, and mount the working directory at the same path as it is locally,
so that it will be compatible with the Sublime LSP plugin.
Usage:
odc run [flags]
Flags:
--dotfiles-repo string An optional dotfiles repository to install
--dotfiles-target string Where to install the dotfiles repository
-h, --help help for run
--sublime-text-compat Enables Sublime Text LSP compatibility mode
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
attach
Run an interactive shell in a running devcontainer.
This command will fail if a devcontainer hasn't already been
started for this workspace. See 'odc run' for more information
about starting new devcontainers.
By default, /bin/bash is used as the interactive shell. To choose
a different shell, use the '--shell' flag to pass a path to a
different shell executable.
When attaching to a container, odc will attempt to forward the
host's gpg and ssh agents to the container by forwarding
the gpg and ssh unix sockets to tcp ports bound to the container,
and forwarding from the tcp ports to the container's gpg and ssh
unix sockets.
Usage:
odc attach [flags]
Flags:
-h, --help help for attach
-s, --shell string The shell to use in the attached container (default "/bin/bash")
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
forward
Forward a port for a workspace's container. Port forwarding
is different from publishing a port with the docker engine. Services
running in the container will receive connections on forwarded ports
as if they were coming from localhost.
If the specified port is already bound on the host, odc will increment
the port number until it finds a free port, and forward that to the
initially requested port on the container. For example, for the
command "odc forward --port 3000", if 3000 is already bound on the
host, but 3001 is free, odc will map port 3001 on the host to port
3000 on the container. odc will always print the port mappings after
running "odc forward".
Docker doesn't support dynamically updating containers, including
dynamically publishing ports. Instead, odc forwards ports by running
an alpine/socat container on the same network as the workspace container,
and using socat to forward connections from the host to the workspace
container.
Usage:
odc forward [flags]
Flags:
-h, --help help for forward
-p, --port uint16 The port to forward
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
exec
Execute a command in a running container.
This command will fail if a devcontainer hasn't already been
started for this workspace. See 'odc run' for more information
about starting new devcontainers.
The command will be executed in a shell environment, so
environment variables are available.
Usage:
odc exec [flags]
Flags:
-h, --help help for exec
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
stop
Stop a running devcontainer
Usage:
odc stop [flags]
Flags:
-h, --help help for stop
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
rm
Removes a devcontainer for a given workspace. If
the container is still running, this command will fail unless
the '--force' flag is passed.
Usage:
odc rm [flags]
Flags:
-f, --force Remove the container even if it's running.
-h, --help help for rm
Global Flags:
--config string config file (default is $HOME/.config/odc.json)
-m, --manifest string Path to the devcontainer.json file (default ".devcontainer/devcontainer.json")
Editor integrations
Terminal-based editors
For terminal-based editors, like vim/NeoVim or Emacs, you can simply run and attach to your devcontainer, install your editor, and start developing:
/h/u/c/my-project (main) $ odc run
/h/u/c/my-project (main) $ odc attach
# These commands are now executing in the container
/w/my-project (main) $ sudo apt update && sudo apt install neovim
/w/my-project (main) $ nvim .
Most likely, however, you have some specific configuration (plugins,
keybindings, etc) that you rely on for your development workflow. We recommend
using a dotfiles repo to track your editor configuration. You can read more
about dotfiles repos as a concept here. To use one
with odc:
/h/u/c/my-project (main) $ odc run --dotfiles-repo https://github.com/your-gh-username/dotfiles
/h/u/c/my-project (main) $ odc attach
# These commands are now executing in the container. `odc` will have run the
# `install` script in your dotfiles repo, so our editor is already installed
# and configured!
/w/my-project (main) $ nvim .
Emacs GUI mode
If you prefer to run Emacs as a standalone GUI application, rather than in a terminal, you can use Tramp to connect to the running container. Many Emacs plugins (including Eglot) work seamlessly over Tramp connections.
When opening a file, simply prefix with /docker:odc- and use Tab-complete to
see the available odc managed containers. Your files will be in
/workspaces/your-project-folder-name within the container, unless you've
specified an alternative workspaceFolder or workspaceMount.
Sublime Text
At the moment, connecting the Sublime Text LSP Plugin to a language server running in a container is a bit cumbersome, but it's possible! We hope to improve this flow in the future.
Start your devcontainer. Make sure to enable "Sublime Text Compatibility Mode", which will ensure that your working directory mount has the same path in your container as it does on your machine, which is necessary for compatibility with Sublime LSP.
# You can also set { "sublime-text-compat": true } in your odc.json
$ odc run --sublime-text-compat
Now, make sure you have the LSP Plugin installed in Sublime Text. If not, open the Command Palette, and execute "Package Control: Add Package", and install "LSP".
Once the LSP Plugin is installed, open the Command Palette again and execute
"Preferences: LSP Settings". This will open a new preferences pane. Here, we'll
patch the client configuration for gopls:
// Settings in here override those in "LSP/LSP.sublime-settings"
{
"clients": {
"gopls": {
"enabled": true,
// It doesn't matter which port you run your language server on,
// but remember it for the next step!
"command": ["odc", "exec", "gopls serve -listen 0.0.0.0:16670"],
"selector": "source.go",
"tcp_port": 16670
}
}
}
This will tell Sublime LSP to run gopls inside of your odc container,
listening on the port that you opened in your devcontainer.json earlier.
Now, forward the port that your language server is listening on from your host machine:
$ odc forward --port 16670
That's it; after you save your preferences file, everything should be working correctly.
VS Code
You don't really need to use odc with VS Code; VS Code's Remote - Containers
extension works great!
If you're interested, though, this fairly easy to set up.
- Start a dev container with
odc run, as demonstrated above - Install the Remote - Containers extension for VS Code
- Open the new "Remote Explorer" in the left sidebar in VS Code
- Under "Other Containers", you'll see your
odccontainer. You might have to hover over the sha256 identifiers to see the container names; look for one prefixed withodc-your-directory-name- - Right click and select Attach to Container
- Once VS Code is attached, open the File Explorer and choose "Open Folder".
Your code will be mounted at
/workspaces/your-directory-nameif your manifest doesn't specify aworkspaceMountorworkspaceFolderoverride.
Code Server
odc will install Coder's
code-server, an open source fork
of VS Code, in your development container if you use the --code-server flag
with odc run. You can include this in your odc.json file if you'd like to
always have code-server available in your development servers.
odc will run code-server on port 4002 in the container, and forward it to
the same port on the host. You can then access code-server from your browser
at localhost:4002!
Supported features
Image or Dockerfile specific properties
- image
- dockerfile
- context
- build
- appPort
- containerEnv
- containerUser
- mounts
- workspaceMount
- workspaceFolder
- runArgs
Docker compose specific properties
- dockerComposeFile
- service
- runServices
General properties
- name
- forwardPorts
- portsAttributes
- otherPortsAttributes
- remoteEnv
- remoteUser
- updateRemoteUserUID
- userEnvProbe
- overrideCommand
- shutdownAction
- features
Lifecycle scripts
- initializeCommand
- onCreateCommand
- updateContentCommand
- postCreateCommand
- postStartCommand
- postAttachCommand
- waitFor
Additional features
- SSH agent forwarding
- GPG agent forwarding
- Automatic dotfiles installation
- Custom shell
- git config mirroring
- Variable interpolation
- viper integration
- Dynamic port publishing
Documentation
¶
Overview ¶
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.