Developing go applications inside of a container with vscode.
Prerequisites:
Create a .devcontainer
folder in the root of your project directory:
.devcontainer
├── .env
├── devcontainer.json
├── docker-compose.yml
└── Dockerfile
The .devcontainer
folder will contain four files.
The .env
file:
REDIS_HOST=redis
REDIS_PORT=6379
This file can be used to define any number of env variables. These environment variables will be automatically loaded and made available from within the dev container when it starts. Use the container's terminal to confirm the environments are set by using the printenv
command. Once the container has been created you'll need to rebuild it for changes made to this file to be seen.
The .devcontainer.json
file:
{
"name": "godev",
"workspaceFolder": "/workspace",
"dockerComposeFile": [
"docker-compose.yml"
],
"service": "godev",
"postStartCommand": "go version",
"customizations": {
"vscode": {
"settings": {
"workbench.colorTheme": "Solarized Dark"
},
"extensions": [
"golang.go",
"ms-azuretools.vscode-docker"
]
}
}
}
This file contains the settings that vscode will use to create the dev container. It references a standard docker compose file that's used to create any services required by your project. In addition to the standard docker features it will also configure vscode to use any extensions required by your project. You can think of this as a throw away environment that is created from scratch when you're ready to work and thrown away when you're done with it.
To learn more about the options available visit the containers.dev website.
The docker-compose.yml
file:
version: '3'
services:
godev:
container_name: godev
build:
context: ../
dockerfile: ./.devcontainer/Dockerfile
env_file:
- .env
volumes:
- ${HOME}/.ssh:/root/.ssh:ro
- ../:/workspace:cached
- /var/run/docker.sock:/var/run/docker.sock
redis:
container_name: redis
image: redis:7.2-alpine
This is a standard docker compose file. It creates two containers for our project. The main go container and redis. You may not need redis, but it's here for sake of the example and shows how to use multiple services. The dev container will only attach to the service referenced within the devcontainer.json
file when it starts. Additional services defined within the docker compose file will be available on your docker network as usual.
To learn more about the options available visit the docker compose file website.
The Dockerfile
file:
FROM golang:1.22
RUN apt-get update && \
# Go tools:
# - https://github.com/golang/tools
# - https://github.com/golang/vscode-go/blob/HEAD/docs/tools.md
go install -v golang.org/x/tools/gopls@latest && \
go install github.com/cweill/gotests/gotests@latest && \
go install github.com/fatih/gomodifytags@latest && \
go install github.com/josharian/impl@latest && \
go install github.com/haya14busa/goplay/cmd/goplay@latest && \
go install github.com/go-delve/delve/cmd/dlv@latest && \
go install honnef.co/go/tools/cmd/staticcheck@latest && \
go install golang.org/x/tools/cmd/godoc@latest && \
go install gotest.tools/gotestsum@latest && \
# Go vulnerability checker:
# https://go.dev/security/vuln/
go install golang.org/x/vuln/cmd/govulncheck@latest && \
# Graphviz for visualizing go test pprof profiles.
apt-get -y install graphviz && \
# Docker cli
curl -fsSL https://get.docker.com -o get-docker.sh && \
sh get-docker.sh
ADD . /workspace
WORKDIR /workspace
CMD ["sleep", "infinity"]
This file will create the golang container. It will pre-install tooling that is used by the vscode go extension. It will also install the docker cli within the container which allows you to access docker containers running on the host machine from within the container by using the docker extension or the docker
cli.
To learn more about available options visit the docker file reference website.
If you've made it this far you're now able to open your project directory within vscode and when doing so will be prompted to reopen it within the devcontainer. It may take a few minutes the first time, but on subsequent loads it will be faster since the container image(s) will already be available within the docker cache.
Now you're ready to get going with go!
What's the point of this? All the benefits of docker alongside single click initialization of your entire dev environment. When you’re done working throw it all away until you need to work on the project again. It’s decoupled from the local machine and isolated.
It’s a game changer if you work on multiple projects, have multiple workstations, use a remote machine to work, or just want to share a consistent workspace with your team. Also makes onboarding easy, because they just open the project and immediately get the same exact tooling used by the existing team.
It goes beyond just having services start with a docker compose file. It’s all the additional project specific settings that are available which can be committed to a repository. Also having the ability to define post create, post start, post attach, shutdown commands, ide extensions that only exists on the remote instead of being installed locally and persisting on your machine when you bounce between projects that don’t need them, port labels and attributes; even less important things like themes.
The way I use vscode is with no extensions installed. I define everything in the devcontainer.json
file per project this way I have what I need, but only when it’s needed. I do this for go, php, javascript, etc as it varies. The other advantage comes from when you have multiple workstations. Everything stays in sync.
Been using devcontainers for years now and love it. I’m convinced it will catch on as JetBrains makes progress on implementing it as well. They were trying to create a competing spec, but seems they have finally caved and decided to support it.