LXDコンテナにOpenStackをインストールするためのプロファイル設定

# 背景
Ubuntu 16.04 + OpenStack Newton で構築した物理サーバーが手元にあり、バージョンも陳腐化したことから、同一物理を流用した新しいOpenStack環境を再構築したいと考えていましたが、そのまま物理上に再構築するのでは、OpenStackのダウンタイムの長時間化が躊躇われ、なかなか重い腰が上がりませんでした。
そのためまず、OpenStackのサービス群をLXDコンテナ化し、OSとOpenStack、双方の依存関係を分離することにしました。必要な作業もコンテナへの関連コンポーネントのインストールと既存の設定ファイルの移行だけで、ダウンタイムも最小限に留められそうです。
ただし、LXDのデフォルトのコンテナ設定(プロファイル)ではハイパーバイザーを含むOpenStackのサービス群は正常に稼働しないため、LXDコンテナにどのようなプロファイルを適用すればよいかを考える必要があります。

# 参考情報
[Running QEMU/KVM Virtual Machines in Unprivileged LXD Containers](https://dshcherb.github.io/2017/12/04/qemu-kvm-virtual-machines-in-unprivileged-lxd.html)
[HyperContainer](http://metasearch.osdn.jp/wiki/index.php?HyperContainer)

# 使用バージョン
LXD 3.12 (snapでインストール)
イメージ: Ubuntu 16.04

# プロファイルの種類
OpenStackの一般的なノード構成に従い「コントローラーノード」、「ネットワークノード」、「コンピュートノード」用の三種類のプロファイルを準備します。
※ 今回の構成では、独立した「ストレージノード」は設けず、ストレージ関連のサービスはコントローラーノードに共存します。DBサーバー、MQサーバー等も同様です。

## コンポーネントの配置
移行元のOpenStackの構成について簡単に説明します。

- ハイパーバイザーは`kvm`
- 仮想ネットワークは`linux-bridge`によるセルフサービスネットワーク構成
- `cinder`のバックエンドには`ceph`を使用しています
- `swift`は使用していません

各コンテナに配置するOpenStack関連コンポーネントは以下の通り。

- コントローラーノード
    - keystone
    - nova
    - neutron-server
    - neutron-plugin-ml2 
    - glance
    - cinder
    - cinder-volume
    - openstack-dashboard
    - mariadb-server
    - rabbitmq-server
    - memcached
    - apache2
    - ceph-deploy
    - ceph-common (cephクライアント)

- ネットワークノード
    - neutron-dhcp-agent
    - neutron-l3-agent
    - neutron-metadata-agent 
    - neutron-linuxbridge-agent

- コンピュートノード
    - nova-compute
    - qemu-kvm
    - libvirt-bin
    - neutron-linuxbridge-agent
    - ceph-common (cephクライアント)
   
##LXDプロファイル
###コントローラーノード
癖のないコンポーネントが配置されるので、プロファイルもデフォルトをそのまま使用します。
`cinder`のバックエンドの選択次第では調整が必要かも知れません。

```yaml:default
default
config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br-management
    type: nic
  root:
    path: /
    pool: local
    type: disk
name: default
used_by:
- /1.0/containers/newton-control-1
```
###ネットワークノード
コンテナ内で仮想ネットワークを稼働させるためのカーネルモジュールを追加します。NICも必要なだけ追加します。

```yaml:openstack-network
config:
  linux.kernel_modules: br_netfilter,iptable_nat,ip6table_nat,ebtables
  security.nesting: "true"
description: OpenStack network node profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br-management
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br-tenant
    type: nic
  eth2:
    name: eth2
    nictype: bridged
    parent: br-provider
    type: nic
  root:
    path: /
    pool: local
    type: disk
name: openstack-network
used_by:
- /1.0/containers/newton-network-1
```
###コンピュートノード
さらに`kvm`用のカーネルモジュールとデバイスファイルを追加します。

```yaml:openstack-compute
config:
  linux.kernel_modules: br_netfilter,iptable_nat,ip6table_nat,ebtables,kvm,kvm_intel,tap,vhost,vhost_net,vhost_scsi,vhost_vsock
  security.nesting: "true"
description: OpenStack compute node profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br-management
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br-tenant
    type: nic
  eth2:
    name: eth2
    nictype: bridged
    parent: br-provider
    type: nic
  kvm:
    path: /dev/kvm
    type: unix-char
  root:
    path: /
    pool: local
    type: disk
  tun:
    path: /dev/net/tun
    type: unix-char
  vhost-net:
    mode: "0600"
    path: /dev/vhost-net
    type: unix-char
  vhost-scsi:
    mode: "0600"
    path: /dev/vhost-scsi
    type: unix-char
  vhost-vsock:
    path: /dev/vhost-vsock
    type: unix-char
name: openstack-compute
used_by:
- /1.0/containers/newton-compute-1
- /1.0/containers/newton-compute-2
```

#最後に
上記プロファイルでLXDコンテナを作成した後の移行作業について、簡単に述べておきます。
ここまで触れていませんでしたが、コントローラーノードだけは、現行環境の初期構築時点でコンテナ化出来ており、コントローラーノードのIPアドレス変更、DBの移行と言った面倒事が避けられたので、物理環境からコンテナ環境への移行としては、新しいコンピュートノードへのインスタンスのライブマイグレーション、物理環境側のコンピュートサービス、ネットワークサービスを破棄、と言う事で、結果、OpenStackは無停止で移行作業を終える事が出来ました。