概要
バージョン2004で正式導入されたWSL2ですが、先日バージョン1909と1903へのバックポートが発表されました!
https://devblogs.microsoft.com/commandline/wsl-2-support-is-coming-to-windows-10-versions-1903-and-1909/
筆者の開発PCは2004へのアップデートが許可されていないので、非常に助かります。
そこで今回は、Docker Desktop for WindowsのWSL2インテグレーション機能と、VSCodeのRemote - Containers拡張機能を使って、Dockerfileでコンテナ内にGoの「快適な」開発環境を作ってみるところまでやってみようと思います。
※既に以下のような素晴らしい記事があり書くのを迷いましたが、自身の理解を深めるのと備忘録も兼ねて書きました。
https://tech-lab.sios.jp/archives/21675
筆者の環境
| エディション | バージョン | OSビルド |
|---|---|---|
| Windows 10 Pro | 1909 | 18363.1049 |
システム要件
| エディション | バージョン | OSビルド |
|---|---|---|
| Windows 10(全エディション) | 2004 | - |
| Windows 10 x64(全エディション) | 1909 | 18363.1049 以上 |
| Windows 10 x64(全エディション) | 1903 | 18362.1049 以上 |
手順
-
WSLをインストールし、WSL2に更新する
-
Docker Desktop for Windows をインストールする
-
VSCoceの拡張機能 Remote Containers を使って、Goの開発環境を構築する
1. WSLをインストールし、WSL2に更新する
以下URLの公式手順通りにやれば問題ありませんが、一応この記事でも手順を書いておきます。
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10
1‐1. CPU仮想化が有効になっているか確認
タスクマネージャを開き、CPUの仮想化が有効となっていることを確認してください。
もし有効になっていない場合は、BIOS(UEFI)で仮想化を有効にしてください。(メーカーによって設定方法が異なるので説明は割愛します)

1‐2. Windows Subsystem for Linuxをインストールする
GUI(マウス操作)でやる場合
コントロールパネル > プログラムと機能 > Windowsの機能の有効化または無効化の順に選択して以下画面を開き、Linux用Windowsサブシステムにチェックを入れます。

CUI(コマンド操作)でやる場合
管理者権限でPowerShellを開き、以下コマンドを実行してください。
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
成功すると以下のようなメッセージが表示されます。
展開イメージのサービスと管理ツール
バージョン: 10.0.18362.900
イメージのバージョン: 10.0.18363.1049
機能を有効にしています
[==========================100.0%==========================]
操作は正常に完了しました。
1‐3. 仮想化マシンプラットフォームのオプションコンポーネントを有効にする
GUI(マウス操作)でやる場合
先程と同様に、コントロールパネル > プログラムと機能 > Windowsの機能の有効化または無効化の順に選択して以下画面を開き、仮想マシンプラットフォームにチェックを入れます。

CUI(コマンド操作)でやる場合
管理者権限でPowerShellを開き、以下コマンドを実行してください。
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
成功すると以下のようなメッセージが表示されます。
展開イメージのサービスと管理ツール
バージョン: 10.0.18362.900
イメージのバージョン: 10.0.18363.1049
機能を有効にしています
[==========================100.0%==========================]
操作は正常に完了しました。
1‐4. PCを再起動する
PCを再起動してWSLのインストールとWSL2の更新を完了させます。
1‐5. WSL2を既定のバージョンとして設定する
新しいLinuxディストリビューションをインストールする際の既定のバージョンをWSL2に変更します。
PowerShellを開き、以下コマンドを実行してください。
wsl --set-default-version 2
以下のメッセージが表示された場合はLinuxカーネルを更新する必要があります。
WSL 2 を実行するには、カーネル コンポーネントの更新が必要です。詳細については https://aka.ms/wsl2kernel を参照してください
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください
メッセージに表示されている以下URLにアクセスし、Linuxカーネル更新プログラムパッケージをダウンロードします。
https://aka.ms/wsl2kernel
ダウンロードしたインストーラーを起動し、Nextをクリックすればインストール完了です。

インストールが完了したら、再び以下コマンドを実行してみてください。今度は成功するはずです。
wsl --set-default-version 2
1‐6. Linuxディストリビューションのインストール
Microsoft Storeを開き、Linuxディストリビューションをインストールします。
wslで検索すればいくつか候補が出てきます。

インストールが完了したら、Ubuntuを起動します。
しばらく待つとユーザー名とパスワードの入力を促されるので、任意のものを入力します。
※今後Ubuntu内で何かするときはパスワード入力を求められるので、パスワードは忘れないでください。

これで、Windows上でLinux(Ubuntu)を起動できるようになりました!

念のためPowerShellを開き、以下コマンドを実行してWSLのバージョンが2になっていることを確認しましょう。
wsl -l -v
NAME STATE VERSION
* Ubuntu Running 2
2. Docker Desktop for Windows をインストールする
次に、Docker Desktop for Windowsをインストールし、Dockerを使えるようにします。
ここで注意点ですが、以下のリリースノートに記載してある通り、バージョンが1909 1903の場合はDocker Desktop Community 2.3.5.0 以上をインストールする必要があります。
https://docs.docker.com/docker-for-windows/edge-release-notes/
執筆時点(2020年9月4日)では、Stable版(安定板)の最新バージョンはDocker Desktop Community 2.3.0.4です。
筆者の環境はバージョン1909なので、今回はEdge版をインストールします。
バージョン2004の方はStable版でも問題ないと思います。
以下URLにアクセスし、Docker Desktop for WindowsのEdge版のインストーラーをダウンロードします。
https://hub.docker.com/editions/community/docker-ce-desktop-windows/
インストーラーを起動すると、最初にConfiguration画面が立ち上がります。
今回はDockerのバックエンドをWSL2にしたいので、Install required Windows components for WSL2にチェックが入っていることを確認します。
従来のHyper-V型は使わないので、Enabled Hyper-V Windows Featuresはオフにしておきます。

OKボタンをクリックするとインストールが始まります。以下画面が表示されたら成功です。
Close and log outボタンをクリックするとログアウトされるので、再度Windowsにログインします。

ログイン後、Docker Desktop for Windowsが自動的に起動します。
しばらく待って起動に成功すると以下画面が表示されます。
Startボタンをクリックするとチュートリアルが始まりますが、今回はSKIPします。

画面上部の歯車アイコンをクリックして、Generalの設定でUse the WSL2 backend engineがチェックされていることを確認します。

dockerコマンドが使用できるかどうか確認します。
PowerShellを起動してdocker versionコマンドを実行し、バージョンが表示されるかどうか確認します。

同じくUbuntuを起動してdocker versionコマンドを実行し、バージョンが表示されるかどうか確認します。

これで、WindowsでDockerが使用できるようになりました!
3. VSCoceの拡張機能 Remote-Containers を使って、Goの開発環境を構築する
最後に、Dockerコンテナ内でGoの開発を「快適に」行うための準備をしていきます。
Dockerコンテナで開発する際のメリットとしては以下のようなものがあります。
- 開発に必要な手順が記載されている
Dockerfileがあれば、コンテナを起動するだけですぐに開発できる環境が整います。 - チーム内に
Dockerfileを配布すれば、チーム全員が同じ環境で開発することができます。 - ランタイムやツールのインストールなどをする必要がないので、ホスト環境を汚しません。
Remote-Containersを使えば、上記のメリットに加えて、VSCodeで開発作業が行えるようになるので、コードの編集はもちろん、インテリセンス、構文チェック、定義ジャンプ、デバッグなどの豊富な支援機能も使えるようになり、コンテナ内での開発が非常にスムーズになります。
それでは早速やっていきましょう。
3-1. VSCoceの拡張機能 Remote Developmentのインストール
まず、VSCodeの拡張機能に、Remote Developmentをインストールします。
こちらはRemote-WSLとRemote-ContainersとRemote-SSHのセットになっています。

3-2. VSCodeをWSL(Ubunt)から起動する
次に、Ubuntuを起動します。
mkdirでgo-sampleフォルダを作成し、cdで作成したフォルダに移動してから、code .コマンドでVSCodeを起動します。

すると、VSCodeがWSL(Ubuntu)のgo-sampleフォルダを開いた状態になります。

3-3. Dockerfileの作成
次に、go-sample直下に.devcontainerというフォルダを作成します。
.devcontainerフォルダ内に、Dockerfileという名前のファイルを作成します。
内容は以下の通りにします。
goのバージョンは1.13.15にしてますが、1.14系やlatestでも問題ないです。
go getでインストールしているのはGo開発で必要なツール群です。
※コンテナをリビルドする度にインストールするのが面倒だったので、Dockerfile内に書きました。もっと良いやり方があったら教えてください!
FROM golang:1.13.15
RUN go get -v -u \
github.com/mdempsky/gocode \
github.com/uudashr/gopkgs/v2/cmd/gopkgs \
github.com/ramya-rao-a/go-outline \
github.com/acroca/go-symbols \
golang.org/x/tools/cmd/guru \
golang.org/x/tools/cmd/gorename \
github.com/cweill/gotests/... \
github.com/fatih/gomodifytags \
github.com/josharian/impl \
github.com/davidrjenni/reftools/cmd/fillstruct \
github.com/haya14busa/goplay/cmd/goplay \
github.com/godoctor/godoctor \
github.com/go-delve/delve/cmd/dlv \
github.com/stamblerre/gocode \
github.com/rogpeppe/godef \
golang.org/x/tools/cmd/goimports \
golang.org/x/lint/golint \
golang.org/x/tools/gopls
3-4. devcontainer.jsonの作成
同じく.devcontainerフォルダ内にdevcontainer.jsonという名前のファイルを作成します。
内容は以下の通りにします。
settingsで設定、extentionsで拡張機能を指定できるので、お好みでどうぞ。
今回はGoの拡張機能をインストールして、設定をちょっと変えています。
エディタの環境まで共有できるのですごく便利ですね!
{
// VSCodeに表示されるワークスペース名
"name": "go-sample",
// Docker buildを実行するディレクトリ。devcontainer.jsonファイルからの相対パスで設定します。
"context": "..",
// コンテナの内容を定義するDockerfileのパス。devcontainer.jsonファイルからの相対パスで設定します。
"dockerFile": "Dockerfile",
// コンテナ側のVSCodeの設定値(setting.json)を変更したい場合、設定します。
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"go.formatTool": "goimports",
"go.useLanguageServer": true,
},
// コンテナ側のVSCodeに拡張機能をインストールする必要がある場合、拡張機能のIDを配列で設定します。
"extensions": [
"golang.Go"
]
}
3-5. Remote-Containersでコンテナにリモート接続する
次に、左下にある>< WSL: Ubuntuをクリックし、Remote-Containers: Reopen in Containerを選択します。

VSCodeが再読込され、コンテナ内で起動します。
先程WSL(Ubuntu)側で作成したフォルダ/ファイルがマウントされているのがわかります。
※初回はコンテナの作成に時間がかかりますが、次回からはもう少し早く起動すると思います。

ターミナルでBashを起動し、go versionを実行します。
Goのバージョン1.13.15がインストールされていることを確認できます。

左下の歯車アイコンから設定を開き、@modifiedと入力して変更した設定のみを表示します。
devcontainer.jsonのsettingsで記載した内容が、リモート側のVSCode設定に反映されていることを確認できます。

拡張機能はローカルにインストールするものとリモート側にインストールするものとで管理が分かれます。
devcontainer.jsonのextensionsで設定したGoの拡張機能がリモート側にインストールされていることを確認できます。

Dockerfileでインストールするよう設定したGoのツール群もインストールされています。

Docker Desktopでもイメージが作成されていることが確認できます。

3-6. コンテナ内でのGo開発(hello world)
環境が整ったので、コンテナ内でGoのhello worldを作ってみます。
ワークスペース直下にmain.goという名前のファイルを作成します。
内容は以下の通りにします。
コピペでなく自分で入力すると、インテリセンスやスニペットなどの支援機能が効いていることが実感できると思います。
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
ターミナルでBashを開き、go run main.goを実行します。hello worldと出力されれば成功です!

デバッグもやってみます。
main.goのソース上でfmt.Println("hellow world")にブレイクポイントを設定し、F5キーを押します。

しばらくするとデバッグが実行され、設定したブレイクポイントで止まります。

デバッグツールバーのステップオーバーをクリックするか、F10キーを押すと次のステップへ進みます。
fmt.Plintlnが実行されて、デバッグコンソールにhello worldを出力されることが確認できます。

これでGoのデバッグが出来るようになりました!
※デバッグを終了させる場合は再度F5キーを押してください。
3-7. コンテナへのリモート接続を終了する
コンテナへのリモート接続を終了させる場合は、左下の>< Dev Containerからリモート接続を終了するを選択するか、右上の×ボタンでVSCodeを閉じてください。

3-8. コンテナへのリモート接続を再開する
再度コンテナへのリモート接続をする場合は、WSL(Ubunt)でgo-sampleフォルダを開き、左下の>< WSL: UbuntuからRemote-Containers: Reopen in Containerを選択してください。

初回起動では32.373秒かかりましたが、2回目は18.217秒で起動できました。

3-9. (おまけ)Windowsから直接Remote-Containersでコンテナにリモート接続する
今回はWSL(Ubuntu)内にソースコードを配置して、WSL(Ubuntu)からVSCodeのRemote-Containersでコンテナを起動しましたが、Windows上にソースコードを配置して、Windowsからコンテナを起動することもできます。
やり方はWSL(Ubuntu)の時と同じで、3-3~3-5の手順をWindows上で行うだけです。
ソースコードはWindowsで管理したいよ!っていう方はその方法でも良いかもです。

初回起動では39.594秒かかりました。WSL(32.373秒)より若干遅い?です。

注意点としては、Windowsからコンテナを起動すると、Docker Desktopが以下の警告を表示します。

Docker Desktopは、WindowsファイルをWSL2コンテナーに共有したことを検出しました。これはパフォーマンスが低下する可能性があります。
https://docs.docker.com/docker-for-windows/wsl/#best-practices
上記URLのDocker Desktop WSL2 Backendのベストプラクティスにもあるように、Linuxファイルシステムからマウントされるとパフォーマンスが大幅に向上するようです。Windowsファイルシステムからコンテナを起動するのは避けるように、ともあるので、気になる方はWSLでソースコードを管理したほうがよさそうです。
まとめ
WSL2とDocker Desktop for WindowsとVSCodeの相性が良く、WindowsでもDocker開発がスムーズに行えるようになってきました。
Dockerfileで開発環境を共有できるのはもちろんですが、devcontainer.jsonでVSCodeの設定や拡張機能まで共有できるのもいいですね!
※Goはまだいいですが、ReactやVueなどのフロントエンドの開発だとESLintとPrettierの設定などでかなり労力を持っていかれるので、、、
これからは開発で積極的に取り入れていきたいと思います!

