Docker上のvscodeでremote containerを使う(Linux)
目的
vscodeそのものをdocker上で動かしてremote containerを使えるようにします。
メリット
- ホスト機が汚れない。
- vscodeのPC間の移行が簡単になる。
デメリット
- フォルダ構成が深くなる。
- コンテナ分のオーバーヘッドでストレージを消費する
前提
Dockerインストール済みのLinux
ホストのInputMethodはfcitx
概要
準備
- bashで実行することを想定
- ホストマシンにログインしているユーザのIDを確認し「ARG UID」に記載(デフォルト:1000)
- ホストマシンのDockerのIDを確認し「ARG DOCKERGID」に記載(デフォルト:969)
- イメージ名を決める(デフォルト:vscode_container)
- vscodeコンテナにバインドしたいフォルダを作る(デフォルト:~/vscode_container)
※バインドしたいフォルダは起動前に作成しておいてくだだい。
イメージ作成
Dockerfileを準備
touch Dockerfile
vim Dockerfile
FROM ubuntu:latest
ENV DEBIAN_FRONTEND noninteractive
ENV LANG ja_JP.UTF-8
ARG UID=1000 # ホストのユーザーIDと一致させる
ARG DOCKERGID=969 # ホストのDockerグループと一致させる
RUN sed -i.org -e 's|ports.ubuntu.com|jp.archive.ubuntu.com|g' /etc/apt/sources.list \
&& apt-get update && apt-get install -y \
tzdata \
locales \
fonts-noto-cjk \
dbus-x11 \
pulseaudio \
fcitx-mozc \
curl \
gpg \
apt-transport-https \
ca-certificates \
lsb-release \
git \
zip \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& groupadd -g ${DOCKERGID} -o docker \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
&& install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ \
&& echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list \
&& apt update && apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
code \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& ln -s -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& dpkg-reconfigure tzdata \
&& locale-gen ja_JP.UTF-8 \
&& rm microsoft.gpg \
&& useradd -m -u ${UID} user
Run usermod -aG docker user
イメージをビルド
docker build -t vscode_container .
vscode起動
docker run \
--net=bridge \
--shm-size=4096m \
--rm \
-t \
-e DISPLAY \
-v /tmp/.X11-unix/X0:/tmp/.X11-unix/X0 \
-e PULSE_COOKIE=/tmp/pulse/cookie \
-e PULSE_SERVER=unix:/tmp/pulse/native \
-v /run/user/1000/pulse/native:/tmp/pulse/native \
-v ~/.config/pulse/cookie:/tmp/pulse/cookie:ro \
-e XMODIFIERS \
-e GTK_IM_MODULE \
-e QT_IM_MODULE \
-e DefalutIMModule=fcitx \
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
-v /run/user/1000/bus:/run/user/1000/bus \
--privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-e HOME_HOST=~/vscode_container \
-v ~/vscode_container:/home/user \
-u `id -u` \
vscode_container code --verbose
devcontainer
...
// Docker out of Docker Bind Configuration.
"workspaceMount": "source=${env:HOME_HOST}/${localWorkspaceFolderBasename},target=/workspace,type=bind,consistency=cached",
"workspaceFolder": "/workspace"
...
これでdocker上のvscodeでRemote Containersで開発できるようになりました。
解説
要点
GUIアプリをDocker上で動かす方法については別記事がありますので参照ください。
Dockerコンテナ上でGUIアプリを表示する
Dockerコンテナ上のGUIアプリで音を出す
Dockerコンテナ上のGUIアプリで日本語入力する
Docker outside of Docker
docker上のvscodeでRemote Containerを利用する際は、dood構成にすると簡単に実現できます。前出の図のように、vscodeコンテナはホストのdocker daemonと通信してdev containerを操作します。
/workspaceのバインドについて
イメージをビルドして起動するれば、コンテナ内のvscodeが起動、ExtensionからRemote Containers導入、dev container起動はできるのですが、このままだとdevcontainerの/workspaceのディレクトリがvscodeのプロジェクトディレクトリにバインドされません。
上の図でvscodeコンテナがdev containerを起動する際は、ホストのDocker Daemonで処理するので、バインド元となるvscodeコンテナのパスが見つかりません。なので、ホストからvscodeコンテナにホストバインドパスを$HOME_HOST環境変数を渡し、ホストのパスを指定できるようにします。
概要のdevcontainerに記載のように.devcontainer.jsonを設定すれば、直接ホストのディレクトリをバインドすることができ、利用できるようになります。
Dockerfile解説
FROM ubuntu:latest
ENV DEBIAN_FRONTEND noninteractive
ENV LANG ja_JP.UTF-8
ARG UID=1000 # ホストのユーザーIDと一致させる
ARG DOCKERGID=969 # ホストのDockerグループと一致させる
RUN sed -i.org -e 's|ports.ubuntu.com|jp.archive.ubuntu.com|g' /etc/apt/sources.list \
&& apt-get update && apt-get install -y \
tzdata \ # タイムゾーン情報
locales \ # ロケール
fonts-noto-cjk \ # 日本語フォント
dbus-x11 \ # プロセス間通信
fcitx-mozc \ # インプットメソッド
pulseaudio \ # 音声用
curl \ # 署名ダウンロード用
gpg \ # 署名管理用
apt-transport-https \ # aptのhttps対応
ca-certificates \ # CA証明書
lsb-release \ # バージョン情報確認
git \ # ソース管理用
zip \ # zip解凍用
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ # dockerの署名をダウンロード
&& groupadd -g ${DOCKERGID} -o docker \ # ホストのDocker GIDと同じIDでDockerグループ作成
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ # aptのリポジトリにdockerを追加
&& curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \ # microsoftの署名をダウンロード
&& install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ \ # microsoftの署名をインストール
&& echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list \ # aptのリポジトリにvscodeを追加
&& apt update && apt install -y \
docker-ce \ # remote containerを使うために必要
docker-ce-cli \ # remote containerを使うために必要
containerd.io \ # remote containerを使うために必要
code \ # vscodeインストール
&& apt-get clean \ # キャッシュ削除
&& rm -rf /var/lib/apt/lists/* \ # キャッシュ削除
&& ln -s -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \ \ # タイムゾーン設定
&& dpkg-reconfigure tzdata \ # タイムゾーン設定
&& locale-gen ja_JP.UTF-8 \ # 日本語ロケール生成
&& rm microsoft.gpg \ # 利用済み署名の削除
&& useradd -m -u ${UID} user # 一般ユーザを追加
# usermodは別RUNにしないとエラーになる
RUN usermod -aG docker user # userをdockerグループに追加
起動コマンド解説
docker run \
--net=bridge \ # ネットワークモード
--shm-size=4096m \ # メモリサイズ
--rm \ # コンテナ終了時削除
-t \ # tty
-e DISPLAY \ # X サーバ名(画面表示)
-v /tmp/.X11-unix/X0:/tmp/.X11-unix/X0 \ # X サーバソケット(画面表示)
-e PULSE_COOKIE=/tmp/pulse/cookie \ # 環境変数で認証ファイルを伝える
-e PULSE_SERVER=unix:/tmp/pulse/native \ # 環境変数でソケットファイルを伝える
-v /run/user/1000/pulse/native:/tmp/pulse/native \ # ソケットを共有する
-v ~/.config/pulse/cookie:/tmp/pulse/cookie:ro \ # 認証ファイルを共有する
-e XMODIFIERS \ # XクライアントにIMを伝える
-e GTK_IM_MODULE \ # GTKアプリにIMを伝える
-e QT_IM_MODULE \ # QTアプリにIMを伝える
-e DefalutIMModule=fcitx \ # IMを伝える
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \ # プロセス間通知のためのパスを伝える
-v /run/user/1000/bus:/run/user/1000/bus \ #プロセス間通信のためのパスを共有する
--privileged \ # doodするために特権付与
-v /var/run/docker.sock:/var/run/docker.sock \ # doodするためにdockerソケット共有
-e HOME_HOST=~/vscode_container \ # ホスト側のバインドパスを教える
# ホストとvscodeコンテナのパスをバインド
# ホスト側のパスはお好みで
-v ~/vscode_container:/home/user \
-u `id -u` \ # ホスト側のユーザIDと同じユーザIDを指定する
vscode_container code --verbose # イメージ名とコマンドを指定する
.devcontainer.json解説
...
// Docker out of Docker Bind Configuration.
// ${env:HOME_HOST}でvscodeコンテナ上の環境変数$HOME_HOSTを展開
// これでホストのバインドパスがわかる
// ${localWorkspaceFolderBasename}はvscodeコンテナ上のプロジェクトディレクトリ名
// これで、devcontainerにマウントされるパスが元のホストのバインドパスを指定できる
"workspaceMount": "source=${env:HOME_HOST}/${localWorkspaceFolderBasename},target=/workspace,type=bind,consistency=cached",
"workspaceFolder": "/workspace"
...
Discussion