メインコンテンツにスキップ
ブログLinux発売日。Linux ディストリビューションの自動化 (featuringUbuntu 20.04)

リリース日 : Linuxディストロの自動化 (Ubuntu 20.04)

ディストリビューションの自動化

こんにちは! Linode でシステムエンジニアをやっている Brad です。今日は最も人気のあるディストリビューションの一つであるUbuntu 20.04の次のLTS(長期サポート)バージョンのリリースで、Linuxの世界では大きな出来事が起きた日となりました。2年前のUbuntu 18.04と同様に、すでにすべてのお客様にご利用いただけるようになっており、最も広く採用されるイメージになることを期待しています。 

新しいイメージの構築、テスト、デプロイについて自動化作業を開発したおかげで、ここLinodeではリリース当日中にディストロを利用できることが当たり前になってきました。しかし、イメージ(またはテンプレートと呼ばれることもある)とは何か、そしてそれを作るには何が必要なのか?その疑問に答えるために、まず OS のインストールがどのように行われるのかを見てみましょう。 

OSのインストール

あなたは、自宅のコンピュータやサーバーに手動でオペレーティングシステムをインストールするプロセスには馴染みがあるかもしれません。通常、インストール用の ISO をダウンロードしてそれを CD や USB ドライブに書き込み、そこからシステムを起動します。そこから通常、インストールするハードドライブ先の選択、どのようなソフトウェア/パッケージを含めるか、そしてユーザー名とパスワードの設定などのいくつかのカスタマイズなどインストールの様々なオプション制御できるメニュー群 (時には手動コマンド) を実行します。すべてが完了したら (うまくいけば) 正常動作するOSが手に入り、起動して使用を開始することができます。

このプロセスは個人ユーザーが単独のインストールを行う場合には十分に機能しますが、少なくない数のシステムをインストールする必要がある場合には、手動でのインストールプロセスは誰が考えても実行不可能です。そこでイメージの出番です。 

イメージってなんだ?

イメージとは、基本的には必要なだけの複数のシステムにデプロイすることができるプリインストールされた OS です。イメージは、通常のインストールを一度実行したのちに、後で別のシステムに「貼り付ける」ことができるインストールのコピーを作成する仕組みです。イメージを保存する方法や形式は様々ですが、ほとんどの場合はイメージは元のインストールのバイト単位の正確なコピーです。

今では一度だけ手動でインストールを行うだけで、他の場所でも再利用できるようになりました。しかし我々にはもっといい方法があります。Linodeは、一般的なディストリビューション (Debian, Ubuntu, CentOS, OpenSUSE) から、他のプロバイダでは見られないようなもの (Alpine, Arch, Gentoo など) まで、多種多様なディストリビューションをサポートしています。それぞれが独自のリリーススケジュールとサポート期間を持っています。サポートしているすべてのディストロを手動でインストールして(一度だけでも)、結果としてのイメージが正しく動作して間違いがないことを確認するには膨大な時間がかかり、ミスが起こりやすくなります。そこで、HashiCorp 製の Packer という素晴らしいツールを使って、イメージの構築プロセスを自動化することにしました。

ビルドの自動化

すべての Linux ディストリビューションは共通のベース(すなわち Linux カーネル)を共有していますが、インストール方法も含めてそれぞれ大きく異なっています。あるディストロはコマンドライン命令を使用し、あるものはメニューインターフェイスを使用し、あるものはそれらのメニューを自動的にナビゲートして答えを提供する機能を含んでいます。幸いなことに、Packer は非常に汎用性の高いツールでありこれらすべてのユースケースを扱うことができます。

まず最初に行うことは、PackerにできるだけLinodeを正確に模擬する仮想マシン(またはVM)を作成するように指示することです。これは、実際のLinodesで使用するのと同じ「ハードウェア」や機能をエミュレートすることを意味します。そうすることで、最終的なランタイム環境に近い環境でインストールが実行されます。USBドライブにOSをインストールして、そのドライブを使って全く別のコンピュータを起動することを想像してみてください。運が良ければうまくいくかもしれませんが、多くの場合はハードウェアデバイスが検出されなかったり、全く起動しなかったりします。実際の動作環境に合わせたインストール環境を用意することで、これらの問題を解決します。

VMが作成されると、Packerは指定されたURLから取得したディストロのインストールISOからVMを起動します。ここからの処理はディストロによって大きく異なります。Arch のようなコマンド駆動型のディストロでは、基本的なインストールを実行する bash スクリプトを与えます。Ubuntu のようなメニュー駆動型のディストロでは、インストーラへの回答を提供するディストリビューションの推奨する方法を使います。 (通常Debian ライクなディストロでは Preseed、RHEL ライクなディストロでは Kickstart のいずれか) 私たちの VM に加えて、Packer は小型の HTTP サーバを作成し、必要なファイルを VM に転送することができます。

これらはすべて、Packer が使用する設定とビルド オプションを定義する JSON ファイルを介して制御されます。ビルドを開始するには、例えば以下を実行する必要があります: packer build ubuntu-20.04.json.

カスタマイズ 

ほとんどの場合、私たちは可能な限りごく基本的なインストールを行います。これは、指定されたディストロが「デフォルト」(「ベース」や「スタンダード」と呼ばれることもあります)と指定しているパッケージをすべてインストールすることを意味します。これらのデフォルトパッケージに加えて、「サポート」パッケージと我々が呼んでいる iotop, mtr, sysstat のような基本的なユーティリティを幾つかインストールします。その結果、サポートチームは顧客をサポートする際にこれらのツールが既にインストールされていることをアテにできます。

インストールが完了した後でVM をシャットダウンする前に、Linode プラットフォームのすべての機能が適切に機能するようにいくつかの最終的なカスタマイズを行います。例えば、ブートローダが LISH (帯域外コンソールアクセス用のツール) の正しい設定で設定されていることを確認します。しかし一般的には、できる限りデフォルトに近い設定を保つようにしています。それにより、特定のディストロを好むユーザーは使い慣れたものを手に入れることができますし、他人の不慣れな車を運転しているような気分にはなりません。

パッケージング 

インストールと設定が終わると、PackerはVMをシャットダウンしてディスクイメージをファイルにエクスポートします。これで終わったように聞こえるかもしれませんが、まだいくつかのステップが残っています。一般的なコンピュータのハードドライブは、パーティションテーブル(新しいシステムでは MBR または GPT)から始まります。Linode は、GRUB ブートローダ自体が各Linode上にあるのではなく、実際は我々のホスト上にあるという点で少しユニークです。 (ただし設定情報はLinodeから読み込まれます。)これは、パーティションテーブルを完全に削除することで単一のパーティションだけを残すことができることを意味します。

これを達成するために、次のように実行することでディスクイメージ上のパーティションの始点と終点、ブロックサイズを決定します: fdisk -l disk.img 次に: dd if=disk.img of=part.img bs=### skip=### count=### を実行し、前のコマンドの開始オフセットを使ってパーティションを「フォークリフト」で取り出すことができます。具体的には、このコマンドの "###" は先ほどの: fdisk コマンドのアウトプットに置き換えられます。

新しいコンピュータの場合と同じように、ドライブ上のスペースのほとんどが空になっているのでこれはディスクイメージに反映されます。これらの「空」のバイトをコピーするのは馬鹿げているので次のように処理します: イメージの縮小 (後に、イメージを貴方のLinodeにデプロイする際に 再膨張させ インスタンスの空き容量を埋めるようにします。)すべてのイメージは ext4 パーティションを使用しているので resize2fs -M part.imgが実行でき、これは自動的にイメージをを可能な限り小さいサイズに縮小してくれます。最後に、出来上がった画像の完全性を確認するために最終的な処理: fsck をgzipで圧縮する前に行います。 gzip.

テスト 

イメージが構築され準備が終わると、次のステップはそれが実際に動作するかどうかを確認することです。新たに作成したイメージはテスト環境にデプロイされ、多くの異なる設定でイメージからLinodeインスタンスがプロビジョニングされます。私たちは自動化されたテストスイートを開発し、ネットワーク接続やパッケージマネージャの動作、バックアップやディスクのサイズ変更などのプラットフォームの様々な機能など、多岐にわたりチェックを行いこれらのインスタンスに負荷を掛けます。このチェックに失敗した場合、プロセスは直ちに中断され、失敗要因に関する情報とともにビルドは失敗します。

このように自動化された方法でビルドとテストを行うことで、迅速な開発サイクルを実現し、より良いイメージをより早くリリースすることが可能になります。当社では新しいチェックを簡単に追加することができるようにテストプロセスを構成しています。万が一お客様からイメージに関する問題が報告された場合でも、迅速に修正プログラムをリリースして増え続けるチェックリストに新しいチェック項目を追加することができます まるで免疫システムのように。

同じようで、違う

共通のイメージからシステムを大量展開するのは素晴らしいことですが、ルートパスワードやネットワーク設定など、特定のインスタンスに固有のものはどうなるのでしょうか?当社のイメージは DHCP を使用するように設定されており、その結果、システムは DHCP サーバから割り当てられた IP アドレスと固有のホスト名を自動的に受信します。しかし、Network Helper (お使いのシステムのスタティックネットワークを自動的に設定します。) や root パスワードリセットツール (初期の root パスワードを設定し、リセットが必要な場合に緊急時にも使用できます。) など、さまざまな「ヘルパー」も提供しています。これらのツールによりインスタンス固有の情報をベースイメージ上に適用することができます。

もちろんすべてのディストロがこれらのタスクを同じように処理できるわけではないので、私たちのツールはサポートされているすべてのディストロでこれらのタスクを実行できる方法を知っておく必要があります。ディストロの新しいメジャーバージョンでは、通常、完全に動作するようにするためにこれらのシステムを更新する必要があります。例えば、Debian は伝統的にネットワークの設定を /etc/network/interfacesに保存する一方で、CentOSは /etc/sysconfig/network-scriptsに設定値を保存します。幸いなことに、ほとんどのディストロはベータリリースを先行して提供しているので、発売日に向けてこれらの変更を行いすべての準備が整っていることを確認するための時間を十分に確保できます。

結論 

ご覧のように新しいディストロのサポートには多くのことがありますが、このプロセスを自動化することの本当の利点は何でしょうか? 今日のようなプロセスができる数年前までは、典型的なディストロのリリース(ビルドからテスト、提供まで)には早くて丸一日、通常は数日かかり、多くの人が関わっていました。それに比べて、今日のUbuntu 20.04のリリースではコードの変更は5行だけで済み、プロセスの最初から最後まで1時間もかかりませんでした。このようにイメージを構築するアプローチは、多くの時間と手間を省き、徹底的にテストされ、常に改善される一貫性のあるビルドを実現しています。何か提案や見てみたいものがあれば、ぜひ教えてください! 私はIRCではOFTCのblaboonとして、Freenodeではlblaboonとして活動しています。Packerを試してみたい方は、ここに素晴らしいドキュメントがあります。また、独自のPacker用Linodeビルダーも用意しており、これを使用して当社のプラットフォーム上で独自のカスタマイズされた画像を作成することができます。Packer用ビルダーの使用方法についてはこちらのガイド&チュートリアルライブラリをご覧ください。


顧客ではありませんか? 20ドルのクレジットで登録してください。

コメント (4)

  1. Author Photo

    This is brilliant and very timely (for me) as I happened to spend some of last weekend to “reverse engineer” the build process (and discovered the GRUB config quirks) while tried to test migrating a Linode VM over to a on-premises (lab) VM Host and vice versa. Maybe this would be a good write-up, if you are searching for tutorial/blog topics. Many thanks for publishing this!

  2. Nathan Melehan

    Hey A. –

    That sounds like a cool topic! If you’re interested, we actually have a paid freelance contributor program for our documentation library called Write For Linode. You can learn more about the program and apply to it here: https://www.linode.com/lp/write-for-linode/

    • Author Photo

      Hi Nathan
      Thanks for this, it looks very tempting. I started to work on the process for the first migration but I was stopped by Grub2. As described in the Packaging section above, the stripped out boot partition stops me to boot up the the image in my VM Host and I haven’t been able boot up the image dd’d out of Linode. If I create a vanilla VM image with the same Ubuntu version as in my Linode VM, the (virtual) disk is partitioned with two partitions, sda1 hosting grub (I assume this is what you strip out in the build process) and sda2, which is “/”. The image “exported” out of Linode, on the other hand has only a single partition as described above. Is there any documentation describing how to undu the stripping out of sda1, or how insert a new boot (sda1) partition back into the image? Many thanks, A

      • Author Photo

        Ok, I managed to get through booting my local clone in the end and it turns out that the startup process didn’t crash (as I thought), it was just slow*. It is because (unsurprisingly) it has a hard-coded static IP address which now lives on the wrong network, so I had to wait until the network config time-out* during the boot-up process.

        That’s easy enough I’ll just change the config in /etc/network/interfaces (the default/standard place in Ubuntu, and as also mentioned in this article). Looking at the “interfaces” file it, is blank with a note that things have moved on (since I last had to deal with linux networking) and it is now handled by something called “netplan”. [grrrrr….]

        No matter, it can’t be that hard, let’s see what /etc/netplan says. Well, the yaml file says my ethernet interface should be called `enp0s3` and should be getting the address from dhcp. But my actual interface name is `eth0` and has a static address. Where is this coming from?! [&$#^%#]

        Time to “brute force” search the entire config.
        `find /etc/ -exec grep ‘12.34.56.78’ {} \; 2>/dev/null` results in 3 hits, one is by an application so there are only two potential places to change, it might be easy enough to check**:

        `grep -Rn ‘12.34.56.78’ * 2>/dev/null`

        systemd/network/05-eth0.network
        systemd/network/.05-eth0.network

        It was auto-generated by Linode’s Network Helper (as described in the article) which is not available in my lab, unsurprisingly, so let’s just copy back the original config:

        `cp 05-eth0.network 05-eth0.network.bak`
        `cp .05-eth0.network 05-eth0.network`
        `shutdown -r now`

        Bingo!!! The VM came up with a new dynamic IP address and I can ping and nslookup to my heart content!!! I haven’t checked if the actual web application survived the extraction, and what else may have broken in the process.

        *and probably a lot more linode specific configs that are inaccessible to my local clone.
        **The actual IP address is not this

        Lessons learned: It is a lot more complicated to migrate out of Linode to a local VM or different cloud and require a lot of effort to fix/adapt the extracted application and the OS, it would be a lot faster just to build the lab up from the ground up. It might be a simpler process to move the other way around (i.e. develop in my own lab and pull the result into Linode) but wouldn’t hold my breath trying.

        Not sure if my experience warrants an article beyond this (chain of) comment(s). But it was a great weekend project and an inspirational learning exercise, many thanks, Linode!

コメントを残す

あなたのメールアドレスは公開されません。必須項目には*印がついています。