Oracle VM VirtualBox で Linux演習環境のイメージを作成する


# やること
社内で Oracle VM VirtualBox(以下 VirtualBox) を使ってLinux研修をする際に、毎回インストールするのは面倒なので配布イメージを作ってみた。


# 構成する環境
Linux研修ではRPM系のCentOS6とDebian系のUbuntu16.04の使う想定だが、VirtualBoxでそれぞれのLinuxを別々の仮想マシン(以下 VM)で構築するのは面倒なので、下図のような感じでコンテナ環境を作ってみることにした。

![サーバー構築環境_ネットワーク図.png](https://qiita-image-store.s3.amazonaws.com/0/108371/445f4cf1-e12f-bc5a-dcc8-a7acaa784cba.png)


# 環境
- Windows7 Pro SP1 32bit
- Oracle VM VirtualBox 5.2.18 ＋ Extension Pack

# やったこと
## (VBox)VirtualBoxにUbuntu16.04をインストールする 
基本的にはデフォルトのままで、OpenSSH Server を入れておく。

## (VM)インストールしたUbuntuの初期設定

リポジトリを修正

```shell-session
root@ubuntu:~#
root@ubuntu:~# vi /etc/apt/sources.list
deb http://jp.archive.ubuntu.com/ubuntu bionic main restricted universe multiverse
deb http://jp.archive.ubuntu.com/ubuntu bionic-security main restricted universe multiverse
deb http://jp.archive.ubuntu.com/ubuntu bionic-updates main restricted universe multiverse
root@ubuntu:~#
```

アップデートする

```shell-session
root@ubuntu:~#
root@ubuntu:~# apt update && apt upgrade -y && apt full-upgrade -y && apt autoremove -y && apt clean -y 
root@ubuntu:~#
```

IPv6の無効化

```shell-session
root@ubuntu:~#
root@ubuntu:~# cat <<EOF >> /etc/sysctl.conf

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

EOF
root@ubuntu:~# 
root@ubuntu:~# sysctl -p
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
root@ubuntu:~#

```

時刻同期設定

```shell-session
~#
~# vi /etc/systemd/timesyncd.conf
　：
[Time]
NTP=ntp.nict.jp ntp.jst.mfeed.ad.jp
　：
~#
~# systemctl start systemd-timesyncd
~#
~# systemctl enable systemd-timesyncd
~#
```


デフォルトエディタを変更

```shell-session
root@ubuntu:~#
root@ubuntu:~# update-alternatives --config editor
alternative editor (/usr/bin/editor を提供) には 4 個の選択肢があります。

  選択肢    パス              優先度  状態
------------------------------------------------------------
* 0            /bin/nano            40        自動モード
  1            /bin/ed             -100       手動モード
  2            /bin/nano            40        手動モード
  3            /usr/bin/vim.basic   30        手動モード
  4            /usr/bin/vim.tiny    10        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 3
update-alternatives: /usr/bin/editor (editor) を提供するためにマニュアルモードで /usr/bin/vim.basic を使います
root@ubuntu:~#
```

## (VM)LXC/LXDのバージョンアップ 
デフォルトではLXC/LXDは2.0系がインストールされているが、せっかくなので3.0系にバージョンアップする。

```shell-session
root@ubuntu:~#
root@ubuntu:~# apt install -y -t xenial-backports lxd lxd-client
root@ubuntu:~#
root@ubuntu:~# lxc version
Client version: 3.0.1
Server version: 3.0.1
root@ubuntu:~#
root@ubuntu:~# lxd version
3.0.1
root@ubuntu:~#
```

## (VM)ブリッジインターフェースを作成する
今回の構成では、ブリッジインターフェースを2つ作成します。

ひとつは、コンテナからインターネット接続をするためのブリッジインターフェース(br0)
こちらは、VirtualBoxのNATネットワーク(環境設定 > ネットワーク)のDHCPから払い出されるもの使いたいので、LXD標準のブリッジインターフェース(lxdbr0)は使わずに、独自のブリッジインターフェース(br0)を作成します。

もうひとつは、ホストマシンとコンテナとの通信確認をするためのブリッジインターフェース(br1)
こちらは、VirtualBoxのホストオンリーアダプタと同じネットワークに所属するブリッジインターフェース(br1)を作成し、ホストオンリーアダプタのDHCP関連設定とは重複しないような固定IPを割り当てます。

```shell-session
root@ubuntu:~#
root@ubuntu:~# apt install -y bridge-utils
root@ubuntu:~#
root@ubuntu:~# cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#auto enp0s3
#iface enp0s3 inet dhcp

# VirtualBox Host-Only Ethernet Adapter
#auto enp0s8
#iface enp0s8 inet dhcp

# Bridge interface for LXD
auto br0
iface br0 inet dhcp
    bridge_ports enp0s3
    bridge_stp off

auto br1
iface br1 inet static
    bridge_ports enp0s8
    bridge_stp off
    address 192.168.56.2
    netmask 255.255.255.0
root@ubuntu:~#
```

再起動してVMの物理インターフェース(enp0s3)と作成したブリッジインターフェース(br0)が接続されていることを確認

```shell-session
user01@ubuntu:~$
user01@ubuntu:~$ brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.080027136663       no              enp0s3
br1             8000.080027f47960       no              enp0s8
user01@ubuntu:~$
```

## (VM)LXDの初期設定をする
今回は独自のブリッジインターフェース(br0)を使うので「★」のところが他の情報と異なっています。

```shell-session
user01@ubuntu:~$
user01@ubuntu:~$ sudo lxd init
[sudo] user01 のパスワード:
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm) [default=btrfs]: dir
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]: no ← ★
Would you like to configure LXD to use an existing bridge or host interface? (yes/no) [default=no]: yes ← ★
Name of the existing bridge or host interface: br0 ← ★
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: yes
config: {}
cluster: null
networks: []
storage_pools:
- config: {}
  description: ""
  name: default
  driver: dir
profiles:
- config: {}
  description: ""
  devices:
    eth0:
      name: eth0
      nictype: bridged
      parent: br0
      type: nic
    root:
      path: /
      pool: default
      type: disk
  name: default

user01@ubuntu:~$
```

その後、ブリッジインターフェース br1 もコンテナに割り当てたいので設定変更をする。
以下 ★ の5行を追加する。

```shell-session
user01@ubuntu:~$
user01@ubuntu:~$ lxc profile edit default

config:
  environment.http_proxy: ""
  user.network_mode: ""
description: Default LXD profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br0
    type: nic
  eth1: ← ★
    name: eth1 ← ★
    nictype: bridged ← ★
    parent: br1 ← ★
    type: nic ← ★
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []

user01@ubuntu:~$
```

コマンドでも追加できる

```shell-session
user01@ubuntu:~$
user01@ubuntu:~$ lxc profile device add default eth1 nic name=eth1 nictype=bridged parent=br1
デバイス eth1 が default に追加されました
user01@ubuntu:~$
```


## (VM)配布用の設定を追加する
SSH関連ファイルを削除

```shell-session
root@ubuntu:~#
root@ubuntu:~# rm -rf /etc/ssh/ssh_host*
root@ubuntu:~#
```

## (VM)起動時にSSH関連ファイルを再生成するスクリプトを追加
UbuntuはSSH関連ファイルの再生成を自動ではやってくれないらしいので、rc.localスクリプトで自動化する。

```shell-session:/etc/rc.local
root@ubuntu:~#
root@ubuntu:~# cat /etc/rc.local
#!/bin/sh
  
if [ ! -e /etc/ssh/ssh_host_rsa_key ]; then
    dpkg-reconfigure openssh-server
fi
  
root@ubuntu:~#
root@ubuntu:~# chmod +x /etc/rc.local
root@ubuntu:~#
```
  
```shell-session:/etc/systemd/system/rc-local.service
root@ubuntu:~#
root@ubuntu:~# cat /etc/systemd/system/rc-local.service
[Unit]
Description=/etc/rc.local compatibility
  
[Service]
Type=oneshot
ExecStart=/etc/rc.local
# disable timeout logic
TimeoutSec=0
#StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
  
[Install]
WantedBy=multi-user.target
  
root@ubuntu:~#
root@ubuntu:~# systemctl enable rc-local.service
root@ubuntu:~#
```
systemdへの登録は[こちらのQiita記事](https://qiita.com/msrks/items/5201ae15d0e1f8de5946)を参考にさせていただきました。
  
## (VM)apt関連の不要なファイルを削除

```shell-session
root@ubuntu:~#
root@ubuntu:~# apt clean
root@ubuntu:~# apt autoremove
root@ubuntu:~#
```

## (VM)不要なカーネルファイルを削除

```shell-session
root@ubuntu:~#
root@ubuntu:~# dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge
root@ubuntu:~#
```
[こちらのQiita記事](https://qiita.com/inohiro/items/5d358c30eb7bacb37c7c)を参考にさせていただきました。

## (VM)ログを削除する

```shell-session
root@ubuntu:~#
root@ubuntu:~# find /var/log/ -type f -name \* -exec cp -f /dev/null {} \;
root@ubuntu:~# rm -rf /var/log/lxd/*
root@ubuntu:~#
```
[こちらのQiita記事](https://qiita.com/Tsukasa_Sato/items/f0a7f029d922883c40a7)を参考にさせていただきました。


## (VM)コマンド履歴を削除する

```shell-session
root@ubuntu:~#
root@ubuntu:~# history -c
root@ubuntu:~# cat /dev/null > ~/.bash_history
root@ubuntu:~#
```

## (VBox)ネットワーク設定をする
VMのネットワークはVirtualBoxが動作するホストPCが接続しているネットワークと相互に影響を与えないようにするため、アダプター1には「NAT」で構成する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/442e6bd4-a1c9-ef6b-fffd-1fba7a63bdac.png)

アダプター2には「ホストオンリーアダプタ」を構成する。
プロミスキャスモードは「すべて許可」とする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/07637a0a-f91d-979b-408a-b4a9660e07ee.png)

ホストオンリーアダプタの設定を確認をして、前述 br1 に割り当てたIPアドレスで問題ないか確認をする。
ここで設定されているIPv4のアドレスがホストマシンの仮想NICのアドレスになる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/0a620b55-3eab-b70e-b79c-0ef7f7d73b8c.png)

DHCPサーバー設定でホストオンリーネットワークにアドレス払い出しの設定をする。
DHCPサーバーを無効にすると仮想マシン起動に時間がかかるので、DHCPサーバーは有効にしておいたほうが良い。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/36c7ac44-79ef-1281-1542-e349d3b2269c.png)


## (VBox)その他注意
VMの設定でチップセットは「ICH9」にしないとVMが起動しません
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/f2a99d1f-6cfe-bfd3-eaf2-bb3e83fbf436.png)

また、ポインティングデバイスを「USBタブレット」にしている場合は、Oracle VM VirtualBox Extension Pack を導入して、USBコントローラーを「USB3.0」にする必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/5a503e5d-e9b3-2f89-3891-ad7c568ae268.png)

## (VBox)VMをエクスポートする
ファイルメニューから「仮想アプライアンスのエクスポート」を実行し、ova形式のイメージにする
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108371/42a71f2d-2bd5-d63d-81cd-6bd712aa6428.png)


# 配布
0. エクスポートしたova形式のファイルを社内のWEBサーバーなどからダウンロードできるようにしておく
0. 入手できたova形式のイメージファイルをVirtualBoxにインポートするだけ
0. 起動してすぐに br1 に割り当てたIPアドレスに TeraTerm 等で接続すると、Ubuntu16.04をインストールし時に追加した一般ユーザーでログインができる。
0. lxcの流儀でコンテナを作ったり削除したりすると楽しい！ 

# あとがき
SSH関連ファイルを削除してから、再起動後に自動で再生成されなかったところがハマった・・