Stelligent

Development Acceleration Through VS Code Remote Containers: Setting Up a Foundational Configuration

Photo by Steve Johnson from Pexels

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 glibc and 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

The 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 Dockerfile.

See the gist on github.

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.

 

devcontainer.json

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.

See the gist on github.

This example comprises six main items, each is described in a bit more detail below.

 

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.

See the gist on github.

 

YAML Extension

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.

See the gist on github.

 

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 Gemfile.

See the gist on github.

 

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, Dockerfile or 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