業務で Linux 向けの Go プログラムを多数開発しています。
しかしながら、開発している機材の OS は好きこのんで Windows です。 在宅から勤務するときに、Windows のリモートデスクトップが最強すぎるので手放せないのが大きな理由です。
そんなわけで、Windows の Hyper-V という機能で Ubuntu を仮想マシンとして動作させ、Emacs で長年開発していました。
しかし近年、モニタも 4K 32 インチと大きくなりましたしメモリも 32 GB 搭載されていますし、なにより Visual Studio Code のような高機能 IDE が手軽に利用できる状況でありながら、ろくにカスタマイズをしない Emacs で開発を続けるのも怠慢かなと考え、「WSL で快適な Go 開発環境を作る」という記事に書いたように Windows + WSL + Visual Studio Code という開発環境を整えました。
開発しているコードは Linux 向けですので、いくら Go がクロスコンパイルが得意といっても本当は Ubuntu 上で開発できるのにこしたことはありません。Windows にせざるを得なかったのは、Ubuntu 上で動作させる Visual Studio Code を 4K の解像度で X プロトコルで表示させるとラグが大きすぎて実用に耐えなかったためでした。
しかし先日、Visual Studio Code から Electron を取り除き、WebSocket でブラウザに画面を表示させるようにする code-server が OSS でリリースされたことにより状況は一変しました。X プロトコルよりもずっと効率的に画面操作ができるので、Chrome on Windows + Ubuntu on Hyper-V + code-server を使うことで以下が実現するのです。
- Visual Studio Code で手軽に高度な IDE を使って開発
- Windows のリモートデスクトップ機能で自宅からも快適に開発
- Ubuntu 上の Go でコンパイルするので高速&クロスコンパイル不要
- ラグなし!
環境構築手順を以下にメモしておきます。
フォントのインストール
後述する VSCode の設定で Ricty Diminished を指定するので、インストールしておきます。
- 4.1.1 の tar archive をダウンロード
- 適当に解凍 (WSL から
/mnt/c/Users/xxxx/Download
に行ってtar xzf ricty_diminished-4.1.1.tar.gz
とか) RictyDiminished-Regular.ttf
を右クリックしてインストール
Hyper-V 上に Ubuntu を構築
リンクだけ:
- Windows 10 での Hyper-V の有効化 | Microsoft Docs
- Run Ubuntu virtual machines made even easier with Hyper-V Quick Create - Windows Developer Blog
- Windows 10 Pro Hyper-V に Ubuntu 18.04 LTS をインストール - Qiita
Ubuntu 上で Go 開発環境を整備
一般的な開発に必要なパッケージとフォントをインストール
$ sudo apt update $ sudo apt -y install jq build-essential manpages-dev glibc-doc git fonts-ricty-diminished
Go 公式のバイナリを
/usr/local/go
以下に展開してインストール/usr/local/go/bin
,$HOME/go/bin
に PATH を追加bingo, golint, goimports などの開発ツールをインストール
$ GOPATH=$HOME/go $ export GOPATH $ mkdir -p $GOPATH/src/github.com/saibing $ cd $GOPATH/src/github.com/saibing $ git clone https://github.com/saibing/bingo $ cd bingo $ GO111MODULE=on go install ./... $ GO111MODULE=off go get -u golang.org/x/tools/cmd/goimports $ GO111MODULE=off go get -u golang.org/x/lint/golint $ GO111MODULE=off go get -u github.com/rogpeppe/godef
vscode をインストール(後述する extension インストールのために使う)
code-server のインストールと初期設定
code-server はシングルバイナリなのでインストールは簡単です。起動すると https で待ち受ける Web アプリケーションとなっているので、証明書を用意しておくと便利です。ここでは自己署名証明書を作る手順を紹介します。
$ DNS=example.com $ IP=10.0.0.1 $ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \ -keyout code-server.key -out code-server.crt -extensions san \ -config <(printf '[req]\ndistinguished_name=req\n[san]\nsubjectAltName=DNS:%s,IP:%s\n' $DNS $IP) \ -subj /CN=$DNS
上記の example.com
, 10.0.0.1
は適当に実行するサーバーの名前と IP アドレスで置き換えてください。うまくいけば code-server.key
と code-server.crt
というファイルが作られます。code-server.crt
を Chrome の設定からルート証明書として追加しましょう。
Visual Studio Code は extension をインストールすることで機能を拡充できるのですが、手軽に拡張をインストールできる Marketplace が code-server には利用規約の関係で利用できないため、現時点では最新の拡張をインストールするのが手間です。
そこで、先ほど入れた公式 vscode を使って Marketplace で最新拡張をインストールし、それを code-server から利用できるようにします。まずは vscode を (X Windows などで) 使って起動して必要な extension をインストールします。
次に code-server を以下のようにインストールして起動します。
最新の code-server の Linux 版をダウンロード
展開してインストール
$ tar xzf code-server-1.31.1-100-linux-x64.tar.gz $ sudo mv code-server-1.31.1-100-linux-x64/code-server /usr/local/bin
code-server を起動
$ code-server --cert=code-server.crt --cert-key=code-server.key
Windows 上の Chrome から Hyper-V Ubuntu に接続し、表示されるパスワードを使ってログイン
一度 code-server を終了し、以下を実行
$ rm -rf $HOME/.code-server/extensions $ ln -s $HOME/.vscode/extensions $HOME/.code-server/extensions
再度起動すると、vscode でインストールした extension が code-server でも利用できるようになっています。
なお code-server --allow-http
とすると HTTP でも接続できますが、この場合 Chrome がクリップボード API を無効化してしまうので、エディタ上でカット&ペースト操作ができなくなります。HTTPS 接続で、証明書を用意するのがお勧めです。
インストールしている拡張
- Bracket Pair Colorizer 2
- Go
- GraphQL for VSCode
- Markdown All in One
- sftp
- Systemd Support
- vscode-icons
- YAML
- zenkaku
Visual Studio Code の設定
現在は以下のようになってます。Control+Shift+P でコマンドパレットを開き、Preferences: Open Settings (JSON)
を選択してコピペするとそのまま真似できます。
{ "editor.fontFamily": "'Ricty Diminished'", "editor.fontSize": 16, "editor.quickSuggestions": { "other": false, "comments": false, "strings": false }, "editor.renderWhitespace": "all", "editor.suggestOnTriggerCharacters": false, "files.eol": "\n", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "go.alternateTools": { "go-langserver": "bingo" }, "go.formatTool": "goimports", "go.installDependenciesWhenBuilding": false, "go.languageServerExperimentalFeatures": { "autoComplete": true }, "go.languageServerFlags": [ "-maxparallelism=4" ], "go.useLanguageServer": true, "markdown.extension.toc.levels": "1..3", "workbench.iconTheme": "vscode-icons", "[go]": { "editor.formatOnSave": true, "editor.formatOnSaveTimeout": 100000 }, "[markdown]": { "editor.formatOnSave": true } }