🐧

VS Code の Remote - SSH 拡張機能:Linux 使い(略)Advent Calendar 2024

2024/12/10に公開

はじめに

これは「Linux 使いになりたい人のための Advent Calendar 2024」の記事です。

筆者は、Web エンジニアを志望する人には、セルフホスト Git サービスを稼働させて利用することをオススメしています。もし Git を使ったことがないなら、Git を学ぶときに、セルフホスト Git サービスを稼働させることも視野に含めながら学習するのが効率的だと考えています。

VS Code の Remote - SSH 拡張機能

前回はセルフホスト Git サービスを使うにあたり、OpenSSH を使うことが多いといった説明の流れから、ssh コマンドの実行を試せる環境を Docker コンテナーを使って用意する方法について紹介しました。

今回は、VS Code Remote - SSH 拡張機能について紹介します。これを使うと、OpenSSH サーバーが動作するリモートマシンに VS Code をリモート接続して開発のための作業をすることができて便利です。

Remote - SSH 拡張機能のインストール

VS Code で Remote - SSH 拡張機能をインストールするには、Quick Open (Ctrl+P) で表示される入力欄へ次のコマンドを貼り付けてから Enter を入力します。

ext install ms-vscode-remote.remote-ssh

この拡張機能は Remote Development 拡張機能に含まれているので、そちらをインストールしても良いです。その場合は、Quick Open (Ctrl+P) で表示される入力欄へ次のコマンドを貼り付けてから Enter を入力します。

ext install ms-vscode-remote.vscode-remote-extensionpack

サポートされている環境は次のようになります。

  • x86_64 Debian 8+, Ubuntu 16.04+, CentOS / RHEL 7+ Linux.
  • ARMv7l (AArch32) Raspbian Stretch/9+ (32-bit).
  • ARMv8l (AArch64) Ubuntu 18.04+ (64-bit).
  • Windows 10 / Server 2016/2019 (1803+) using the official OpenSSH Server.
  • macOS 10.14+ (Mojave) SSH hosts with Remote Login enabled.

なお、Linux については glibc ベースのディストリビューションであれば含まれます。musl libc ベースのものはサポートされていないので注意が必要です。

Remote - SSH 拡張機能の使い方

次の手順で Remote - SSH 拡張機能を使うことができます。

  1. F1 で表示される入力欄で「Remote-SSH: Open SSH Host」
  2. 使用するユーザー名とホスト名(または IP アドレス)を ユーザー名@ホスト名 または ユーザー名@ドメイン名 のフォーマットで入力
  3. パスフレーズまたはパスワード入力のプロンプトが表示されたら、それを入力
  4. SSH ログインが成功したら、「File」-「Open Folder」でリモートマシンのフォルダーを開きます。

F1 キーで表示されるコマンドパレットで「Remote-SSH」と入力すると、使用可能なコマンドの一覧が表示されます。

なお、ここで、~/.ssh/configHost のエントリーを登録しておくと、Remote - SSH 拡張機能でそのホストを指定して SSH ログインができるようになります。複雑なオプション指定が必要な SSH ログインについては、この機能を活用しましょう。

拡張機能の管理

リモートマシンでの拡張機能の管理については、注意が必要です。ローカルとリモートで使える拡張機能は異なります。拡張機能は2つのカテゴリーに分類できます。

  • UI 用拡張機能。これはローカルホストにインストールされます。
  • Workspace 用拡張機能。これはリモートにインストールされます。

リモートにインストールされた拡張機能は、リモートの OS や CPU アーキテクチャで動作するものである必要があります。

Docker を使って試用

Docker を使って Remote - SSH 拡張機能の動作を確認することができます。ただし、前回使ってみた linuxserver/openssh-server のイメージは Alpine ベースで、これは Remote - SSH 拡張機能が対応していません。ということで、きちんと試すのは結構大変だったりします。

とはいえ、「これぐらいのことはできないとね」というものなのでやってみました。後で説明する openssh-vscode:ubuntu2204 イメージをビルドした後に、OpenSSH サーバーを起動します。

docker compose -f /openssh-vscode/compose.yaml up -d

それから、VS Code の Remote - SSH 拡張機能で openssh-vscode の openssh-server へ SSH ログインして試用ができます。

作成した環境について簡単に紹介します。詳しい説明はしませんが、簡単なコードしか用意していないので、これを見れば何をしているかは大体わかるはずです。

openssh-vscode ディレクトリー構造

openssh-vscode/
├── README.md ... このファイルと同じ内容
├── build-image/ ... ビルド用
│   ├── Dockerfile
│   ├── compose.yaml
│   ├── entrypoint.sh
│   ├── etc/
│   │   └── apt/
│   │       └── sources.list
│   └── script/
│       ├── add-user.sh
│       ├── install-basic-command.sh
│       ├── install-ext-command.sh
│       └── update-sshd-config.sh
├── compose.yaml ... コンテナー起動用
└── sample/
    ├── dot.ssh/
    │   ├── authorized_keys
    │   ├── id_ed25519
    │   ├── id_ed25519.pub
    │   ├── id_ed25519_pass
    │   ├── id_ed25519_pass.pub
    │   └── known_hosts
    ├── ssh_host_keys/
    │   ├── ssh_host_ecdsa_key
    │   ├── ssh_host_ecdsa_key.pub
    │   ├── ssh_host_ed25519_key
    │   ├── ssh_host_ed25519_key.pub
    │   ├── ssh_host_rsa_key
    │   └── ssh_host_rsa_key.pub
    └── ssh/
         └── config ... この内容を `~/.ssh/config` へ追加します。

openssh-server のエントリー作成

最初に用意する OpenSSH サーバーへの接続用エントリを ~/.ssh/config へ用意します。これで複雑な OpenSSH サーバーへの接続がホスト名を指定するだけで済むようになります。ここでは先に紹介した openssh-vscode ディレクトリーは /openssh-vscode に用意してあるとします。

Host openssh-server
  HostName localhost
  Port 2222
  User vscode
  IdentityFile  /openssh-vscode/sample/dot.ssh/id_ed25519_pass

このファイルは次のようにして所有者のみが読み書きできるモードにします。

chmod 600 ~/.ssh/config

動作確認用 compose.yaml

動作確認用の openssh-vscode/compose.yaml は次のとおり。イメージは ubuntu:22.04 ベースのものにしてあります。バインドマウントが多いのですが、ubuntu:22.04 だとホスト用のキーを個別に指定することになって、こうなってしまいました。

name: openssh-vscode
services:
  openssh-client:
    image: openssh-vscode:ubuntu2204
    container_name: openssh-client
    hostname: openssh-client
    tty: true
    user: 1000:1000
    entrypoint: /usr/bin/bash
    working_dir: /home/vscode
    volumes:
      - type: bind
        source: ./sample/dot.ssh/id_ed25519
        target: /home/vscode/.ssh/id_ed25519
        read_only: true
      - type: bind
        source: ./sample/dot.ssh/id_ed25519_pass
        target: /home/vscode/.ssh/id_ed25519_pass
        read_only: true
      - type: bind
        source: ./sample/dot.ssh/known_hosts
        target: /home/vscode/.ssh/known_hosts

  openssh-server:
    image: openssh-vscode:ubuntu2204
    container_name: openssh-server
    hostname: openssh-server
    tty: true
    ports:
      - 127.0.0.1:2222:22
    volumes:
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_ecdsa_key
        target: /etc/ssh/ssh_host_ecdsa_key
        read_only: true
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_ecdsa_key.pub
        target: /etc/ssh/ssh_host_ecdsa_key.pub
        read_only: true
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_ed25519_key
        target: /etc/ssh/ssh_host_ed25519_key
        read_only: true
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_ed25519_key.pub
        target: /etc/ssh/ssh_host_ed25519_key.pub
        read_only: true
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_rsa_key
        target: /etc/ssh/ssh_host_rsa_key
        read_only: true
      - type: bind
        source: ./sample/ssh_host_keys/ssh_host_rsa_key.pub
        target: /etc/ssh/ssh_host_rsa_key.pub
        read_only: true
      - type: bind
        source: ./sample/dot.ssh/authorized_keys
        target: /home/vscode/.ssh/authorized_keys
        read_only: true

openssh-server の方が VS Code をアタッチするコンテナー用です。openssh-client は、ssh コマンドの動作確認用コンテナーのために用意してあるものです。こちらは使わなくても良いです。openssh-server へアクセスできないときに確認用にしてください。こちらからアクセスできる場合はネットワークの問題になります。

鍵については、前回使ったものを流用しています。ただ、前回と違って、authorized_keys は次のものを用意しました。

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGiL8rnDO1D/SW5p3WnZ+0ctlek2PU1rUoJ9sGXMBF9j user001@openssh-server
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPu5/vlBHnJsuDr2zxDncVPGZ5jjbUUhKeyKOQhkFo0e user001@openssh-server pass

また、known_hosts も用意しました。

|1|FTkkYo05xCaf1xYoZgSg6zXn3vM=|8MMbIvS6m/iLur1f6DeAubGVuM8= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII4uYsbRjF9zA/NOTA3I4YAd0BpHTBNhXbf6EMmdAkzH
|1|M2uIQypapeZIl8FVZGX3S0LbDF4=|KE+K1hFWo5qZG6UIldS5ylV6boo= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCtW9eyKj9et068MnZIpvUtDZ+34l5bD55Jqahw80EzmNxF45Q+jWM2WoVMDk1aY+cokfDHghNPZ0iaoMzoNftDhz1guJMr53wX1z153z2IohLtnviibgT0dfsTRaUqZ8wg6JbFkcFuNUcNeKbS9sFdC11RY1g5I+0VJOQuISy2NfiaJqRKjJ3IrmmjHUM+4sInt8jt1E9L13y+291fzQNp7MqmkRwA/zD6xHbxk71fYYBr130CVxkoT+h+VEm2J/tL+7ZVQalR6JqAoXZNpVTjF+oaB+QWYxDmPdAwS3KwPae0JUGKXF+/JNyv97TNE4ipUUJOj/iqkUMLpBPlp3dUYf4vfZhHBOzQhU1h+l91r5mjF+eBVdfzgX4TwPhya1dBtHFV+rDhj6qVOK3vEjiVguZXRlJiTNgzuFsxrgXSj0gOmhr79scyCWOMvIgyhHZM5+iFw+yq7F3R/KhBJWx2zxV4gKZY5tGD6gYd7yh74/5Avr2wMnZqkTZhG7ahsJs=
|1|T6Zadz458qmDgfvkPN1Cf16Ak+Y=|3NAwSJNu5eilVBXX7omcrKH6zTU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHdwMzS0govO4ZCDtMqXhOiuE5uP/GwY2LOejE+6gK+gscgjxcj9U7Iop4XFxoWN2xBEv4f/y77hAZYH5Yf/5b8=

openssh-vscode:ubuntu2204 イメージ作成

openssh-vscode:ubuntu2204 のイメージ作成には、次のファイル openssh-vscode/build-image/compose.yaml を用意しました。

作成したイメージ名やオプションについて後でわかるようにビルド用に compose.yaml ファイルを用意する派です。

name: openssh-vscode-build
services:
  openssh-vscode-build:
    build:
      context: .
      dockerfile: Dockerfile
    image: openssh-vscode:ubuntu2204
    container_name: openssh-vscode-build
    hostname: openssh-vscode-build

Dockerfile は次のとおり。インストール関連はスクリプトにしておいて、それを利用する派です。流用がしやすくなります。

FROM ubuntu:22.04

ARG ARGS_TARGET=openssh-vscode

COPY script /usr/local/script
COPY etc/apt/sources.list /etc/apt/sources.list
COPY entrypoint.sh /

# root ユーザーで実行する処理
RUN apt-get update \
    && sh /usr/local/script/install-basic-command.sh \
    && sh /usr/local/script/install-ext-command.sh \
    && apt-get -y autoremove \
    && apt-get -y clean \
    && rm -rf /var/cache/apt /var/lib/apt/lists

# vscode ユーザーを用意し、vscode ユーザーが実行する処理
# vscode だけ sudo 権限ありのユーザーとして用意。ほかは sudo 権限はなし。
RUN SUDO=TRUE USERNAME=vscode bash /usr/local/script/add-user.sh \
    && sudo -u vscode sh -c "mkdir /home/vscode/.ssh" \
    && sudo -u vscode sh -c "chmod 700 /home/vscode/.ssh" \
    && USER=vscode sh /usr/local/script/update-sshd-config.sh \
    && echo "${ARGS_TARGET}: installed"

ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 22

apt は国内のミラーを使うよう、sources.list を置き換えています。

deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy main restricted
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy-updates main restricted
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy universe
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy-updates universe
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy multiverse
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy-updates multiverse
deb http://ftp.udx.icscoe.jp/Linux/ubuntu/ jammy-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
deb http://security.ubuntu.com/ubuntu/ jammy-security universe
deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse

install-basic-command.sh は次のとおり。

#!/bin/sh

DEBIAN_FRONTEND=noninteractive \
    apt-get install -y curl git gpg openssh-server sudo unzip wget zip

install-ext-command.sh は次のとおり。

#!/bin/sh

DEBIAN_FRONTEND=noninteractive \
    apt-get -y install byobu sysstat autossh openssh-client

add-user.sh は次のとおり。

#!/usr/bin/env bash

if [ "${USERNAME}" = "" ]; then
    USERNAME="vscode"
fi
group_name="${USERNAME}"

groupadd "${USERNAME}"
useradd -s /bin/bash --gid "${USERNAME}" -m "${USERNAME}"

if [ "${SUDO}" = "TRUE" ]; then
    echo "${USERNAME}" ALL=\(root\) NOPASSWD:ALL > "/etc/sudoers.d/${USERNAME}"
    chmod 0440 "/etc/sudoers.d/${USERNAME}"
fi

# Shell customization
user_home="/home/${USERNAME}"
if [ ! -d "${user_home}" ]; then
    mkdir -p "${user_home}"
    chown "${USERNAME}:${group_name}" "${user_home}"
fi

## Restore user .bashrc / .profile
possible_rc_files=( ".bashrc" ".profile" )
for rc_file in "${possible_rc_files[@]}"; do
    if [ -f "/etc/skel/${rc_file}" ]; then
        if [ ! -e "${user_home}/${rc_file}" ] || [ ! -s "${user_home}/${rc_file}" ]; then
            cp "/etc/skel/${rc_file}" "${user_home}/${rc_file}"
            chown "${USERNAME}:${group_name}" "${user_home}/${rc_file}"
        fi
    fi
done

update-sshd-config.sh は次のとおり。

#!/bin/sh

apt-get -y install openssh-server

if [ ! -e /root/ws ]; then
    mkdir /root/ws/;
fi
cp /etc/ssh/sshd_config /root/ws/sshd_config

cat << EOS | tee -a /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
X11Forwarding no
ClientAliveInterval 30
ClientAliveCountMax 3
AllowUsers ${USER}
EOS

sed -i "s/^X11Forwarding yes/#X11Forwarding yes/" /etc/ssh/sshd_config

CMD="diff /etc/ssh/sshd_config /root/ws/sshd_config"
if ${CMD} > /dev/null; then
    # 差分がないと失敗
    exit 1
else
    # 差分があると成功
    exit 0
fi

entrypoint.sh は次のとおり。

#!/bin/sh
if [ ! -e /run/sshd ]; then
    mkdir /run/sshd
fi
if [ ! -e /etc/ssh/ssh_host_ed25519_key ]; then
    /usr/bin/ssh-keygen -A
fi
exec /usr/sbin/sshd -D -e "$@"

ファイルを用意したら、ビルドします。これで、openssh-vscode:ubuntu2204 イメージが作成できます。

docker compose -f /openssh-vscoder/build-image/compose.yaml build

参考資料

Discussion