Visual Studio Code now offers the ability to use a docker container as a fully fledged development environment with the introduction of the Remote Containers extension.
Workspace files are made accessible from inside a container which can also host the tools relevant to the development environment, leaving VS Code acting as a remote UI to enable a 'local quality' development experience:
The obvious benefit here is the ability to very rapidly spin up a development environment through the use of pre-existing containers which already provide all required components.
Starting Up
First thing to do is create the config files that will tell VS Code how to configure the environment; this can be done by executing 'Add Development Container Configuration Files' (Ctrl + Shift + P):
This will create devcontainer.json and Dockerfile files under .devcontainer within the workspace.
The Dockerfile defines the container that Code will create and then connect to for use as a development environment. A bare bones Dockerfile for use with a Node app may look like this:
FROM node:slim USER node
devcontainer.json defines how VS Code should work with a remote container. A simple example below shows how to reference the Dockerfile:
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/typescript-node { "name": "TriggerService", "build": { "dockerfile": "Dockerfile", }, "settings": { "terminal.integrated.shell.linux": "/bin/bash" }, "extensions": [ "dbaeumer.vscode-eslint", "ms-vscode.vscode-typescript-tslint-plugin" ], "remoteUser": "node" }
With both of these files in place, VS Code will prompt to re-open in the container environment (or use the command palette to execute 'Reopen in Container'):
Once started up, an indicator in the bottom left shows that VS Code is currently connected to a container:
Create a Simple App
At this point VS Code is now connected to the node:slim container as configured in the Dockerfile.
Because this image provides everything needed to start developing a Node application, we can start by using npm to install Express:
npm init -y npm install express
Then create index.js under the src folder:
const express = require( "express" ); const app = express(); const port = 8080; // define a route handler for the default home page app.get( "/", ( req, res ) => { res.send( "Hello world!" ); } ); // start the Express server app.listen( port, () => { console.log( `server started at http://localhost:${ port }` ); } );
Next we need to update the package.json file to set the main entry point and start command:
{ "name": "test-app", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { "start": "node .", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" } }
Now executing the following command from the terminal will start up the application inside the container:
npm run start
The key thing to note here is that we stood up this simple Node app without ever having to actually install Node on our host system; everything was pulled down via the node:slim docker image.
At this point the application is exposed on port 8080, so can be accessed at http://localhost:8080.
What's Next?
We have only covered enough here to get up and running, barely scratching the surface of what can be done with remote containers.
Next up, debugging from inside a container, and using docker compose to handle spinning up multiple containers.