Ubuntu Weekly Recipe

第615回サーバー版インストーラーに導入された自動インストール機能

Ubuntuのサーバー版のインストーラーである「Subiquity」に最近「自動インストール機能」が追加されました。cloud-configのようにインストールオプションをYAMLファイルに書くことで、インストールをすべて自動化する機能です。今回はその機能を試してみましょう。

インストールの自動化

第495回でも紹介したように、Ubuntuは17.10からサーバー版のインストーラーとしてSubiquityが導入されました。Subiquityでは、デスクトップ版のUbiquityと同じように、必要最低限のインストールオプションをTUI(Text-based User Interface)からグラフィカルに選んでインストールできます[1]⁠。

図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種類です。

  1. SMBIOS(System Management BIOS)上のシリアル番号
  2. カーネルのコマンドラインパラメーター
  3. ラベル「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でアクセスすることになります。

あとはしばらく放置しておけば、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_listfalseにすることで、/etc/apt/sources.listを変更することを示しています。またgeoiptrueに指定することで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の範囲外の事前設定も一通り行えます。

他にもearly-commandslate-commandserror-commandsによって、インストール開始直後・終了直後・エラー発生時に実行するコマンドを指定可能です。snapspackagesで、自動インストールするパッケージを指定できます。

インストール時に必要な設定はひととおり自動化できるようになっているはずですので、まずは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ブートを使うことになるでしょう。

おすすめ記事

記事・ニュース一覧