GitHub Actions による deb パッケージ作成の自動化

Arai, Junya
nttlabs
Published in
10 min readMay 13, 2020

こんにちは.NTT の新井です.

CheckInstall による Slurm の deb パッケージ化」という記事において,Ubuntu 上で手軽に tarball から deb パッケージを作成する方法をご紹介しました.今回はその続編として,GitHub Actions でパッケージ作成スクリプトを実行することによるパッケージ化とリリースの方法を紹介します.また,その応用でプルリクエスト作成時のテストも自動化します.

GitHub Actions

GitHub Actions はソフトウェア開発における定型的な処理 (ワークフロー) の実行を GitHub 上で自動化する仕組み,あるいはサービスです.GitHub のリポジトリに対する push やプルリクエスト作成等のイベントを契機として,GitHub がホストする VM 上でユーザが定義した処理を行うことができます.これは例えば継続的インテグレーション (CI) や継続的デプロイメント (CD) のために使用されます.また,GitHub Actions は無料です (参考).

GitHub Actions の処理は次のような階層化された概念で表現されます:

  • ワークフロー:1つ以上のジョブから構成される処理のまとまり.イベントにより起動される.
  • ジョブ:同じ環境で実行される (=ファイルシステムを共有する) ステップの集合.
  • ステップ:ジョブ環境におけるコマンド実行または1つのアクション.
  • アクション:GitHub Marketplace などで提供されるポータブルな機能.例えばリポジトリのチェックアウトやリリースの作成など.

GitHub Actions を用いたパッケージ化には我々のチームにおいて次のような利点があります:

  • パッケージ作成環境の違いによるパッケージ内容の変化を防げます.パッケージの内容は作成環境にインストールされているライブラリなどによって変化する場合があります.GitHub Actions が提供する環境を使うことで常に同じパッケージを作成できます.(もちろん GitHub 側が環境を変更することもあり得るので,そこは注意が必要ですが.)
  • プロジェクトで使用するファイルを GitHub 上に集約できます.「AWS CodeBuildでAnsibleのCIをしてみた」や「Private RepositoryのGitLFSとAWS CodeBuildを連携する」でご紹介したように,我々のチームでは GitHub と AWS CodeBuild の連携により GPU クラスタの構築スクリプト (Ansible Playbook) をテストしています.テストのためにはインターネットからアクセス可能な場所に内製パッケージを置く必要があります.ローカルでパッケージ化してアップロードするよりも,GitHub 上でパッケージ化しそのままアクセス可能にするほうがシンプルです.

リポジトリの構成

GitHub Actions はリポジトリ単位で設定します.具体的にはリポジトリの直下に.github/workflowsディレクトリを作成し,その中に YAML ファイルでワークフローを定義します.ここではそのファイルを.github/workflows/main.ymlとしましょう.また「CheckInstall による Slurm の deb パッケージ化」では諸事情により gist でパッケージ化スクリプト群を公開していますが,これらをリポジトリに入れることにします.つまり,以下のようなディレクトリ構成のリポジトリがあるものとして説明を始めます.

.
├── .git/
│ └── […]
├── .github/
│ └── workflows/
│ └── main.yml
├── build.sh
├── description-pak
├── include-list
├── postinstall-pak
├── preinstall-pak
└── preremove-pak

ワークフローファイルの記述

ここでは次のようなワークフローを定義することにします:

  • バージョンを示すタグが push されたとき,パッケージ化スクリプトbuild.shを実行し,作成されたパッケージをリリースする.

「バージョンを示すタグ」は GitHub のフィルタパターンにおいてv[0–9]+.[0–9]+.[0-9]+*にマッチするタグと定義します.例えばv0.12.3-rc4などはこのパターンにマッチします.

まずは結論としてこの処理を行うmain.ymlファイルを示します.

main.ymlをこの通りに変更し,add,commit,tag 作成,push を行います.すると GitHub 上で自動的にワークフローの実行が開始されます.

git add .github/workflows/main.yml
git commit
git tag v20.02.2
git push origin v20.02.2
ワークフロー実行中の画面.
ワークフローによって作成されたリリース.

続いてmain.ymlの内容を簡単にご説明します.詳細は GitHub ヘルプをご確認ください.

name: Main workflow
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+*'

ワークフロー名とトリガの定義です.ここでは指定のパターンにマッチする名前のタグが push されたとき起動されるように指定しています.Push 以外にもプルリクエストの作成など様々なイベントをトリガとして設定できます (参考).

jobs:
release:
name: Release
runs-on: ubuntu-18.04
steps:

このワークフローにおける唯一のジョブreleaseの定義です.runs-onではジョブの実行環境を指定します (参考).stepsにジョブを構成するステップを列挙します.

      - name: Check out the repository
uses: actions/checkout@v2
- name: Run the packaging script
run: sudo bash build.sh
- name: Create a release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: This release is created by GitHub Actions.
draft: false
prerelease: false
- name: Upload the package
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_name: slurm_20.02.2-1_amd64.deb
asset_path: ./slurm_20.02.2-1_amd64.deb
asset_content_type: application/vnd.debian.binary-package

ステップはコマンドまたはアクションです.例えば1番目のステップではアクション actions/checkout@v2 を使用してリポジトリの内容を取得します.gitコマンドでも同じことはできますが,このアクションではプライベートリポジトリへアクセスするために必要なトークンの処理や,ワークフローを起動したタグやブランチの自動選択などが自動的に行われます.一方,3番目と4番目のアクションでは環境変数でトークンを渡していることに注意してください.

ちなみに,このワークフローではリリースするファイル名slurm_20.02.2-1_amd64.debがハードコーディングされているため,Slurm のバージョンアップに合わせて変更が必要になります.このあたりをスマートにする方法は要検討です.

テストの追加

前述のワークフローにより GitHub Actions 上でパッケージ化とリリースが可能になりました.しかしそこまでやるのであれば,パッケージ作成スクリプトのテストとパッケージの動作確認もプルリクエストの作成時に実施したいものです.その場合,例えば次のようなワークフローの設計になります.

  1. プルリクエストの編集 (作成を含む),またはバージョンを示すタグの push があったとき,パッケージを作成する.
  2. プルリクエストの編集があったとき,パッケージを実際にインストールし,Slurm の動作をテストする.
  3. バージョンを示すタグの push があったとき,パッケージをリリースする.

これらをジョブとして定義し,1つのワークフローで実施します.トリガが異なるにも関わらずなぜ1つのワークフローにするのでしょうか.それは現状の GitHub Actions においてワークフロー間の依存関係を定義できないためです (参考12).パッケージ作成には時間がかかるので,完了するまで他の処理を止めなければなりません.ジョブ間であれば依存関係を定義できるので,ジョブの実行開始条件としてトリガを確認することにより処理順序を守らせます.具体的には次のようなワークフローを定義します.なおテストのために実行しているtest.shの内容は省略します.

needs: buildによってジョブ間の依存関係を定義しています.さらに if: github.event_name == …でワークフローのトリガを確認しています.buildは常に実行されますが,testpull_requestのとき,releasepushのときにのみ実行されます.また,異なるジョブの間ではファイルシステムが共有されないことに注意が必要です.生成されたパッケージをアーティファクト (成果物) として登録することによりジョブ間で共有しています.

おわりに

この記事では GitHub Actions を用いたパッケージ作成とリリース,およびテストを行う方法についてご紹介しました.

私たち NTT は OSS を活用した研究開発を共に行う仲間を募集しています.ぜひ弊社ソフトウェアイノベーションセンタ紹介ページや,採用情報ページをご覧ください.

--

--

Arai, Junya
nttlabs
Writer for

Researcher, Nippon Telegraph and Telephone (NTT) Corp. Graph algorithms / parallel distributed processing / non-von Neumann processors.