This blog post is the second in a three-part series about the Visual Studio Code Remote – Containers extension. The first post went over the benefits and general concepts of using a container for development work on a project. This post will go over some instructions on how to implement this for a project, basic setups, and configurations that can be helpful to get started, along with some use cases. The last post will go into further details on some more advanced topics and settings that can be configured in the dev container, along with some things to look out for when setting it up for a project.
Getting Started and Installation
Installation is quite simple and easy, however, there are a few requirements needed before this can be implemented and taken advantage of, which can be found here. The two main requirements are having Docker Desktop (or equivalent) installed and choosing a
glibc based Linux docker image to build off of. Current support for
musl based Alpine Linux is limited due to most other VS Code extensions being compiled natively for
x86. More information about this matter can be found here.
Along with the requirements listed above, the only other items needed to get this implemented into a project are two files in a directory in the root of the project.
Dockerfile can be set up to be very simple. Either choose to use an already existing image or use that as a starting point and build on top of that. Here is an example of a Ruby project that will use a slightly modified
This example uses the official Ruby image from DockerHub. On top of that base image, a few gems are installed and updated to the latest version available. These gems coincide with some of the extensions that will be installed further along in this post.
In addition to the
Dockerfile, the development container needs to have a
devcontainer.json file that will be used to further configure the development environment. This file is used to launch the container and specify any extensions and settings to install once the container is up and running. Additionally, a developer can define a set of post-create commands to be run to also aid in the setup of the development container environment.
Here is an example of what a
devcontainer.json file might look like for a Ruby project.
This example comprises six main items, each is described in a bit more detail below.
name– Defines the name for the development environment.
dockerFile– Points to the location of the
Dockerfilethat will be used to launch the container. This is the same file that was listed above in the Dockerfile examples.
appPort– Sets the port number that the container will run on. VS Code uses this port to connect and communicate with the container when it is launched.
extensions– Defines a list of extensions to be installed into the container. These can be individual extensions or extension packs. These are installed into the development environment on top of what has already been installed on the user’s local system.
settings– Defines the settings for the extensions and the code editor. Similarly, these settings are applied to the development environment in addition to what the user has defined in their local setup.
postCreateCommand– Specifies a command or set of commands that are run after the container is up and running.
Watch Your Path
The example above showed a few ways where paths can be set in the settings for the extensions. It is important to define these according to the proper paths and locations from the container. Without it, the coding environment won’t be able to fully utilize particular extensions and the developer can be greeted with warning and error messages stating that certain commands or functionalities are unable to be located.
Spaces vs Tabs
Each project can be set up with its own individual settings and preferences. One of these often debated preferences can be the use of spaces or tabs when formatting the code. The container can have this item already configured that way when a developer starts working on the project they don’t have to worry about which format to follow.
Furthermore, a project can greatly benefit from having custom settings that can be used to assist a developer with creating code. For example, a project that relies heavily on creating CloudFormation templates can utilize a combination of a
yaml extension and setting up some custom tags that are often used when creating these templates. Additionally, the project can depict the use of using single-quotes over double-quotes in YAML files as well.
Custom Command Execution using postCreateCommand
Properly allocating the
postCreateCommand is an essential part of the
devcontainer.json file. This item will run a command or list of commands after the container is created. This is particularly useful for running commands or even scripts from within the project to get a complete development environment setup without any interaction or commands from the user. For example, running
bundle install for the Ruby project to run through and install all the necessary gems from the projects defined
Rebuilding Container and Applying Changes
It is easy to implement and test changes to the Docker image and container settings. Anytime there are changes to the container configuration files,
devcontainer.json, a rebuild will be needed. For example, adding additional gems, extra
RUN commands to install into the container image, or even just adding some
runArgs or adding another script to the post-create command will require a rebuild of the container for the changes to take into effect. VS Code will prompt the user to rebuild the container when it notices changes in those files while launching into the dev environment.
Or the user can invoke a rebuild of the container from the Command Palette.
Now Go Wild With Configurations
These examples show that it doesn’t take much to get a completely custom development environment running for a project with already built-in tools and pre-configured settings. It was easy to get something simple going for the config-lint project. There were three main reasons to push for the use of the VS Code Remote – Containers dev environment. The first was to avoid the
Go dependency issues that several developers encountered when they started working on the project. Getting modules installed from the start without any action needed from the developer was also important. To help with further limiting the sparse bugs and errors that came with deploying the project, it was important to set up a working development environment that matched the actual CI/CD pipeline. Resolving the installation and dependency issues with getting a developer’s local systems setup just right took extra time that is much better well spent on actual coding work for the project itself.
The final post in this series will go into further detail about enabling and using more advanced features within the development container. The aim is to provide a real-world example where this is implemented with greater customization for the cfn_nag project that allows developers to start working on the project in minutes.
Stelligent Amazon Pollycast