ラズパイ上の Docker コンテナに VS Code の Remote Containers で接続する


はじめに

Docker を使い始めてからというもの、開発環境を簡単に作り直すことができるようになったので、うっかり環境を壊してしまう恐怖から開放されて気軽にあれこれ試せるようになりました。ただし、Docker コンテナ内で動かす用のコードを VS Code で編集すると、環境が異なるので構文エラーになったり補完が効かなかったりして、不便に感じることもあると思います。

それを解消してくれる VS Code の拡張機能が Remote Containers です。Docker コンテナに接続して、コンテナ内の環境でコードを編集できるようになります。

やり方は VS Code のドキュメントにありますので、それを参考に進めます。

リモートのセットアップ

Remote Containers はローカルだけでなくリモートにある Docker コンテナに接続することもできます。ここでは、Raspberry Pi 3B+ 上で Docker コンテナを立ち上げて、ローカルの VS Code からコンテナ内に入れるようにしてみます。

Raspberry Pi の設定

用意するもの

  • Raspberry Pi OS (32bit) セットアップ済みの Raspberry Pi 3B+
  • Ubuntu インストール済みの PC

SSHの有効化

Raspberry Pi の SSH を有効化します。スタートメニューから、設定(Preference) -> Raspberry Pi の設定 (Raspberry Pi Configuration) の、インターフェース (Interfaces) タブから設定できます。

固定IPアドレスの設定

Raspberry Pi の固定IPアドレスを設定します。/etc/dhcpcd.conf を編集して、ネットワーク内の他の機器に被らないアドレスを指定します。ここでは 192.168.0.51 にしました。

Docker のセットアップ

Raspberry Pi に Docker をインストールします。インストール用のスクリプトがあるので次のコマンドを実行するだけです。(公式のドキュメントには本番環境での使用は推奨されないと書いてありますが、今回は実験なので目をつぶります。)

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh

root 以外のユーザーから docker コマンドを起動できるように設定します。

$ sudo usermod -aG docker $USER
$ newgrp docker

Dockerが正常に動作しているか確認するため、 ubuntu:18.04 のコンテナを走らせてみます。

$ docker run -it --rm ubuntu:18.04

次のような出力が得られたら大丈夫です。Ctrl+D で終了させます。

Unable to find image 'ubuntu:18.04' locally
18.04: Pulling from library/ubuntu
9ac910c0311f: Pull complete 
5b89a6b5bccf: Pull complete 
36058ccabae5: Pull complete 
Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:18.04
root@c956f3eea22c:/#

VS Code の設定

PC に戻って VS Code の設定を行います。

拡張機能のインストール

VS Code の拡張機能を開いて、 Docker と Remote Containers がインストールされていることを確認します。インストールされていなければ、ここでインストールします。

リモート Docker ホストの設定

File -> Preferences -> Settings から設定画面を開きます。検索欄に docker.host と入力すると、Docker ホストを設定する項目が出てくるので、ssh://myuser@mymachine のかたちでホストを入力します。

SSH 鍵の設定

これ以降、SSH 鍵を設定していないと何度もパスワードの入力を求められます。面倒なので、Quick start: Using SSH keys を参考に、次のようなコマンドで SSH 鍵を作成して設定します。

$ ssh-keygen -t rsa -b 4096
$ ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

接続テスト

devcontainer.json ファイルを作成します。作業ディレクトリで .devcontainer/devcontainer.json ファイルを作って下の例のように入力します。

Remote Containers は、デフォルトで作業ディレクトリをコンテナにマウントするようになっていますが、ローカルのファイルをそのままリモートにマウントすることはできないらしく、この例では作業ディレクトリの代わりに Named volume をマウントしています。

{
    "image": "ubuntu",
    "workspaceFolder": "/workspace",
    "workspaceMount": "source=remote-workspace,target=/workspace,type=volume"
}

準備が出来たら Remote Containers を走らせます。F1 キーか、画面右下の緑ボタンをクリックして、Remote-Containers: Reopen in Container を選択します。

しかしエラーが発生しました。どうやらこのコンテナには libatomic というライブラリが無いようです。

Remote-Containers server: /root/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/node: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory

というわけで、Raspberry Pi 上で Dockerfile を作って、libatomic をインストールした Docker イメージをビルドします。

FROM ubuntu:18.04

RUN apt-get update && apt-get install -y libatomic1
$ docker build -t ubuntu .

VS Code に戻って今度は Remote-Containers: Rebuild and Reopen in Container を実行すると接続することができました。

その他の設定

上の操作で接続することはできましたが、これだけだとあまり便利ではないので以下の設定を加えます。

リモートのファイルのマウント

ローカルのファイルは Named volume 経由でないとマウントできないようですが、リモートのファイルは直接マウントすることができます。例えばリモートに /home/pi/workspace というディレクトリがあって、Docker コンテナの /workspace にマウントしたい場合は、devcontainer.json"workspaceMount" を次のように変更することでマウントできます。

"workspaceMount": "source=/home/pi/workspace,target=/workspace,type=bind,consistency=cached",

非 root ユーザーの追加

上で使用したコンテナのユーザーは root でした。Remote Containers は root で利用することもできますが、Permission 関連の問題が生じることが多いので、ユーザーを追加しておいたほうが無難です。ドキュメントを参考に、Dockerfile に次の行を追加します。ユーザー名は割と何でもいいのですが、この例では vscode です。

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
    && apt-get update \
    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

# Set the default user
USER $USERNAME

拡張機能を再インストールしないよう設定

Remote Containers を使うと、VS Code の拡張機能は Docker コンテナ内の ~/.vscode-server/extensions~/.vscode-server-insiders/extensions にインストールされます。そのためコンテナを再ビルドすると拡張機能もインストールし直す必要が生じてしまいますが、以下の手順でそれを回避できます。

  • Docker イメージに~/.vscode-server/extensions~/.vscode-server-insiders/extensions を作成します。ドキュメントに従って Dockerfile に次の行を追加します。

    RUN mkdir -p /home/$USERNAME/.vscode-server/extensions \
            /home/$USERNAME/.vscode-server-insiders/extensions \
        && chown -R $USERNAME \
            /home/$USERNAME/.vscode-server \
            /home/$USERNAME/.vscode-server-insiders
    
  • devcontainer.json を編集して、作成したディレクトリに Named volume をマウントするように設定を追加します。unique-vol-name-here には他のコンテナと被らない名前で上書きします。

    "mounts": [
        "source=unique-vol-name-here,target=/home/vscode/.vscode-server/extensions,type=volume",
        "source=unique-vol-name-here-insiders,target=/home/vscode/.vscode-server-insiders/extensions,type=volume",
    ]
    

Dockerfile と devcontainer.json

上記の設定を反映した結果、Dockerfile と devcontainer.json は次のようになりました。

FROM ubuntu:18.04

RUN apt-get update && apt-get install -y libatomic1

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
    && apt-get update \
    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

# Set the default user
USER $USERNAME

# Create extension directory
RUN mkdir -p /home/$USERNAME/.vscode-server/extensions \
        /home/$USERNAME/.vscode-server-insiders/extensions \
    && chown -R $USERNAME \
        /home/$USERNAME/.vscode-server \
        /home/$USERNAME/.vscode-server-insiders
{
    "image": "ubuntu",
    "workspaceFolder": "/workspace",
    "workspaceMount": "source=/home/pi/workspace,target=/workspace,type=bind,consistency=cached",
    "mounts": [
        "source=remote-extensions,target=/home/vscode/.vscode-server/extensions,type=volume",
        "source=remote-extensions,target=/home/vscode/.vscode-server-insiders/extensions,type=volume",
    ]
}

おわりに

Raspberry Pi 上のコンテナに、PC の VS Code から接続することができました。Raspberry Pi だけでなく Jetson など他のシングルボードコンピュータや、遠隔地のサーバーにも利用できるそうなので、いろいろと便利な開発環境が作れそうです。

参考