patorashのブログ

方向性はまだない

Vagrant + Hyper-V + Ubuntu18.04でRailsを動かせた

ずっとWindowsでの開発環境構築を試しているのですが、とりあえずベストではないにしてもベターまで来たかなと思うのでメモを残します。過去のトラブルはこちら。

patorash.hatenablog.com

patorash.hatenablog.com

なお、Hyper-Vを使わずにVirtualBoxを使うほうを強くお勧めします!(ハマりどころが少ないだろうから)

VagrantHyper-Vを選ぶ際のTips

VagrantでプロバイダをHyper-Vにすることができますが、制限事項がかなり多いです。

フォルダ共有にはsmbを選んだほうがよさそう

フォルダ共有はNFSがいいという意見がネットでは多いのですが、どうもVirtualBoxだとうまく動くみたいなのですが、Hyper-Vだと動かない模様。試行錯誤したのですが、私にはわからなかったため、smbを使って共有しています。以下のissueでは、Hyper-VだったらSMBでいいという話になっているみたいでした。

github.com

また、SMBでフォルダ共有を行う場合は、vagrant upを実行する都度、Windowsにログインするためのユーザ名とパスワードの入力を求められるので、これを最初はVagrantfileに直書きしていたのですが、vagrantのdotenvプラグインがあるとのことだったので、これを使うようにしました。

vagrant plugin install dotenv

これで、.envファイルにログイン情報を移動させることができます。

SMB_USER = "" # Windowsのユーザ名
SMB_PASS = "" # Windowsのパスワード

そして、これを使うようにVagrantfileを編集します。

# -*- mode: ruby -*-
# vi: set ft=ruby :
Dotenv.load # 追加

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provider "hyperv"

  config.vm.synced_folder "~/vagrant",
    "/vagrant",
    create: true,
    type: "smb",
    mount_options: ["vers=3.0"],
    smb_password: "#{ENV['SMB_PASS']}",
    smb_username: "#{ENV['SMB_USER']}"

  # 略
end

これでOK…と思ったら、ところがどっこい、vagrant upするとホストのIPが見つからないというエラーで共有できませんでした。これは、接続する仮想スイッチのネットワークをパブリックとワークからプライベートネットワークにすれば解決しました。上のほうに載せている過去記事を見ていただければと思います。

Vagrantのポートフォワーディングは使えない

とりあえずこれで、Windows側とHyper-V上のUbuntuでフォルダ共有できたので、Vagrantfileを修正してポートフォワードするようにして、Ubuntu側でRailsを起動してみました。

# 追加
config.vm.network "forwarded_port", guest: 3000, host: 3000, host_ip: "127.0.0.1"

が、うんともすんとも言いません…。調べてみると、どうもHyper-Vの場合はネットワークの設定は全て無視されるようです。 なので、上記の設定は何の意味もない模様。

では、Hyper-Vの場合はどうすればいいのか?Windows側でポートフォワーディングの設定を行う必要があります。参考にちょうどよいページがありました。

4thsight.xyz

これを参考に、設定してみます。192.168.212.51は、VM側に設定されているIPです。

netsh interface portproxy add v4tov4 listenport=3000 listenaddress=127.0.0.1 connectport=3000 connectaddress=192.168.212.51

これで、VM側の3000番ポートがホスト側にポートフォワードされるようになりました。Windowsのブラウザでhttp://localhost:3000にアクセスしたら、Ubuntuで起動中のRailsアプリにアクセスできました!なお、Railsアプリを起動するときはbin/rails s -b 0.0.0.0を忘れずに!!

これで、とりあえずやった!というお気持ちを表明。

Hyper-Vの仮想スイッチ(Default Switch)は使えない

ここで、過去にPCを再起動したらVMのIPが変わっていたことを思い出しました。

ということで、Windowsを起動すると仮想スイッチのDefault SwitchのIPがコロコロと変わり、全く意味がない模様。

yamanxworld.blogspot.com

せっかくnetshでポートフォワードの設定を書いたのに、台無しです…。こうなると、自分で仮想スイッチを定義するのがよさそうです。しかし、自分で作った仮想スイッチだとVMにIPの割り当てを行ってくれず、VM側でIPを設定する必要がある模様。なんとか自動でIPをふる方法を調べていたのですが、見つからなかったので、公式の言う通りにしてみます。

docs.microsoft.com

仮想スイッチの作成とNATの設定

以降の処理は、PowerShellで、管理者権限で。まず、Switchを作ります。

New-VMSwitch -SwitchName "VagrantNAT" -SwitchType Internal

次に、Switchの情報を見ます。ifIndexが必要な情報となります。

Get-NetAdapter

Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
vEthernet (VagrantNAT)    Hyper-V Virtual Ethernet Adapter #2          10 Up           00-15-5D-8F-1B-31        10 Gbps
# 他は省略

次に、仮想スイッチにIPを割り当てます。今回は192.168.100.1にしました。-InterfaceIndexに先ほどのifIndexの値を指定します。

New-NetIPAddress -IPAddress 192.168.100.1 -PrefixLength 24 -InterfaceIndex 10

次に、NATネットワークを作ります。

New-NetNat -Name VagrantNATnetwork -InternalIPInterfaceAddressPrefix 192.168.100.0/24

これで、ネットワークは完成です。VMへのIPの割り当ては別途VMに入って行います。

VM側のIP設定を行う

VMはとりあえずvagrant upを行います。IPは割り当てられませんが、作業にはvagrant sshが使えるので問題ありません。

vagrant sshを使ってVMの中に入り、IPを設定します。Ubuntu18.04からIPの設定方法が変わった模様です。

jyn.jp

sudo vi /etc/netplan/01-netcfg.yaml

これで、以下のように設定しました。

network:
  version: 2  
  ethernets:
    eth0: 
      addresses:
        - 192.168.100.2/24
      gateway4: 192.168.100.1
      dhcp4: false
      nameservers:
        addresses:
          - 8.8.8.8

nameserversは、192.168.100.1にしたらapt-getに失敗したので、8.8.8.8にしています。 そして、netplanの設定を反映します。

sudo netplan apply

これで、VMに固定IPが設定されました。

ポートフォワードの設定をやり直し

既存の設定は意味がないので、resetで削除し、先ほど登録したVMのIPでポートフォワードの設定をやり直します。

netsh interface portproxy reset
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=127.0.0.1 connectport=3000 connectaddress=192.168.100.2

これで完了!VM側でRailsアプリを起動したところ、http://localhost:3000でアクセスできました🎉🎉🎉

なお、PCを再起動しても問題ありませんでした!ただ、Vagrant自動起動にしていたらSMBの共有に失敗していたので、vagrant reloadしたらうまくいきました。

まだまだ開発環境としては問題がありそうなのですが(SMB上にRailsアプリを置いてrails sすると遅い…)、とりあえず動かせたので、よしとします。