Windows11+VSCode+Dev ContainersでGo環境を構築する手順をまとめます。前提条件として、WSL2、WSL Dockerのインストールが完了済みとします。Docker Desktopのライセンスがある場合や個人での利用の場合は通常のDocker Desktopを入れてもOKです。
環境
- プロセッサ 12th Gen Intel(R) Core(TM) i7-12700 2.10 GHz
- メモリ 64 GB
- OS Windows11 22H2 ビルド22621.1265
- VSCode 1.76
- Remote Development v0.24.0
- Dev Containers v0.282.0
- WSL
PS C:\> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
MSRDC バージョン: 1.2.3575
Direct3D バージョン: 1.606.4
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windowsバージョン: 10.0.22621.1265
- WSL Docker
Client: Docker Engine - Community
Version: 23.0.1
API version: 1.42
Go version: go1.19.5
Git commit: a5ee5b1
Built: Thu Feb 9 19:47:01 2023
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 23.0.1
API version: 1.42 (minimum version 1.12)
Go version: go1.19.5
Git commit: bc3805a
Built: Thu Feb 9 19:47:01 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.16
GitCommit: 31aa4358a36870b21a992d3ad2bef29e1d693bec
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
構築手順
1.VSCodeのRemote DevelopmentでWSL上の開発用ディレクトリを開く
2. ctrl+shift+pでコマンドパレットを表示し、devと入力、Dev Containers: Add Dev Container Configuration Files…を選択
3. goと入力し、最初に出た項目を選択
4. 1.19-bullseyeを選択
5. Select features画面はそのままEnterでスキップ。.devcontainersディレクトリとdevcontainers.jsonが生成される
6. ctrl+shift+pでコマンドパレットを表示し、reopenと入力。Rebuild and Reopen in Containerを選択
7. 開発コンテナがセットアップされ、環境構築完了!いかがでしたか?
何が入ったのか
一昔前は環境構築で何時間と費やしていたのに今はこんなに簡単に1環境が作れるなんて便利ですね。でもよしなにやってくれて何が起きたかわからないので、詳しく見ていくことにします。まず、ウィザード形式で作られたdevcontainer.jsonの中身は下のようになっています。
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:0-1.19-bullseye"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
各キーの意味は以下の通りのようです2。
キー | 意味 |
name | dev containerの名前 |
image | ベースイメージ。ローカルのDockerfileからビルドしない場合はこれを指定。 |
features | dev containerのfeature ID。featureに関しては後述。 |
forwardPorts | コンテナからVSCodeを利用しているマシンへのポートフォワード内容 |
postCreateCommand | コンテナ構築完了後に実行されるシェルコマンド |
customizations | dev containerを利用しているプログラム(今回はVSCode)特有の設定。 |
remoteUser | コンテナに接続する際に使うユーザー |
今回imageにmcr.microsoft.com/devcontainers/go:0-1.19-bullseyeを指定しているのでこちらのイメージが使用されています。ではこのイメージはどうやって作られているかというと、dev containerのDockerfileをメンテしているリポジトリにDockerfileが置かれています。現在の内容は以下の通りです。
# [Choice] Go version (use -bullseye variants on local arm64/Apple Silicon): 1, 1.20, 1.19, 1-bullseye, 1.20-bullseye, 1.19-bullseye, 1-buster, 1.20-buster, 1.19-buster
ARG VARIANT=1.20-bullseye
FROM golang:${VARIANT}
# [Optional] Uncomment the next line to use go get to install anything else you need
# RUN go get -x <your-dependency-or-tool>
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
ということで単にGoのイメージを使っているだけに過ぎないようです。では、Goのイメージは何をやっているのか。GoのイメージのDockerfileはこちらです。
#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#
FROM buildpack-deps:bullseye-scm
# install cgo-related dependencies
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
g++ \
gcc \
libc6-dev \
make \
pkg-config \
; \
rm -rf /var/lib/apt/lists/*
ENV PATH /usr/local/go/bin:$PATH
ENV GOLANG_VERSION 1.19.6
RUN set -eux; \
arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
url=; \
case "$arch" in \
'amd64') \
url='https://dl.google.com/go/go1.19.6.linux-amd64.tar.gz'; \
sha256='e3410c676ced327aec928303fef11385702a5562fd19d9a1750d5a2979763c3d'; \
;; \
'armel') \
export GOARCH='arm' GOARM='5' GOOS='linux'; \
;; \
'armhf') \
url='https://dl.google.com/go/go1.19.6.linux-armv6l.tar.gz'; \
sha256='1f5900567595366fbb3b9ea02cee8ea67ac4b87234fb246549b902cde1013821'; \
;; \
'arm64') \
url='https://dl.google.com/go/go1.19.6.linux-arm64.tar.gz'; \
sha256='e4d63c933a68e5fad07cab9d12c5c1610ce4810832d47c44314c3246f511ac4f'; \
;; \
'i386') \
url='https://dl.google.com/go/go1.19.6.linux-386.tar.gz'; \
sha256='da4546cc516ae88698e8643d6d22fe1465b44dd49fc36abb34d53a93c19581ad'; \
;; \
'mips64el') \
export GOARCH='mips64le' GOOS='linux'; \
;; \
'ppc64el') \
url='https://dl.google.com/go/go1.19.6.linux-ppc64le.tar.gz'; \
sha256='4ce62f9bad666e7aa73171c3056fe89b23548d1a78de8be5f30b64ccd10990de'; \
;; \
's390x') \
url='https://dl.google.com/go/go1.19.6.linux-s390x.tar.gz'; \
sha256='1673f748e25acbb2504536f41239231ac658c99e06d04ba68d51123ee62108a5'; \
;; \
*) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \
esac; \
build=; \
if [ -z "$url" ]; then \
# https://github.com/golang/go/issues/38536#issuecomment-616897960
build=1; \
url='https://dl.google.com/go/go1.19.6.src.tar.gz'; \
sha256='d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767'; \
echo >&2; \
echo >&2 "warning: current architecture ($arch) does not have a compatible Go binary release; will be building from source"; \
echo >&2; \
fi; \
\
wget -O go.tgz.asc "$url.asc"; \
wget -O go.tgz "$url" --progress=dot:giga; \
echo "$sha256 *go.tgz" | sha256sum -c -; \
\
# https://github.com/golang/go/issues/14739#issuecomment-324767697
GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; \
# https://www.google.com/linuxrepositories/
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 'EB4C 1BFD 4F04 2F6D DDCC EC91 7721 F63B D38B 4796'; \
# let's also fetch the specific subkey of that key explicitly that we expect "go.tgz.asc" to be signed by, just to make sure we definitely have it
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys '2F52 8D36 D67B 69ED F998 D857 78BD 6547 3CB3 BD13'; \
gpg --batch --verify go.tgz.asc go.tgz; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME" go.tgz.asc; \
\
tar -C /usr/local -xzf go.tgz; \
rm go.tgz; \
\
if [ -n "$build" ]; then \
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends golang-go; \
\
export GOCACHE='/tmp/gocache'; \
\
( \
cd /usr/local/go/src; \
# set GOROOT_BOOTSTRAP + GOHOST* such that we can build Go successfully
export GOROOT_BOOTSTRAP="$(go env GOROOT)" GOHOSTOS="$GOOS" GOHOSTARCH="$GOARCH"; \
./make.bash; \
); \
\
apt-mark auto '.*' > /dev/null; \
apt-mark manual $savedAptMark > /dev/null; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
rm -rf /var/lib/apt/lists/*; \
\
# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain
rm -rf \
/usr/local/go/pkg/*/cmd \
/usr/local/go/pkg/bootstrap \
/usr/local/go/pkg/obj \
/usr/local/go/pkg/tool/*/api \
/usr/local/go/pkg/tool/*/go_bootstrap \
/usr/local/go/src/cmd/dist/dist \
"$GOCACHE" \
; \
fi; \
\
go version
ENV GOPATH /go
ENV PATH $GOPATH/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
まず、実行環境のCPUアーキテクチャを取得し、https://go.dev/dl/から対応するリリースと署名をwgetします。gpgでtgzが改ざんされていないか署名と照合します。照合したらgo.tgzを/usr/localにインストールします。もし実行環境のCPUアーキテクチャに対応するGoのリリースが存在しなければビルドに必要なものをインストールしてGoをビルドします。本当に最低限の内容が入るみたいですね。
VSCode拡張の自動インストール
customizationsの項目を次のように編集します。
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["golang.go","mhutchie.git-graph"]
}
}
devcontainer.jsonを編集するとVSCodeにリビルドするよう促されるのでリビルドします。といっても、Dockerfileを編集したわけではないのでキャッシュが効いてすぐリビルドは終わります。
動作確認
開発環境で
go mod init github.com/K-Nksm/hello
します。適当な位置にhello.goを作成して
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
と書きます。エディタでhello.goを開いたままF5を押すとコンパイルと実行が行われます。下みたいな表示が出ればOK。
コメント