Docker Engine on Vagrant (VirtualBox) on Linux な環境を用意する

Vagrantによる仮想マシンでDocker Engineを動かしてみました.

この手の記事, n番煎じかわかりませんが, 参考にできるまとまった記事を見つけられず試行錯誤したところがちょっとだけあったので, 記しておきます.


# 目的と背景

使っているマシンは Linux (archlinux).

Docker Machine (VirtualBox + boot2docker) がDeprecatedへ移行したあとも, ずっと使っていました.

「LinuxならネイティブでDocker使えるのでは?」

という疑問もっともなのですが, ホストで稼働するDocker Machineの操作には権限が必要.
suするかdockerコマンドにsudoをつける必要があり, ちょっとしたお遊びや検証用とで毎回それをやるのは精神衛生的によろしくない.

また, ログインユーザーをdockerグループに加えるでもクリアできます.
しかし, それはroot権限を与えているも同等で (`--privileged` オプション), やはり気楽さに欠けます.

という理由で, Docker Machineだったのですが, Engineバージョンが古いママであるためにできないことがちょっとずつ出てきています.
代替手段としてVagrant (VirtualBox) 上の仮想マシンでDocker Engineを動かすことを試みました.

長くなりましたが, ここまでが背景.

目的は Docker Machine (boot2docker) を代替できて, かつユーザー権限で操作可能なDocker Engine環境を用意することです.

この記事を下敷きにしてます. これはホストがmacosですね.

https://blog.avenuecode.com/running-docker-in-a-vagrant-vm


# 検証に使った環境

あまり細かいことに意味はないかもですが.

* docker 20.10.14
* docker-compose 2.4.0
* vagrant 2.2.19
* virtualbox 6.1.32

on ArchLinux.

あと, Vagrantぜんぜん詳しくありません.


# 手順

ここから手順と検証結果.


## Vagrantfile を用意する

適当なディレクトリに Vagrantfile を作成します.
作成といってますが, 実際は `vagrant init` コマンドで作ったファイルをイジイジした最終的なものがこれです.

```ruby:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"

  config.vm.network "private_network", type: "dhcp", name: "vboxnet1"

  config.vm.provision "shell", inline: <<-SHELL
  curl -fsSL https://get.docker.com | sh
  sudo curl -L \
    https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` \
    -o /usr/local/bin/docker-compose
  sudo chmod +x /usr/local/bin/docker-compose
  sudo adduser vagrant docker
  SHELL
end
```

ベースは Ubuntu 20.04 にしました.

いくつか補足します.


### ホストオンリーネットワークを使う

Vagrantはデフォルトでブリッジ接続する仮想マシンを作成するようで,
ホストマシンと同じセグメントの仮想マシンが作られます.

それはちょっと嫌かなと思ったので, VirtualBoxの配下となるようホストオンリーネットワークにしました.

```ruby
config.vm.network "private_network", type: "dhcp", name: "vboxnet1"
```

IP決めてVagrantfileに書くのが面倒だったので, DHCPを使用.

ちなみにVirtualBoxの既存のホストネットワークが使えるかと思ったら, VM起動のときに, 次のエラーが出てしまいました.

> A host only network interface you're attempting to configure via DHCP
> already has a conflicting host only adapter with DHCP enabled. The
> DHCP on this adapter is incompatible with the DHCP settings. Two
> host only network interfaces are not allowed to overlap, and each
> host only network interface can have only one DHCP server. Please
> reconfigure your host only network or remove the virtual machine
> using the other host only network.

VirtualBoxの画面でホストネットワークマネージャーを開き, DHCPを有効にしたホストネットワークを作成し,
その名前「vboxnet1」を指定しています.
これで解決しましたが, 理由はよくわかりません (気にしてません).


### プロビジョニングでDocker EngineとDocker Composeをインストール

このへんは見たままですが, aptコマンドではなく,
Docker公式のスクリプトでDocker本体とDocker Compose をインストールしています.

```ruby
config.vm.provision "shell", inline: <<-SHELL
curl -fsSL https://get.docker.com | sh
sudo curl -L \
  https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` \
  -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo adduser vagrant docker
SHELL
```

デフォルトのユーザー vagrant をdockerグループに加えてます.

```ruby
sudo adduser vagrant docker
```


## 仮想マシンを起動し, プロビジョニングで諸々インストールする

Vagrantfile があるディレクトリをカレントにして, 次のコマンドを実行.

Docker, Docker Composeのインストールと, 操作ユーザの設定をおこないます.
```sh
$ vagrant up
```


## 仮想マシンにssh接続して, dockerコマンドを試しておく

ここまで正常に進んでいたら, 起動した仮想マシンにssh接続して,
かんたんにdockerが動いているかを確認しておきます.

まずsshで仮想マシンに接続.

```sh
$ vagrant ssh
```

接続できたら, ついでに仮想マシンに割り振られたIPを見ておきます.

```
$ vagrant ssh
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-105-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Fri Apr  8 18:42:39 UTC 2022

  System load:  0.46              Users logged in:          0
  Usage of /:   5.1% of 38.71GB   IPv4 address for docker0: 172.17.0.1
  Memory usage: 26%               IPv4 address for enp0s3:  10.0.2.15
  Swap usage:   0%                IPv4 address for enp0s8:  192.168.57.5
  Processes:    119


25 updates can be applied immediately.
18 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
```

IPは「192.168.57.5」

続いて, dockerコマンドを試します. 次のコマンドを実行.

```sh
$ docker run --rm hello-world
```

「Hello from Docker!」という出力がでたら, それでOK.
`exit` で仮想マシンからログアウトします.


## ホストから仮想マシンのDocker Engineを操作するための準備

さきほどは `vagrant ssh` コマンドで接続しましたが, 次は `ssh` コマンドでつなげるようにします.
Vagrantが生成してくれたSSH接続用の秘密鍵を登録.

```sh
ssh-add .vagrant/machines/default/virtualbox/private_key
```

続いて, sshコマンドで仮想マシンへ接続.

```sh
$ ssh -lvagrant -p22 192.168.57.5
```

問題なければログアウト.

次に `DOCKER_HOST` という環境変数を設定しておきます.

```sh
# fishなら
$ set -x DOCKER_HOST "ssh://vagrant@192.168.57.5:22"

# bash/zshなら
$ export DOCKER_HOST="ssh://vagrant@192.168.57.5:22"
```

ちなみに, 接続時のIPアドレスに仮想マシンのものを使ってますが,
Vagrantは仮想マシンのSSH 22番ポートをローカルの2222番ポートに転送してるので,
IP 127.0.0.1, ポート 2222 と読み替えてもだいじょうぶ.


## ホストからdockerコマンドを試す

ようやく, ホストから仮想マシンのDocker Engineを操作してみます.

次のコマンドを実行.

```sh
$ docker run -p18000:18000 --rm python:3.10 python -mhttp.server --bind 0.0.0.0 18000
```

ここでは次のことをチェックします.

* ホストから仮想マシンのDocker Engineを操作
* docker runコマンドのportオプション (ポート転送)

コンテナが起動したような表示になったら, もうひとつターミナルを用意して次のコマンドを実行.


```sh
$ curl -s -v -o/dev/null "http://192.168.57.5:18000"
```

docker run コマンドを実行したターミナルに, こういう出力.

```sh
192.168.57.1 - - [08/Apr/2022 19:09:18] "GET / HTTP/1.1" 200 -
```

curl を実行したほうにこういう出力があればOK.

```
> GET / HTTP/1.1
> Host: 192.168.57.5:18000
> User-Agent: curl/7.82.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.10.4
< Date: Fri, 08 Apr 2022 19:09:18 GMT
< Content-type: text/html; charset=utf-8
< Content-Length: 297
```


# 最後に

というわけで, Dockerを使う作業の一通りのことはできたのではないかなと思います.
Docker Composeも動きました (冗長な気がしたので割愛しました).

ボリューム共有のこと忘れてました. デフォだとVagrantfileがある場所?
vagrant upコマンドを実行した場所が 仮想マシンの /vagrant ディレクトリにマウントされるみたいです.
同じパスにマウントできないと, やや使いづらいので, 要検証.

ネットワークもどうするのがいいかは使ってみてからまた考える.

なんか動きがモッサリしてます. なぜだろう?
実用するかはわかりませんが, 他にわかったことや気になったことがあったら追記します.

最後に書きますが, Linux向けのDocker Desktopの提供が控えており, 現在はbeta版の模様.

https://www.publickey1.jp/blog/21/docker_desktop_for_linuxdocker.html

https://docs.docker.com/desktop/linux/

beta版がサポートするディストリビューションが中途半端 (Ubuntu 21.04, 24.10) なのと, AURになかったので,
Vagrantを試してみたくなったというのもありました.