最近GNU/Linux系のパッケージング周りの仕組みに初めてチャレンジしている福田です。
GitHub Actionsにおける.deb/.rpmパッケージのテストにVirtualBoxが便利だったので、今回はその方法についてご紹介します。
VirtualBoxとDockerのどちらをテストに使うか
GitHub Actionsで複数のディストリビューション向けのテストをする場合、Dockerが便利です。すぐに起動しますし、ビルド結果をキャッシュすることもできるので、CIの時間を短縮しやすいからです。 ただ、Dockerでは上手くテストできないケースがあります。
たとえば、サービスとして動く.deb/.rpmパッケージのケースです。Docker内ではsystemdが動いていないのでsystemdを使ってサービスを動かす.deb/.rpmパッケージをテストできません。 このようなケースではVirtualBoxが便利です。
DockerはOSを仮想化するだけでマシンを仮想化するわけではありません。つまり、マシンにインストールしたディストリビューションのような普通の起動処理は使われません。普通の起動処理とは、ざっくり言うと、まずブートローダーが起動して、カーネルを読み込んで、/sbin/init
を起動するというような処理です。一方、VirtualBoxはマシンを仮想化するので普通の起動処理と同じ処理で起動した環境を使えます。
サービスとして動く.deb/.rpmパッケージは普通の起動処理で起動した環境用に作られているので、普通の起動処理で起動した環境でテストするべきです。ということで、サービスとして動く.deb/.rpmパッケージのテストにはDockerよりもVirtualBoxの方が向いています。
もう少し詳しい説明が欲しい場合は、たとえば、以下のDockerの公式サイトにあるコンテナーと一般的な仮想マシンとの違いの説明をご覧ください。
VagrantでVirtualBoxを使う
Vagrant1は、VirtualBoxなどの仮想化ツールを便利に扱える強力なツールです。
Vagrant自身は仮想化の機能を一切持ちませんが、VirtualBoxなどの仮想化ツールのフロントエンドとなり、 これを利用することで仮想環境を用いるワークフローの自動化などを簡単に行えます。
今回はこれを利用してテストを行います。
GitHub ActionsでVagrantを使う方法
それでは、GitHub ActionsでVagrant経由でVirtualBoxを使ってテストする方法を紹介します。
macOSを使ったテスト用のjobを設定する
GitHub Actionsではjobの環境をruns-on
で設定しますが、Vagrantを使いたい場合はmacos-12
を設定します。
これは、GitHub Actionsが提供しているUbuntuのrunnerはネストした仮想化機能が有効になっていないからです2。ネストした仮想化機能が有効になっていないとUbuntuのrunnerでVirtualBoxを使えません。
2022-07-22現在、macos-12
のrunnerではネストした仮想化機能が有効になっています。また、デフォルトでVagrantもインストールされているのですぐにVagrant経由でVirtualBoxを使えます3。
GitHub Actionsの大枠の設定は次のようになります。
# {...}
jobs:
build:
name: Build
# {パッケージのビルド}
test:
name: Test
needs: build
runs-on: macos-12
# {Vagrant環境でテスト}
needs
を指定して、build
のjobが終わったら、test
のjobが走るようにしています。
他のjobでビルドしたパッケージを取得する
テストのjobはビルドのjobと分かれているので、テストのjobの環境でビルドしたパッケージを取得する必要があります。 それには次のアップロードとダウンロードのアクションを使います。
- アップロード: actions/upload-artifact
- ダウンロード: actions/download-artifact
ビルドのjobでパッケージをアップロードしておき、テストのjobでそれをダウンロードして利用します。
これを踏まえると、大枠の設定例は次のようになります。
{...}
jobs:
build:
name: Build
{パッケージのビルド}
- uses: actions/upload-artifact@v3
with:
name: {アップロードする名前}
path: {アップロードするパス}
{後処理}
test:
name: Test
needs: build
runs-on: macos-12
steps:
{前処理}
- uses: actions/download-artifact@v3
with:
name: {アップロード時に指定した名前}
path: {ダウンロード先のパス}
{Vagrant環境でテスト}
Vagrantを使う
Vagrantを使うために、まずプロジェクトにVagrantfile
を追加します。今回実際に利用したVagrantfile
は次です。
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
vms = [
{
:id => "centos-7",
:box => "bento/centos-7",
},
{
:id => "debian-bullseye",
:box => "bento/debian-11",
},
{
:id => "almalinux-8",
:box => "bento/almalinux-8",
},
{
:id => "almalinux-9",
:box => "bento/almalinux-9",
},
{
:id => "ubuntu-bionic",
:box => "bento/ubuntu-18.04",
},
{
:id => "ubuntu-focal",
:box => "bento/ubuntu-20.04",
},
]
n_cpus = ENV["VM_N_CPUS"] || 2
n_cpus = Integer(n_cpus) if n_cpus
memory = ENV["VM_MEMORY"] || 1024
memory = Integer(memory) if memory
vms.each do |vm|
id = vm[:id]
box = vm[:box] || id
config.vm.define(id) do |node|
node.vm.box = box
node.vm.provider("virtualbox") do |virtual_box|
virtual_box.cpus = n_cpus if n_cpus
virtual_box.memory = memory if memory
end
end
end
end
複数のディストリビューションを管理しています。
前半のvms
変数の内容を編集することで、用いるディストリビューションの種類を設定できます。
:id
の値はconfig.vm.define
に用いられ、後述するvagrant up
やvagrant ssh
で指定するイメージの名前になります。
:box
の値はconfig.vm.box
(上例ではnode.vm.box
)に用いられ、これが利用したいディストリビューションになります。
例えば以下のサイトから利用したいディストリビューションを探して、その値を設定します。
以上のように:id
と:box
の2つの値を設定することで、複数のディストリビューションを扱うことができます。
詳しいVagrantfile
の設定方法や仕組みについては、次のドキュメントをご覧ください。
Vagrantfile
を追加したら、次のようにテストのjobのstepを設定します。
- name: Run VM
run: |
vagrant up {用いるイメージ名}
- name: Run test
run: |
vagrant \
ssh {用いるイメージ名} \
-- \
{テスト実行ファイル}
「用いるイメージ名」には、Vagrantfile
で設定した:id
の値を指定します。
Vagrantでは、立ち上げたディレクトリが仮想環境内の/vagrant
ディレクトリにマウントされるので、ダウンロードしたパッケージは
/vagrant
からアクセスすることができます。
このようにすることで、ビルドしたパッケージを好きな環境でインストールし、起動できるかどうかなどを確認することができます。
例: RHEL系において、サービスとして正常に起動するかどうかをテストする
例えば以下のようにパッケージをインストールし、サービスとして起動できるかどうかをテストすることができます。
テストファイル: pacakge/test.sh
{事前準備}
sudo dnf install -y /vagrant/{パッケージのパス}
! sudo systemctl status {サービス名}
sudo systemctl enable --now {サービス名}
sudo systemctl status {サービス名}
GitHub Actionsのテストのjobのstep設定例
- name: Run VM
run: |
vagrant up almalinux-9
- name: Run test
run: |
vagrant \
ssh almalinux-9 \
-- \
/vagrant/pacakge/test.sh
まとめ
本記事では、GitHub ActionsとVirtualBoxを使って.deb/.rpmパッケージをテストする方法について紹介しました。
実際に設定したGitHub Actionsは、次になります。
ここではstrategy
のmatrix
を用いることで、複数の環境向けのパッケージのビルドとテストを管理しています。
クリアコードではこのように業務の成果を公開することを重視しています。業務の成果を公開する職場で働きたい人はクリアコードの採用情報をぜひご覧ください。
-
GitHub Actionsが提供しているUbuntuのrunnerは仮想マシン上で動いているので、仮想マシン上でさらに仮想マシンを動かすにはネストした仮想化機能を有効にする必要があります。しかし、Ubuntuのrunnerを動かしているAzureのインスタンスの種類ではネストした仮想化機能を有効にできません。そのためGitHub Actionsが提供しているUbuntuのrunnerでもネストした仮想化機能を有効にできません。参考:調べたユーザーのコメント・中の人からのサポートしていないという回答 ↩
-
macos-11
はデフォルトでVagrantを使えないので、注意して下さい。 ↩