📤

Docker上のvscodeでremote containerを使う(Linux)

2021/12/12に公開

目的

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を準備

host bash
touch Dockerfile
vim Dockerfile
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
    

イメージをビルド

host bash
docker build -t vscode_container .

vscode起動

host bash
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

.devcontainer/devcontainer.json
...
  // 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解説

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グループに追加

起動コマンド解説

host bash
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解説

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