While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Introduction

In this article we’ll use the Docker Plugin for Visual Studio Code. Docker allows us to package our applications into images and run them as containers on any platform that has Docker installed. We’ll use this plugin with two developer stacks: Node.js and Go.

Installation

You need to have docker installed on your work station. Instructions on how to install and run docker are available here, and it should be specific to the particular operation system you are running.

You also need to have Visual Studio Code installed.

Once you have Visual Studio Code installed, open it click on the extensions section on the left most pane, and search for Docker.
VS Code with left panel open showing Docker plugin

Once installed, you should notice a few new things in your Visual Studio Code instance. On the left most pane, there’s a new Docker section with the Docker logo, which when clicked opens the Docker Explorer with three sections. Images, Containers, Registries
The Docker Explorer panel

There are also a few commands added to the command palette, which you can view by opening the command palette and typing in docker
Docker typed into the command palette showing the commands available.

Node.js

We’ll use a Node.js application to demonstrate the capabilities the Docker plugin adds to VSCode.

Let’s create an Express server.

  • mkdir docker-node
  • cd docker-node
  • npm init -y
  • npm install --save express
  • touch index.js

We should have a directory tree like this:

.
├── index.js
├── node_modules
├── package-lock.json
└── package.json

1 directory, 3 files

This is the content of index.js

index.js
const express = require('express')
const app = express()

app.listen(3000)

app.get('/', (req, res) => {
  res.send('hello world')
})

Update package.json to have a start script.

package.json
"scripts": {
    "start": "node index.js"
  },

Now, we can simply run this app with npm start, and go to port 3000 and see the app working.

Traditionally, to add Docker, we would follow these steps.

  1. Create a Dockerfile (or docker-compose.yaml)
  2. Add docker instructions to the file (FROM, WORKDIR, ADD, EXPOSE, CMD)
  3. Run docker build... on the terminal to build the image
  4. Run docker run... on the terminal to run the container

With the plugin however, all we need to do is the following.
Open the command palette, and type in docker, then select Docker: Add Docker files to Workspace. It should be the first option. Press Enter
Selecting "Add Docker Files to Workspace"
You will be asked to choose the platform/stack, select Node.js and press Enter.
Selecting Node.js
You will then be asked to choose a port. Write 3000 since it’s the port our app will listen to.
Adding in the port number, 3000
The following files are added to your workspace: .dockerignore, docker-compose.debug.yml, docker-compose.yml, and Dockerfile.
Files listed in your workspace

The .dockerignore tells docker to ignore the files listed when adding files to the build image.

The docker-compose.debug.yml will allow you to run docker-compose with inspect, and attach a debugger.

version: '2.1'

services:
  docker-node:
    image: docker-node
    build: .
    environment:
      NODE_ENV: development
    ports:
      - 3000:3000
      - 9229:9229
    command: node --inspect=0.0.0.0:9229 index.js

If you are debugging during development though, you may need to attach a volume so that changes you make on your local machine are persisted in the container.

The docker-compose.yml file is a standard docker-compose file used to run docker-services. When you add other resources/services such as database connections and load balancers, you’ll edit this file.

version: '2.1'

services:
  docker-node:
    image: docker-node
    build: .
    environment:
      NODE_ENV: production
    ports:
      - 3000:3000

The Dockerfile, which is the most important here, since it has to be built, contains the instructions we would have to write manually if we did not have the plugin installed.

FROM node:8.9-alpine
ENV NODE_ENV production
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
RUN npm install --production --silent && mv node_modules ../
COPY . .
EXPOSE 3000
CMD npm start

Next, to build the Image, open the VS Code command palette, and type in docker then select Docker: Build Image and press Enter.
Selecting Docker Build Image
You’ll be prompted to select the Dockerfile, choose it and press Enter.
Selecting the Dockerfile
Next you’ll be prompted to select the tag. Leave the default docker-node selected and press Enter.
Leaving docker-node as the selection
The Integrated Terminal will open, and the build logs will show.
Build logs showing after the docker-build command

Finally, we need to run the container. Once again, open the command palette and type in docker run, the select Docker: Run
docker run typed into the command palette
A list of all containers in your system will show up, select docker-node:latest, the one we tagged, and press Enter.
selecting docker-node
The terminal will show the logs for the run command.
logs output after the docker run command
Notice it added the -p 3000:3000 exposing the port to our host machine so that we can run the application by visiting localhost:3000.

We can also run the container by going to the left pane, selecting the Docker section, then under Images, choose the docker-node image, right click and click on run.
under the docker-node menu, menu with "run" highlighted
The same logs will run on the terminal.

You’ll also notice that the images section above has a list of the images in your system. Once the docker-node container is running, We can check the running containers in the same section, and even stop them.
under docker-node registries the "Attach Shell" option is selected
Above, Attach Shell is selected, which is equivalent to the docker command below.

  • docker exec -it <container> sh

This shows the below terminal log output.

docker exec command executed with file output

You can see we’re in the container and we can list the files inside the container.

Stop the container, and try running the app with docker-compose. Open the command palette, find docker-compose and see the output.

Go

If you are not familiar with Golang, you can skip to the next topic.

Docker is also built with Go

Let’s create a Go App.

  • mkdir docker-go
  • cd docker-go
  • touch main.go

Your directory tree will have one file.

.
└── main.go

0 directories, 1 file

Here’s the content for the main.go file.

main.go
package main

import (
    "log"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello World"))
}

func main() {
    http.HandleFunc("/", helloHandler)

    if err := http.ListenAndServe(":9000", nil); err != nil {
        log.Fatalln("ListenAndServer Error", err)
    }
}

You can run the App with:

  • go run main.go

Let’s however use the VSCode Docker plugin to build an image and run the container.

Create the Dockerfile by opening the command palette, typing in Docker and selecting Docker: Add Dockerfile to Workspace.

You will be prompted to select a platform, choose Go and press Enter.
Selecting Go from the Application Platform menu

You’ll then be prompted to select a port, write in port 9000, since it’s the port we chose on our app, and press Enter.
Selecting the port by entering "9000"

The following 4 files will be created. .dockerignore, docker-compose.debug.yml, docker-compose.yml, and Dockerfile.
The files created under the Docker-Go Application

The .dockerignore file tells Docker to ignore some files when adding files to the image.

The docker-compose.debug.yml and the docker-compose.yml are used by Docker Compose to run the app. They are not that much different, since the debug file requires additional input, as debugging Go is more complex.

The Dockerfile here is however the most interesting bit. The last two lines of the build stage are commented out and added RUN go install -v ./...

# RUN go-wrapper download   # "go get -d -v ./..."
# RUN go-wrapper install    # "go install -v ./..."
RUN go install -v ./...

Here’s the final docker file.

#build stage
FROM golang:alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN apk add --no-cache git
# RUN go-wrapper download   # "go get -d -v ./..."
# RUN go-wrapper install    # "go install -v ./..."
RUN go install -v ./...

#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /go/bin/app /app
ENTRYPOINT ./app
LABEL Name=docker-go Version=0.0.1
EXPOSE 9000

This type of Dockerfile pattern is called multi-stage build, and it’s main advantage is optimization of Docker images. It’s mostly useful for compiled languages, which in most cases doesn’t require the compilation tools to run the compiled app. Go is a good example.

In a nutshell, we use part of the Docker build to compile the app, then copy the compiled binary to a lighter Docker image, and run it from there.

Next we need to build the image. Open the command palette, and type in docker-build, select Docker: Build Image and press Enter.

You’ll be prompted to select the Dockerfile, leave the default selected and press Enter.

Finally, you’ll be ask to pick an image tag. Leave the default docker-go:latest and press Enter.
Selecting the docker-go:latest image
You’ll see the build logs in the integrated terminal.

Lastly, we need to run the container. Open the command palette and type in docker run. Select Docker: Run and press Enter.
selecting docker Run in the command palette
You’ll be prompted to select the image. Select docker-go:latest.
selecting docker=go:latest for the image
You’ll see the logs in the Integrated Terminal.
logs in the output following  the command running
Like before, you can also run the container by selecting the Docker section in the left pane, and under containers, select docker-go, right click on click Run.
Selecting "Run" from the Images panel
You’ll then see the same docker run logs.

Since our our running Docker container only had the binary, we can attach the shell, in the containers section.
In the Containers section of the
We can the type in ls in the attached shell in the Integrated Terminal, and we’ll see a binary file called app, which corresponds to the Dockerfile.
running `ls` in the integrated terminal with the app file listed

Other Features

We’ll finally look at other helpful features that come with the VSCode Docker plugin.

Docker inspect images: This allows you to inspect the images built and see the details in a JSON file.

Select the image you want and open the context menu, and select inspect image.
Selecting the Go image and inspect image from the dropdown
A JSON file will be opened with the details.
JSOn file witht he details of the image

Show container logs: This is also found in the context menu for running containers. We’ll use the running Node.js container
Selecting "show logs" from the dropdown
The logs will be shown in the Integrated Terminal.
logs showing in the terminal

Registries: You can log in to your Docker registry and see the images you’ve built and pushed.

System Prune: This option allows you to run docker system prune, which clears unused images your system. It’s available via the button with the windows and a cross in the Docker explorer.
The System Prune option selected in the Docker Explorer menu

Intellisense: If you have to write the Docker files (Dockerfile, docker-compose.yml) yourself, you’ll get useful intellisense when typing.
User typing with Intellisense providing suggestions
It will even give you available image tags. This is triggered by typing in the image name, then a full colon, and CMD + Space.
Image tags listed after typing command + space

Dockerfile Linting: When you have an error in your Dockerfiles, a squiggly line will appear in VS Code and when you hover over it, you’ll be shown what the error is.
error typed in with line highlighting the error and suggestions

The problems tab below VS Code will also show it.
Problems tab selected with the issues listed

Conclusion

The Docker plugin for VS Code can help you quickly set up and create your Dockerfiles, build them and run them, without typing many of the commands yourself.

0 Comments

Creative Commons License