Kesinの知見置き場

知見を共有していきたいじゃないですか

VSCode Remote Containersに自分のdotfilesを持ち込む

ついにarm版のmacOSが発表されてしまったので、自分はこれを機に開発機をmacから乗り換えようと考えています。そのために注目しているのがVSCode Remote Containerです。

Remote Containersで使うコンテナ環境は.devcontainerというファイルに定義します。ブラウザからでも使うことができるVSCode Codespace(VSCode Onlineからリネームされた)や、今年に発表されたGitHub Codespaceでも同じように実行環境を.devcontainerで設定できるようです。

これを知るまではmacからWindowsのWSL2環境に移行しようかと考えていたのですが、コンテナであれば緩やかに移行できるし、VSCodeベースのオンラインエディタでも同じ環境を再現できることからWSL2に移行するよりも筋が良いように思いました。

Remote Containersを使ってみる

まずはドキュメントを見ながらお試しで始めてみます。手順自体は公式ドキュメントにスクショ付きで丁寧な解説があるのでそちらを見てください。ぽちぽち進めるだけでVSCodeが.devcontainerやDockerfileまで生成してくれるのでイチから手書きで用意していく必要はありませんでした。

最初のコンテナをビルドするところで時間が少々かかりますが、それさえ終わればあとは普段の環境と遜色ないでしょう。ターミナルを開けば見慣れたLinuxの環境です。

指定したコンテナの中で作業をしているため、言語のバージョンも当然コンテナでセットアップ済みのものが使えます。○○envみたいなバージョンを切り替えるツールは不要です。さらに、いかなる技術によるものかVSCode上で操作するgitだけではなく、ターミナル上でも自分のgitの設定や認証情報が引き継がれています。コミットをすればちゃんとauthorは自分になりますし、そのままGitHubにpushもできます。

一見するとローカル環境と比べても何不自由ない状態なのですが、普段どおりにターミナルを使おうとすると不便さに気が付きます。ls -lエイリアスとしてよく使われるllも使えません。当然laも無いし、そもそもlsの結果に色がついていない。さらにプロンプトも自分のお気に入りの表示ではありません。これでは普段使いには厳しい。

(本題)自分のdotfilesをRemote Containersに持ち込む

MSさんはこのあたりを分かっているので、自分のdotfilesをコンテナの中に持ち込む方法をVSCodeに用意してくれています。流石ですね。

Personalizing with dotfile repositories

公式ドキュメントではこのあたりなのですが、中身が少なくて意外にハマりポイントが多かったので解説していきたいと思います。

まずは「Remote-Containers: Settings」を呼び出して設定画面に行きます。設定する項目が3つ存在し、それぞれ以下のような意味です。

  • Dotfiles: Install Command
  • Dotfiles: Repository
    • git cloneするdotfilesのリポジトリ。owner/repositoryの書き方でOK
  • Dotfiles: Target Path
    • git cloneする先のパス
    • Remote Containersの初期セットアップ時に選択したコンテナの場合、おそらくrootユーザーで起動するので~/dotfilesの実際のパスは/root/dotfilesとなる

自分のdotfilesのリポジトリにセットアップ用のinstall.shを用意しておき、こういう感じに設定します。

f:id:Kesin:20200710003623p:plain
Remote Containersの設定

install.shにセットアップ処理を書いていきます。最低限、普段使いしているaliasの追加とlsに色だけは付いて欲しいのでこのような設定を書いてみます。

#!/bin/bash

# alias
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# ls
export LS_OPTIONS='--color=auto'
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -hlrt'
alias la='ls $LS_OPTIONS -hlrta'
export CLICOLOR=1

これをpushしたら実際にdotfilesを読み込んでもらうためにコンテナを作り直します。VSCodeの左下の緑のボタンを押して「Remote-Containers: Rebuild Container」を実行するとコンテナを作り直してdotfilesを読み込み直してくれます。

さて、読み込みが終わったのでこれで解決・・・と思いきや、aliasもlsの色付けも反映されていません。ドキュメントにも難しいことは書いていなかったのになぜ?

Remote Containersとdotfilesのセットアップの仕組み

上手くできなかった理由を考えます。そもそもこのRemote Containersがどういう手順で起動しているのかを推測してみました。

  1. .devcontainerに従ってDockerfileからコンテナをビルド
  2. .devcontainerに書かれているextensionsをインストール
  3. docker run —mount type=bind,src=$(pwd),dst=/workspace/{REPO_NAME} {CONTAINER}に近いコマンドでVSCodeから開いているディレクトリを丸ごとコンテナにmountして実行
  4. dotfilesをgit clone
  5. 指定したスクリプトを実行(install.sh)
  6. コンテナ内でシェルを起動
  7. debian系のコンテナだと/root/.profileが存在するのでこれがシェル起動時に実行される
  8. .profileの最後で.bashrcを読み込む(. ~/.bashrc)

ログが出ているわけではないので自分の推測と観測した結果ですが、おそらくこういう手順で実行されています。最後の.profileが.barshrcを .(source)で読み込む のに対して、5のinstall.shは 普通のスクリプトとして実行 されます。

install.shに書いたaliasが反映されていないのはこれが原因です。普通のスクリプトの実行と.(source)の違いについてはこのあたりの記事を参照してください。

https://www.atmarkit.co.jp/ait/articles/1712/21/news015.html

install.shで行うべきこと

8にあるようにコンテナの起動時に.profile→.bashrcの順序で読み込まれていることは分かっています。ということは、もともと存在する.bashrcをシンボリックリンクで置き換えることにより自前の.bashrcを読み込ませることが可能です。

#!/bin/bash
cd ~/
ln -fs ~/dotfiles/.bashrc .

先程のaliasなどは自前の.bashrcに移し、install.shではシンボリックリンクを貼るだけにします。これを再度pushし、再びRebuild Containerを実行しましょう。

f:id:Kesin:20200710003703p:plain
install.shが正しく設定できたターミナル

できました!自分はaliasとlsの色付けに加えてプロンプトにgitのブランチを表示させるように変更してみましたが、コンテナの起動時に自動的に反映されています。
これでファイル操作をターミナルで行う硬派なユーザーでも心置きなくRemote Containers環境でコーディングできるようになりました。後はみなさん各自で最強のdotfilesを用意してください。

最後に現時点での自分のdotfilesを貼っておきます。自分の場合はinstall_vscode_container.shという名前にしたのでこちらを参照してください。

自分はaliasとlsの色付けに加えて、プロンプトにgitのブランチ名を表示させたりgitのdiffを改良するdiff-highlightを使えるようにしています。

https://github.com/Kesin11/dotfiles/blob/08617cb952817883199d7d4f676b9cb2a5bc15f0/install_vscode_container.sh

おまけ install.shの効率的なデバッグ方法

install.shを修正するたびにgit pushしてVSCodeからRebuild Containerするのは時間がかかるので、デバッグはもっと効率的な方法で行いましょう。

dotfilesのリポジトリが置いてあるディレクトリ上でこのdocker runを実行してください。dotfilesをそのままコンテナ内の/home/dotfilesの位置にマウントした状態でbashが起動します。使うコンテナは.devcontainersとDockerfileで自分が使いたいコンテナの名前に変更してください。

docker run --entrypoint=bash --rm -it --mount type=bind,src=$(pwd),dst=/home/dotfiles mcr.microsoft.com/vscode/devcontainers/typescript-node:0-12

コンテナのbashが起動したらコンテナの中でinstall.shを実行し、続けて. ~/.profile を実行することでVSCodeのRemote Containers起動手順を模倣できます。dotfilesはホスト側のディレクトリをマウントしているので、ホスト側で編集すればコンテナ内にも即反映されます。望みの状態になるまで各種ファイルを編集しながら読み込み直してデバッグしていきましょう。

もしもまっさらな状態からやり直したくなったときは一度コンテナから抜けます。—rmオプションを付けているので、再びdocker runするとまっさらな状態に戻っています。最終確認としてまっさらな状態から全てが正しく設定できているか確認するといいでしょう。