Ubuntu OpenStack Installerの高速化

[Ubuntu OpenStack Installer](https://help.ubuntu.com/lts/clouddocs/installer/)は、[Canonical](https://www.ubuntu.com/)社が開発しているOpenStackのインストーラーです。私はUbuntuユーザーなのでこれをよく使っているのですが、構築が完了するまでに非常に時間がかかるのが難点でした(数時間とか)。これを改善したワークアラウンドを紹介します。

> ちなみに、他のOpenStackインストーラーは
>
> * 公式の[DevStack](http://docs.openstack.org/developer/devstack/)
> * Red Hatが開発している[RDO](https://www.rdoproject.org/)
> * Mirantisが開発している[Fuel](https://www.mirantis.com/products/mirantis-> openstack-software/openstack-deployment-fuel/)
>
> とかがあります。

# なぜ遅いのか

このインストーラーは内部でlxcやjujuを利用していて、それらがlxcのコンテナイメージやkvmのマシンイメージを [cloud-images.ubuntu.com](http://cloud-images.ubuntu.com) からダウンロードします。このサーバーはイギリスにあるようで、日本から非常に遠いです。ひどいと100KB/secくらいしか出ません。イメージファイルは数百MBあるので、ダウンロードだけでかなり時間がかかります。

こういうときはミラーサーバを使うべきです。Ubuntuは非常に多くのミラーがあるのですが、ほとんどがaptとISOイメージで、コンテナイメージのミラーは非常に少ないです。日本では唯一、富山大学がミラーです。

[日本国内のダウンロードサイト](https://www.ubuntulinux.jp/ubuntu/mirrors)
(UEC iamgeのところ)

そしてUbuntu OpenStack Installerには、ミラーを設定する項目はありません。また、内部で呼び出しいているlxcやjujuなども、ミラーの設定はあるもののインストーラーが隠蔽してしまうので、残念ながら設定ができませんでした。

仕方ないのでミラーを設定するのでは無く、あらかじめミラーからダウンロードして置いてキャッシュを作成しておき、インストーラーはキャッシュを利用するようなアプローチを取りました。

* インストーラーが最初に作成するlxcコンテナのイメージ(ダウンロードサイズ150MBくらい)を、ミラーサイトからダウンロードしてキャッシュを作成する。
* lxcコンテナ内でjujuが起動する仮想マシンイメージ(ダウンロードサイズ250MBくらい)を、ホスト側であらかじめダウンロードしておいてディレクトリ共有でコンテナ内で利用する。

# 手順

ではやってみます。ここではシングルノードへのインストールが前提です。[オフィシャルのドキュメント](https://help.ubuntu.com/lts/clouddocs/installer/en/single-install.html)も合わせて見て下さい。

動作確認はVMware上のUbuntu14.04LTSで行っています。

```shell-session
hiro@ubuntu14:~$ uname -a
Linux ubuntu14 4.2.0-27-generic #32~14.04.1-Ubuntu SMP Fri Jan 22 15:32:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
hiro@ubuntu14:~$ openstack-install --version
openstack-install 0.99.28
```

以下、色々解説も書きましたが、やること自体は少ないです。

## 1. 準備

openstack-installを実行する直前(Start the installationの前)までオフィシャルドキュメントの通りに進めます。

## 2. lxcのコンテナイメージのキャッシュを作成する

lxcはコンテナを起動する際にコンテナイメージを必要とし、イメージのダウンロードの際には内部で /usr/share/lxc/templates/lxc-ubuntu-cloud が呼ばれます。中身はシェルスクリプトです。

そして、lxc-ubuntu-cloudはさらに内部でubuntu-cloudimg-queryを実行します。このコマンドはcloud-utilsパッケージに含まれるコマンドで、ホストのアーキテクチャーやUbuntuのリリース名を元にイメージのダウンロードとrootfsの展開を行います。これもシェルスクリプトです。

ubuntu-cloudimg-queryは環境変数 **UBUNTU_CLOUDIMG_QUERY_BASEURL** でミラーを指定することができます。しかし、日本のミラーにはコンテナイメージファイルはミラーされているものの、ubuntu-cloudimg-queryが利用する[クエリファイル](http://cloud-images.ubuntu.com/query/)だけミラーされていません(なぜなのか...)

そこで、一度ミラーなしでubuntu-cloudimg-queryを実行しローカルにクエリのキャッシュを作り、次にlxc-ubuntu-cloudを実行してミラーからイメージをダウンロードするという段階を踏みます。

まず、ubuntu-cloudimg-queryを実行します。第一引数はUbuntuのリリース名(/etc/lsb-releaseに書いてあります)、第二引数はreleasedで固定、第三引数はホストのアーキテクチャです。

```shell-session
hiro@ubuntu14:~$ ubuntu-cloudimg-query trusty released amd64 > /dev/null
```

次にlxc-ubuntu-cloudでコンテナイメージをダウンロードします。環境変数UBUNTU_CLOUDIMG_QUERY_BASEURLを指定することで、ミラーからコンテナイメージがダウンロードされます。pathパラメータは必須のパラメータで、指定したディレクトリにrootfsが展開されますが、これは不要なので適当なディレクトリを指定しておきます。

```shell-session
UBUNTU_CLOUDIMG_QUERY_BASEURL=http://ubuntutym2.u-toyama.ac.jp/cloud-images/releases sudo -E /usr/share/lxc/templates/lxc-ubuntu-cloud --path=/tmp/hoge
```

そしてコンテナイメージが/var/cache/lxc/cloud-(リリース名)にキャッシュされていることを確認します。

```shell-session
hiro@ubuntu14:~$ sudo ls -l /var/cache/lxc/cloud-trusty
合計 122104
drwxr-xr-x 22 root root      4096  7月 26 11:59 rootfs
drwxr-xr-x  3 root root      4096  7月 26 12:04 tmp
-rw-r--r--  1 root root 125023208  7月 15 06:03 ubuntu-14.04-server-cloudimg-amd64-root.tar.xz
```

## 3. 仮想マシンイメージをあらかじめダウンロードしておく

次に、jujuがlxc内部で使用する仮想マシンイメージを、あらかじめミラーからダウンロードしておきます。juju内部では[uvtool](https://help.ubuntu.com/lts/serverguide/cloud-images-and-uvtool.html)が使われており、イメージの管理には**uvt-simplestreams-libvirt**コマンドを使います。このコマンドもcloud-images.ubuntu.comからイメージをダウンロードするのでボトルネックになります。ミラーの指定は--sourceオプションで行います。

結論として、残念ながらjujuを使う場合において--sourceオプションを指定する方法はありません。このあたりです。

https://github.com/juju/juju/blob/69d8569f1da7a360851dc79d8b76549562e1b326/container/kvm/libvirt.go#L59
https://github.com/juju/juju/blob/69d8569f1da7a360851dc79d8b76549562e1b326/container/kvm/kvm.go#L146


なので方法論として、ホスト側であらかじめイメージをミラーからダウンロードしておいて、そのキャッシュディレクトリ(/var/lib/uvtool)をlxcコンテナ内のjujuと共有するようにします。

uvtoolをインストールする

```shell-session
hiro@ubuntu14:~$ sudo apt-get install uvtool
```

仮想マシンイメージをミラーからダウンロードする(オプションのreleaseとarchは使っているバージョンに合わせて下さい。)
 
```
hiro@ubuntu14:~$ uvt-simplestreams-libvirt sync --source=http://ubuntutym2.u-toyama.ac.jp/cloud-images/releases arch=amd64 release=trusty
```

何も出力されませんが、/var/lib/uvtool/ 配下にキャッシュファイルが作成されています。

```shell-session
hiro@ubuntu14:~$ ls -l /var/lib/uvtool/libvirt/images/
合計 845196
drwxr-xr-x 2 root      root          4096  7月 26 19:24 ./
drwxr-xr-x 4 root      root          4096  7月 26 12:48 ../
-rw------- 1 pollinate libvirtd 865468416  7月 26 16:40 x-uvt-b64-Y29tLnVidW50dS5jbG91ZDpzZXJ2ZXI6MTQuMDQ6YW1kNjQgMjAxNjA3MTQ=
```

## 4. cloud-initのテンプレートを修正する

インストーラーが使うcloud-initのuser-dataを修正します。 インストーラーがホストのuvtoolのディレクトリをホームディレクトリにマウントするので、/var/lib/にシンボリックリンクを作る必要があるからです。

```shell-session
sudo vi /usr/share/openstack/templates/userdata.yaml
```

最下行に以下の一行を追加します。YAMLなのでインデントに注意です。

```yaml
{%- if https_proxy %}
  - echo "export https_proxy={{ https_proxy }}" >> /home/ubuntu/.bashrc
  - echo "export HTTPS_PROXY={{ https_proxy }}" >> /home/ubuntu/.bashrc
{%- endif %}
  - "chown ubuntu:ubuntu /home/ubuntu /home/ubuntu/.bashrc"
  - "ln -s /home/ubuntu/uvtool /var/lib/uvtool"              ← この行
```

## 5. openstack-installを実行する

ようやくOpenStackのインストール開始です！ openstack-installを実行する際に、環境変数を2つ指定します。

```shell-session
EXTRA_BIND_DIRS=/var/lib/uvtool USE_LXC_IMAGE_CACHE=1 sudo -E openstack-install
```

sudoに-Eオプションを付けることが必須です。これによりsudoから起動したコマンドに環境変数が引き継がれます。

EXTRA_BIND_DIRSは、インストーラーが作成するlxcコンテナが、ホストのディレクトリをマウントするよう指定するオプションです。ホストのuvtoolのキャッシュディレクトリをコンテナ内から使用するために指定しています。これはヘルプには書いてなくコード内にあります。

https://github.com/Ubuntu-Solutions-Engineering/openstack-installer/blob/350445f5a7fdb7f42b7c97f14eb77813ecf816a2/cloudinstall/controllers/install/single.py#L225

USE_LXC_IMAGE_CACHEはインストーラーがlxcイメージを起動する際に、キャッシュされたイメージファイルを使うことを強制するものです。挙動としては、インストーラーが内部で起動するlxc-createから-Fオプションが除外されます。これを指定しないと、openstack-installを実行する度にイメージのダウンロードが行われてしまいます。これはオフィシャルドキュメントに記述があります(Additional Tipsのところ)

https://help.ubuntu.com/lts/clouddocs/installer/en/single-install.html



あとは通常通りインストールを進めるだけです！ インストール時間がかなり短くなってるはずです(数十分で終わる)