Ubuntuのサーバー版のインストーラーである「Subiquity」に最近「自動インストール機能」が追加されました。cloud-configのようにインストールオプションをYAMLファイルに書くことで、インストールをすべて自動化する機能です。今回はその機能を試してみましょう。
インストールの自動化
第495回 でも紹介したように、Ubuntuは17.10からサーバー版のインストーラーとしてSubiquityが導入されました。Subiquityでは、デスクトップ版のUbiquityと同じように、必要最低限のインストールオプションをTUI(Text-based User Interface)からグラフィカルに選んでインストールできます[1] 。
[1] TUIかどうかという観点で言えば、従来のdebian-installerもTUIです。Subiquity導入の最大のメリットはサーバー版のインストールイメージもデスクトップ版と同じように「Liveイメージ化」できることでしょう。つまりインストールイメージを起動したあと、「 Alt-F2」などを押して仮想コンソールを切り替えることで、インストールすることなく「普通のサーバー版Ubuntu」として使えます。一種のレスキューイメージとしても使えると思っておけば良いでしょう。
図1 Subiquityで導入されたグラフィカルインストーラー
しかしながら従来のdebian-installerと比べると、ひとつ大きな機能が不足していました。それがインストールの自動化 です。
debian-installerでは第154回 の「さくらVPSへのネットブートインストールをPreseedingで自動化する」でも紹介したように、「 preseeding」というdebfconfを羅列したファイルを用意することで、インストールオプションを自動選択する仕組みが存在しました。RHELやCentOSなどで言うところのkickstartですね。
何台もの物理マシンにUbuntuをインストールするなら、インストールの自動化は欠かせません。自動化の仕組みさえあればサーバー版を自動インストールしたあとに「ubuntu-desktop」パッケージをインストールすることで、デスクトップ版のインストールの自動化として使えます。よってSubiquityによるインストールの自動化は、長きに渡って強く要求されていた機能でした。
Ubuntu Weekly Topicsの2020年4月10日号 でも紹介しているように、ようやくその自動インストール機能が実装され、幅広くテスト依頼を呼びかけられる状態になったのです。今回はそのテストも兼ねてSubiquityによるインストールの自動化方法を紹介しましょう。
ちなみにSubiquityはsnapパッケージとして提供されています。つまりUbuntu 18.04 LTSなど過去のリリースでも新しいバージョンのインストーラーを利用可能です。現時点でも、Ubuntu 18.04 LTSのサーバーをインストールしようとすると「新しいSubiquityパッケージがリリースされているが更新してからインストールするか?」との確認画面が表示されます。さらに18.04の最後のポイントリリースになるであろう18.04.5にも、自動インストールに対応したSubiquityが同梱される見込みです。
図2 Subiquityを最新版に更新してからインストールも可能
簡易的なYAMLファイルで自動インストールを体験
まずは簡易的なYAMLファイルで自動インストールを体験してみましょう。これには公式WikiのQuickStart の手順が参考になります。必要になるのはQEMUが動くUbuntuと開発中のUbuntu 20.04 LTSのインストールイメージだけです。
自動インストールの設定を記述するYAMLファイルはcloud-configフォーマットで記述します。また作成したファイルはcloud-initと同じ手順でインストーラーに渡します。cloud-initにおいてコンフィグデータをどこに保存するか、つまりどのデータストアを選択するかは、第561回 「ローカルインストール時もcloud-initを活用する」にて解説してるとおり、主に次の3種類です。
SMBIOS(System Management BIOS)上のシリアル番号
カーネルのコマンドラインパラメーター
ラベル「cidata」が付けられたファイルシステム
このうち1は主に仮想マシン向けの機能なので、実機で使うとすれば2か3になるでしょう。2の場合はローカルのファイルシステムだけでなく、ネットワークの先のサーバーも指定可能です。まずは2の方法で試してみましょう。
必要なパッケージをインストールし、ファイルをダウンロードしておきます。
$ mkdir autoinstall && cd $_
$ sudo apt install qemu-system-x86 qemu-utils
$ wget http://cdimage.ubuntu.com/ubuntu-server/daily-live/current/focal-live-server-amd64.iso
cloud-configフォーマットのファイル(user-data)とuser-dataの情報を記述するmeta-dataファイルを作りましょう。
$ mkdir www
$ openssl passwd -6 ubuntu
$6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/
$ cat > www/user-data << 'EOF'
#cloud-config
autoinstall:
version: 1
identity:
hostname: ubuntu-server
username: ubuntu
password: "$6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/"
EOF
$ touch www/meta-data
自動インストールの設定は「autoinstall」キーに対する値として記述します。Subiquityはこの「autoinstall」キーの有無で自動インストールモードに移行するかどうかを判断しています。個別の設定値の説明は公式WikiのConfigReference を参照してください。今回は次のような設定を行っています。
ホスト名を「ubuntu-server」にする
ユーザー名を「ubuntu」にする
パスワードを「ubuntu」にする
それ以外はSubiquityの既定の設定値が使われます。ちなみに「interactive-sections」キーを使うと、「 cloud-configの設定値を設定した上で、通常のインストールと同じようにユーザーが選択できるようにする」ことも可能です。
「meta-data」はcloud-configファイルのバージョンなどの元になるデータですが、今回は空で作成しておくことにします。
今回はHTTP経由でこれらの設定ファイルを提供することにします。よってPython 3の組み込みHTTPサーバーを起動しておきましょう。
$ cd www
$ python3 -m http.server --cgi 3003
$ curl http://localhost:3003/user-data
(中略)
<li><a href="meta-data">meta-data</a></li>
<li><a href="user-data">user-data</a></li>
(後略)
user-dataが見えていることを確認できました。ちなみに「--cgi
」を付けているのは、後述のレポート機能を使うためです。今のところはあってもなくてもかまいません。
$ sudo mount -r focal-live-server-amd64.iso /mnt
$ qemu-img create -f qcow2 image.qcow2 10G
$ qemu-system-x86_64 -enable-kvm -no-reboot -m 1024 \
-drive file=image.qcow2,format=qcow2,cache=none,if=virtio \
-cdrom focal-live-server-amd64.iso \
-kernel /mnt/casper/vmlinuz \
-initrd /mnt/casper/initrd \
-append 'autoinstall ds=nocloud-net;s=http://_gateway:3003/' \
-nographic
$ sudo umount /mnt
ポイントは「-append
」で起動パラメーターを指定している部分です。自動インストールのためにふたつパラメーターを追加する必要があります。
「autoinstall
」 :cloud-configファイルの中にautoinstallキーが存在しているとき、ユーザーの操作なしに自動インストールを開始するためのオプション。言い換えるとこのオプションがないと、画面に「Continue with autoinstall?」と表示されて「yes」と入力しない限り自動インストールが開始しません[2] 。
「ds=nocloud-net;s=http://_gateway:3003/
」 :cloud-configファイルの場所(データストア)を指定するためのオプション。今回はホスト上にポート3003でHTTPサーバーを立てているため、仮想マシンのゲストからだと設定のようなURLでアクセスすることになります。
[2] これは自動インストールの設定が入っているUSBスティックを接続した状態で起動してしまうと、意図せず上書きインストールしてしまう危険性があるためです。仮想マシンではなく物理マシンで完全な自動化を目指すなら、ネットブートなどカーネルオプションを変更可能な仕組みから利用することになるでしょう。
あとはしばらく放置しておけば、qemu-system-x86_64
コマンドが自動終了しているはずです。
次にインストール後のサーバーを起動してみましょう。
$ qemu-system-x86_64 -enable-kvm -no-reboot -m 1024 \
-drive file=image.qcow2,format=qcow2,cache=none,if=virtio
デスクトップ環境なら上記のコマンドでウィンドウが立ち上がり、アカウント名がubuntu、パスワードがubuntuでログインできるはずです。
今回の設定だとopenssh-serverがインストールされないため、QEMUのディスプレイウィンドウを立ち上げる必要があります。もしデスクトップ環境のないサーバー上で実行するなら、第595回 「リモートデスクトップのためのSPICEクライアントあれこれ」で紹介しているようなSPICE関連のオプションを付けて、リモートデスクトップからアクセスすると良いでしょう。
より本格的なコンフィグを用意する
ConfigReference を参考に、より本格的な設定を用意してみましょう。
$ cat > www/user-data << 'EOF'
#cloud-config
autoinstall:
version: 1
locale: ja_JP.UTF-8
keyboard:
layout: "jp"
apt:
preserve_sources_list: false
primary:
- arches: [default]
uri: "http://archive.ubuntu.com/ubuntu"
geoip: true
storage:
layout:
name: lvm
identity:
hostname: ubuntu-server
realname: "Mitsuya Shibata"
username: ubuntu
password: "$6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/"
ssh:
install_server: true
authorized-keys: [ "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAmhhimVNdsJLG3Sc6s3QD0nM5esEjUPQtC1k9b5M8fsp75ZaYhgoE3VUE+vXe5jD0tMlVbrzly4OnghloOgBtmrTqiuC7iUxcfWQ+11b7RI660m43ZQinafobZo7jMHOE2IwLFw5/bj6xm8LiXDn1Y2pA2d13V1f9MPKNexsYeuBfsru4AlwhKifEEjL0PS4saV1tcT1WM3na8jstI6jmdsOQ+cngj8HnpWTg8+YIFe1iqAnIIuFWSKjLqTFrJRIO4pnzNeo0naHqjxVoAytUqjxjXWT093DxW0wDvHUNxRhSwqL6S45ehcD2M7AXszOW2ZbX3i455SB2bClXZHBN2Q== shibata" ]
reporting:
hook:
type: webhook
endpoint: http://_gateway:3003/cgi-bin/done
level: INFO
user-data:
timezone: Asia/Tokyo
EOF
注意すべきポイントをいくつか見ていきましょう。
apt:
preserve_sources_list: false
primary:
- arches: [default]
uri: "http://archive.ubuntu.com/ubuntu"
geoip: true
APTのリポジトリの設定です。これはcurtinのapt関連の設定 をそのまま記述します。「 preserve_sources_list
」を「false
」にすることで、/etc/apt/sources.list
を変更することを示しています。また「geoip
」を「true
」に指定することでIPアドレスから位置情報を推定し、適切なミラーサーバーを選択してくれます。他にもGPG鍵を含む、サードパーティのリポジトリの追加なども可能です。
storage:
layout:
name: lvm
ストレージはケースバイケースで複雑になりがちなので、公式Wikiのstorageの設定 を参照してください。ここでは標準のストレージ全体をLVM設定にする方法を記述しています。今回設定していないネットワークも複雑な設定 になりがちです。原則としてnetplanの設定をそのまま記述する形になります。
ssh:
install_server: true
authorized-keys: [ "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAmhhimVNdsJLG3Sc6s3QD0nM5esEjUPQtC1k9b5M8fsp75ZaYhgoE3VUE+vXe5jD0tMlVbrzly4OnghloOgBtmrTqiuC7iUxcfWQ+11b7RI660m43ZQinafobZo7jMHOE2IwLFw5/bj6xm8LiXDn1Y2pA2d13V1f9MPKNexsYeuBfsru4AlwhKifEEjL0PS4saV1tcT1WM3na8jstI6jmdsOQ+cngj8HnpWTg8+YIFe1iqAnIIuFWSKjLqTFrJRIO4pnzNeo0naHqjxVoAytUqjxjXWT093DxW0wDvHUNxRhSwqL6S45ehcD2M7AXszOW2ZbX3i455SB2bClXZHBN2Q== shibata" ]
サーバー用途ならOpenSSHサーバーはインストールしておきたいところでしょう。気をつけなければいけないのは、本記事執筆時点ではサーバーをインストールするキーは「install-server
」ではなく「install_server
」です。これはソースコード側が単なる記述ミスである ため、20.04のリリース時点では解消している予定です。
「authorized-keys
」にはインストール時のユーザーのSSH用公開鍵を複数登録できます。公開鍵が未登録の場合は、SSHのパスワードログインがオンの状態でインストールされます。
reporting:
hook:
type: webhook
endpoint: http://_gateway:3003/cgi-bin/done
level: INFO
「reporting
」ではインストール時の進捗を報告する仕組みです。現時点では標準出力に出力するか、webhookで流し込むかの二択です。ここではwebhookを指定しています。
前述のPython 3の組み込みサーバーでは「--cgi
」オプションをつけるとCGI機能が有効になり、cgi-binディレクトリ以下にCGIスクリプトを配置できます。たとえば、次のようなスクリプトを用意しておくと、installed.jsonにログファイルが残るようになります。
$ mkdir www/cgi-bin
$ cat > www/cgi-bin/done << 'EOF'
#!/usr/bin/bash
read -n $CONTENT_LENGTH QUERY_STRING_POST
echo $QUERY_STRING_POST >> installed.json
echo "Content-type: text/plain"
echo ""
echo "OK"
EOF
$ chmod +x www/cgi-bin/done
$ curl -X POST -H "Content-Type: application/json" \
-d '{"key":"value"}' http://localhost:3003/cgi-bin/done
OK
インストールの進捗を把握したり、インストールが完了したら別の処理を実行したいときなどに、使えるでしょう。
user-data:
timezone: Asia/Tokyo
実はSubiquityにはタイムゾーンを指定するインターフェースが存在しません。そのためautoinstallキー以下でもタイムゾーンは設定できません[3] 。しかしながら「user-data
」キーを使えば、最終的に生成されるcloud-init用の設定を指定可能です。上記ではcloud-init経由でtimezone指定するようにしています。ちなみにcloud-init用に設定は一通り使えるため、複数のアカウントなどSubiquityの範囲外の事前設定も一通り行えます。
[3] debconf-selections
によって設定できるかもしれませんが、今回は試していません。Subiquityの自動インストールの仕組みを考えると、debconfi-selections
による設定は「最終的な回避策」ぐらいに考えておくのが良いでしょう。
他にもearly-commands
やlate-commands
、error-commands
によって、インストール開始直後・終了直後・エラー発生時に実行するコマンドを指定可能です。snaps
やpackages
で、自動インストールするパッケージを指定できます。
インストール時に必要な設定はひととおり自動化できるようになっているはずですので、まずはConfigReferenceを参照しながら、各自のインストールオプションをYAMLファイルに落とし込んでみてください。
ちなみにinteractive-sections
に「*
」を指定することで、「 YAMLで記述した項目を設定済みにした上で、インタラクティブにインストール」が可能になります。
interactive-sections:
- "*"
ただしパスワードなどセンシティブなデータは自動入力されませんので注意してください。
USBスティックからインストールを自動化する
最後にUSBスティックから設定を流し込んでみましょう。
$ sudo apt install cloud-image-utils
$ cd www
$ cloud-localds ../user-data.img user-data
これで設定入りのイメージファイルを作成できました。これをUSBスティックにddで書き込めば良いのですが、今回はQEMU上にマウントすることにします。
$ qemu-system-x86_64 -enable-kvm -no-reboot -m 1024 \
-drive file=image.qcow2,format=qcow2,cache=none,if=virtio \
-cdrom focal-live-server-amd64.iso \
-drive file=user-data.img,format=raw
注意すべきなのはUSBからだと完全な自動化はできない ということです。インストーラーが起動したあとに「Continue with autoinstall?」と表示されるので、そこで「yes」と入力してください。
もしどうしても自動化したいなら、PXEブートを使うことになる でしょう。