Help us understand the problem. What is going on with this article?

Visual Studio Code - "Remote Development" を使って Docker Container on "Vagrant + VirtualBox" のファイルを編集する

要約

  • Vagrant で構築した仮想環境の中にある Docker へ繋げるときは 多段SSH を使う。
  • Docker Container に SSHサーバ を構築する必要がある。
  • VS Docde の Remote Development は Remote SSH を使用する。

はじめに

VS Code に Remote Development と呼ばれる拡張機能が追加されました。

数ヶ月遅れでその機能の素晴らしさに気づき、その活用方法をメモしておこうと記事を作成します。

基本的な用途は以下のクラスメソッドさんの記事が分かりやすいので参照ください。

【設定爆速】VS CodeのRemote Developmentを使ってSSH接続したEC2上のファイルを編集する

概要

書くこと

  • VS Code Remote Development の活用方法
    • 多段SSH を用いて、2つ先の仮想環境に繋げる方法
  • docker container を作るポイント
  • ホストOS の設定( .ssh/config

書かないこと

  • Vagrant で Docker / docker-compose の環境を作る方法

想定環境

この記事で実現するシステムの構成は下図の通りです。

image.png

上図の通り、VS Code の Remote Development を使用して、リモート環境のコードを VS Code の UI で直接編集出来るようにします。

また、多段SSH の仕組みを用いて、1つ目の仮想環境の先に存在する Docker コンテナ に対しても同じ仕組みでコードの編集が出来るようにします。

今回の仕組みを実現した環境の詳細は以下の通りです。

Item Version
HostOS Windows 10
VirtualBox 5.2.18 r124319 (Qt5.6.2)
command
> vagrant -v
Vagrant 2.1.2

> vagrant plugin list
vagrant-disksize (0.1.2)
vagrant-docker-compose (1.5.1)
vagrant-omnibus (1.5.0)
vagrant-proxyconf (1.5.2)
vagrant-vbguest (0.15.2)

> vagrant box list
centos/7         (virtualbox, 1905.1)
command
$ rpm -qa kernel\* | sort
kernel-3.10.0-1062.9.1.el7.x86_64
kernel-3.10.0-957.12.2.el7.x86_64
kernel-devel-3.10.0-1062.9.1.el7.x86_64
kernel-headers-3.10.0-1062.9.1.el7.x86_64
kernel-tools-3.10.0-1062.9.1.el7.x86_64
kernel-tools-libs-3.10.0-1062.9.1.el7.x86_64

Remote Development が実現すること

「ローカルPCのコードを修正して、それで十分?」

近年のソフトウェア開発の現状として、次のような傾向があります。

  • 特定のコンテナやVMでのみでアプリケーションが動作する。
  • ローカルでは実現出来ない実行環境が多くある。

こういった現状の中で、ローカルPCでソースコードのみ修正出来たとしても、以下のようなケースにおいては、手間が増えてしまいます。

  • 実行環境へのデプロイが必要である。
  • IDEが直接コードを実行することで実現出来るようや動的解析機能のため、ローカルPCにも開発キットの導入が必要なケースがある。

例えば次の図のように、コンテナ上に PHP の実行環境を作って動作出来るようにした場合を考えます。
コンテナ上のアプリケーションは意図した通りに動くでしょうが、 VS Code で静的解析や動的解析を行いたい場合、別途、Host OS や ローカルPC上の VS Code に手を加える必要が出てきます。

image.png

また、Web Application をチーム開発する場合には、Docker などで共通化した仮想環境を作成して配布することが多いと思いますが、ローカルPCで別途設定が必要となると、全てが共通化出来ているとは言えず、面倒な手間も増えてしまいます。

リモート環境のコンテクストで、リッチなローカル開発環境の提供

VS Code の Remote Development を使用することで ローカルPC 上の VS Code を使用して、リモート環境にあるコードを違和感なく編集することが出来ます。

image.png
cited from Remote Development with VS Code - Visual Studio Code

3つの拡張機能

Remote Development は、次の3つリモート環境に対応しています。

  • remote workspaces running in WSL
  • remote workspaces running in Docker containers
  • remote workspaces running in physical and virtual machines over SSH

image.png
cited from Remote Development with VS Code - Visual Studio Code

Architecture and extension

Remote Development は、大きく別けて以下の2つの extension から構成されています。

  • UI Extensions
  • Workspace Extensions

この2つは、下図のようなアーキテクチャで構成されています。

image.png
cited from Supporting Remote Development and Visual Studio Online - Visual Studio Code

実現のイメージ

今回の記事では、次のように、ホストOS の VS Code から 仮想環境のコードを編集出来るようにすることを目指します。
特に、仮想環境の上にある Docker Container を、同じ仕組みでどのように実現するかがポイントです。

image.png

設定手順

設定を行うにあたって、 Docker や docker-compose の導入以外で特徴的な作業としては次の3つがあります。

  1. Docker Container に sshd サーバを構築し、 root ユーザでログイン出来るようにする。
  2. Docker Container 起動時に Port Forward 設定を行う。
  3. Host OS に ssh/config 設定を追加する。

これらを図で示すと以下のようになります。

image.png

この設定を行うことで、 HostOS に存在する VS Code の Remote Development を使用して、2つ先の Docker Container に対して Remote SSH 接続を行うことが出来ます。

1. Vagrant 環境の構築

まず最初に、 Docker と docker-compose をインストールした 仮想環境を構築します。
この手順は本筋ではないので、次の手順で構築してください。
(設定内容は anfangd/docker-on-vagrant-script - GitHub を参照ください。)

command(powershell)
## Vagrant のプラグインをインストールする
> vagrant plugin install vagrant-vbguest
> vagrant plugin install vagrant-proxyconf

## GitHub から Vagrantfile と provision.sh を取得する
> git clone https://github.com/anfangd/docker-on-vagrant-script.git
> cd docker-on-vagrant-script

## Vagrant の起動する
> vagrant up

vbguest に関連するエラーが発生した場合は以下を参照してください。
(kernel version のミスマッチによってエラーが発生する可能性があります。)

2. .ssh/config の設定(その1)

次のコマンドで、Vagrant で起動している仮想環境の ssh-config を確認することが出来ます。

command(powershell@Windows10)
> vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

上記のコマンドで確認した内容を、 .ssh/config にコピペします。
なお、Host名は任意の名前に変更してください。

これらは Windows 10 向けの設定のため、macOS などの場合は適宜 PATH の修正などを行ってください。

.ssh/config(Windows10)
Host vagrant-os
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

3. 秘密鍵の転送

Guest OS から Docker に接続するために、 Vagrant が自動生成した 公開鍵のペアを使用します。
Host OS 上に秘密鍵が存在するので、 Guest OS へ秘密鍵をコピーします。

command(powershell@Windows10)
## 注意 `vagrant up` したディレクトリで実行する
> scp .vagrant/machines/default/virtualbox/private_key vagrant-os:/home/vagrant/.ssh/

## Guest OS に SSH接続
> vagrant ssh

## private_key の実行権限を変更(Guest OS 内)
$ chmod 600 ~/.ssh/private_key

4. Docker Container の起動

Docker を実行出来る仮想環境の構築が出来たら、 Docker Container を構築します。
以下は今回使用する Dockerfile です。

Dockerfile
# image
FROM php:7.0.15-fpm

ENV LANG C.UTF-8

RUN apt-get update -qq && \
    apt-get install -y \
        zlib1g-dev \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
        && docker-php-ext-install zip \
        && yes "" | pecl install xdebug \
        && docker-php-ext-enable xdebug \
        && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
        && docker-php-ext-install -j$(nproc) gd

RUN apt-get update \
    && apt-get install -y libpq-dev \
    && docker-php-ext-install pdo_mysql pdo_pgsql

RUN apt-get update \
    && apt-get install -my wget gnupg

WORKDIR /opt/

# ここから最後までがポイント
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd

## /etc/ssh/sshd_config の設定書き換え
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

# 公開鍵をコピー
COPY authorized_keys /root/authorized_keys

EXPOSE 22

# Activate authorized_keys & Boot sshd
CMD mkdir ~/.ssh && \
    mv ~/authorized_keys ~/.ssh/authorized_keys && \
    chmod 0600 ~/.ssh/authorized_keys &&  \
    # 最後に ssh を起動
    /usr/sbin/sshd -D

上の Dockerfile のうち、後半部分で openssh-server の導入や 公開鍵認証の設定などについて記載しています。

Docker Container の起動は次のコマンドで実行します。

command(bash@CentOS)
$ pwd
/vagrant/docker-sample

# 公開鍵をコピー
$ cp ~/.ssh/authorized_keys .

$ ls
Dockerfile authorized_keys

# build
$ docker build ./ -t example

# Docker Container を起動
# Port:10000 を Port:22 に転送
$ docker run -d -p 10000:22 example

# Docker Container に SSH 接続
$ ssh root@127.0.0.1 -p 10000 -i ~/.ssh/private_key

5. .ssh/config の設定(その2)

2.) で設定した .ssh/config に設定を追加します。

.ssh/config(Windows10)
Host vagrant-os
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

# 以下を追加
Host docker-os
  Hostname 127.0.0.1
  User root
  Port 10000
  ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p vagrant-os
  IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key

上記の設定で Docker Container に接続出来るか確認してみましょう。

command(powershell@HostOS)
> ssh docker-os

これで接続できれば設定は完了です。

6. Visual Studio Code の設定

前節までの設定が出来てしまえば、あとは以下の記事の通り extensions をインストールして開けば使用出来ます。

以下のように、CentOS へのアクセスを示す vagrant-os に加え、その上の Docker Container である docker-os も開けるようになっています。

image.png

extra-1. 【HostOS←→GuestOS】 のフォルダ同期を停止する

Vagrant で構築した GuestOS のフォルダと HostOS のフォルダを同期する方法は、非常に便利なようで厄介な点がいくつかあります。
私は以下のような事象で時間を取られることがよくあります。

  • Vagrant や Box のバージョンアップで頻繁にエラーが発生する。
  • GuestOS 内の Webサーバと通信する時、HTTP アクセスが遅くなる。
  • npm install する時にエラーが発生する。

ただ、今回の記事で使用した VS Code - Remote Development を使用すれば、ファイル同期の必要がなく、仮想環境内のファイルを直接修正出来るのでこのファイル同期の仕組みが不要になります。

同期をしないようにするには、以下のように Vagrantfile を修正して vagrant reload すれば良いだけなので非常に簡単です。

Vagrantfile(@HostOS)
<略>
  # Synced Folder
  #config.vm.synced_folder "./", "/vagrant", type:"virtualbox", mount_options: ['dmode=777','fmode=777']
  config.vm.synced_folder ".", "/vagrant", disabled: true
<略>

一方で、これをしてしまうと、これまで当たり前に出来ていたことが一部できなくなってしまいます。
想定されるケースと対策で重要そうなものを以下に記載します。

  • GuestOS にファイルを配置する。
    →scp コマンドなどで転送する。
  • 仮想環境と同期しているフォルダの git リポジトリを Sourcetree で参照していた場合の対処法
    →VSCode の拡張機能で代替する。
  • Vagrant の Box を誤って削除してしまう。
    →HostOSとファイル同期してないので、中身は消えてしまいます。
     こまめに commit & push して、Vagrant Box の環境は削除される前提で作業しましょう。

おわりに

多段SSH方式、めちゃくちゃ便利ですね。
Remote Container で実現する方法を模索して時間を浪費してしまったのですが、多段SSH方式でスムーズに実現することが出来ました。

そして何より、 Visual Studio Code さん、どんどん使いやすさが増してゆきます。

TODO

参考

Vagrant + VirtualBox で Docker 環境を構築する。

Vagrant で共有フォルダ設定でエラーが出来た時の対処法

※ Remote Development 機能の出現によって、この共有をしない方が開発が効率的になる可能性有り。

多段SSHの実現方法

anfangd
Web Application Developer
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした