Node.js の開発では Docker for Mac が便利ですが、仕組み的にディスクアクセスが遅くなるので、処理性能が半分とまではいかないものの、3割くらい遅いです。そこで Docker for Mac のお手軽環境を諦めて、代わりに VirtualBox 上で Docker を使うと、ほとんど性能劣化なく動くようです。
VirtualBox 上で動かす VM は何でも良いのですが、プロダクション環境は AWS が多いので、今回は VM にも Amazon Linux 2 を使うことにします。各ファイルも VirtualBox 上の VM 側に置いて、Mac から NFS でアクセスします。
(1) VirtualBox をインストールする。
https://www.virtualbox.org/wiki/Downloads の「OS X hosts」から、VirtualBox をダウンロード・インストールする。120MB くらい。
(2) VirtualBox > ファイル > ホストネットワークマネージャー > 作成
(3) Amazon Linux 2 の VM イメージをダウンロードする。
https://cdn.amazonlinux.com/os-images/latest/virtualbox/ から
最新の VM イメージ amzn2-virtualbox-2.0.20200304.0-x86_64.xfs.gpt.vdi をダウンロードする。1.5GB。
(Amazon Linux 2 LTS 2.0.20200304.0 x86_64 VirtualBox image)
(4) cloud-init 用の ISO イメージ (cidata) を作成する
mkdir -p ~/Desktop/amzn2
cd ~/Desktop/amzn2
mkdir seedconfig
cat <<__EOT__>seedconfig/meta-data
local-hostname: amzn2
__EOT__
cat <<__EOT__>seedconfig/user-data
#cloud-config
# ↑1行目の「#cloud-config」を抜かないこと。
# デフォルトで ec2-user ユーザが作成される。
users:
- default
# ec2-user ユーザのパスワードを指定する。: の後にスペースを入れると、スペース入りのパスワードになるので注意。
chpasswd:
list:
- "ec2-user:amazon"
# あとで eth1 を作るために、vboxnet0 のネットワーク内の IP アドレスを指定する。
write_files:
- path: /etc/sysconfig/network-scripts/ifcfg-eth1
content: |
BOOTPROTO=static
DEVICE=eth1
IPADDR=192.168.56.78
ONBOOT=yes
TYPE=Ethernet
PREFIX=24
PEERDNS=no
IPV6INIT=no
DEFROUTE=no
EC2SYNC=no
USERCTL=no
PERSISTENT_DHCLIENT=no
__EOT__
mkdir -p ~/VirtualBox\ VMs
# ISO イメージを作成する
hdiutil makehybrid -o ~/VirtualBox\ VMs/seed.iso -hfs -joliet -iso -default-volume-name cidata seedconfig/
# ダウンロードした VM イメージも、コピーしてから使う
cp -p ~/Downloads/amzn2-virtualbox-2.0.20200304.0-x86_64.xfs.gpt.vdi ~/VirtualBox\ VMs/amzn2.xfs.dvi
(5) VirtualBox > 仮想マシン > 新規
- 名前:amzn2
- マシンフォルダー:/Users/xxxx/VirtualBox VMs(デフォルト)
- タイプ:Linux
- バージョン:Linux 2.6 / 3.x / 4.x (64-bit)
- メモリーサイズ:2048MB
- ハードディスク:すでにある仮想ハードディスクファイルを使用する → amzn2.xfs.dvi を選択
(6) amzn2 > 設定 > ストレージ
- コントローラー:IDE の右側の [+] ボタンから、seed.iso を追加する。
- 画面下部の「新しいストレージコントローラを追加します」「新規のストレージ割り当てを追加します」ではなくて、「光学ドライブの追加」を選ぶ。
(7) amzn2 > 設定 > ネットワーク > アダプター1
- ネットワークアダプターを有効化:ON(まま)
- 割り当て:NAT
- 備考:アダプター1= eth0 は、VM からの上り回線用。Mac 側の上流回線が何でもOK。LAN 内から VM へのアクセスを防ぐ。
(8) amzn2 > 設定 > ネットワーク > アダプター2
- ネットワークアダプターを有効化:ON
- 割り当て:ホストオンリーアダプター
- 名前:vboxnet0
- 備考:アダプター2=eth1 は、Mac から VM への接続用。eth0 をリセットしても、eth1 は通じる。
(9) amzn2 > 起動
- VM を起動する。
- 初回は ssh が効かないので、VirtualBox の画面から ec2-user ユーザでログインする。
- cloud-init の設定をすれは、初回から SSH 接続できるだろうけど、デフォルトではできないので、妥協。
# 以下は VM 内で実行する
sudo su -
# ホストオンリーアダプターを有効化する
ifup eth1
# 自分のアクセス用のユーザ foobar を作成する。
# 自分の uid と docker の gid は固定しておくと、あとで面倒がない。
# ここでは 1234 としているが、1001 を指定した方が便利かも?
adduser -M -u 1234 foobar
groupadd -g 987 docker
usermod -aG docker foobar
# ssh 公開鍵 authorized_keys を設定せずに、パスワードで SSH 接続する場合
passwd foobar
sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
systemctl reload sshd
(10) Mac から SSH 接続でログインする
# Mac 側の Terminal.app で実行する
echo "192.168.56.78 amzn2" | sudo tee -a /etc/hosts
ssh foobar@amzn2
# 以下は VM 内で実行する
sudo su -
#(オプション)ダウンロードした .rpm パッケージを残したい場合
sed -i 's/^keepcache=0/keepcache=1/' /etc/yum.conf
#(オプション)yum や apk のキャッシュ用に Squid を入れる場合
yum install -y squid
systemctl enable squid
systemctl start squid
tail -f /var/log/squid/access.log /var/log/squid/cache.log
echo 'proxy=http://127.0.0.1:3128' >> /etc/yum.conf
#(オプション)他にも必要なパッケージがあればインストールする
yum update -y
yum install -y git
(11) Docker を使う
ssh foobar@amzn2
# 以下は VM 内で実行する
# Docker をインストールする
sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker
# foobar ユーザ権限でも Docker を使えるのを確認する
docker run hello-world
(12) NFS サーバを設定する
ssh foobar@amzn2
# 以下は VM 内で実行する
sudo su -
# NFS をインストールする
yum install -y nfs-utils
systemctl start nfs-server.service
systemctl enable nfs-server.service
# ホストオンリーアダプター(自分の Mac)からのみ NFS 接続を許可する
echo "/home/foobar 192.168.56.0/24(rw,sync,no_subtree_check,insecure,all_squash,anonuid=1234,anongid=1234)" > /etc/exports
exportfs -ar # 更新
exportfs -v # 確認
(12) Mac から NFS をマウントする
# Mac 側の Terminal.app で実行する
sudo mkdir /Volumes/foobar
sudo mount -t nfs amzn2:/home/foobar /Volumes/foobar
# Mac から NFS 経由でアクセスできるようになった
ls -l /Volumes/foobar
df -m /Volumes/foobar
open /Volumes/foobar
# マウント解除する場合(Finder.app からもアンマウントできる)
sudo umount /Volumes/foobar
あるいは、NFS でなくて Samba でも、VM 内のファイルを Mac から操作できますが、NFS の方が良さそう。
VM を動かすホストを別マシンに分けても(有線 LAN なら)NFS 経由で問題ない速度でアクセスできます。
(備考)Samba と NFS の比較:
Samba
⭕ Finder からマウント操作できるので分かりやすい
⭕ 設定でアクセスするユーザアカウントを指定可能。
❌ パーミションの互換性や、シンボリックリンクで面倒な事態が発生
NFS
⭕ 1ユーザの環境なら、パーミションも問題なし。
⭕ UNIX 同士なので、シンボリックリンクも問題なし。
❌ マウントするときに mount コマンドを叩く必要がある(切断は Finder から操作できる)
PS.
Docker for Mac ができる前の時代に戻った感覚ですが、ちょっとこれでしばらく運用してみようかと。
Node.js については Docker for Mac もまだ現実的な速度なんだけど、PHP (WordPress) はファイルアクセスが多いためか、数倍は遅くて、使い物になりませんでした。
『Alpine のメモリが遅い』という話もみかけましたが、Node.js については、試した限りでは、メモリは問題なくて、ディスクアクセスの影響が大きいように感じています。
Windows なら WSL 2 でそろそろ直接 Docker が動くようなので、羨ましいですね。