第485回で紹介したaptlyを使えば、簡単に自分専用のリポジトリを構築できます。さらに第487回の方法で任意のアーキテクチャーのパッケージを作ることができます。今回は応用編ということで、ARM用のバイナリパッケージを提供するバックポートリポジトリを作ってみましょう。
リポジトリの作成
第487回でバイナリパッケージの作成方法を学びました。次はそれを公開するリポジトリをaptlyを用いて作成しましょう。aptlyのインストール方法や基本的な使い方は第485回を参照してください。
aptlyで作ったリポジトリのフロントエンド部分(HTTPサーバー部分)はNginxを使うことにします。第485回ではaptlyが作ったユーザーローカルのディレクトリ「~/.aptly/public/
」をリポジトリとして公開していましたが、NginxなどのHTTPサーバーから外部に公開するのであれば「/srv
」以下のディレクトリに置くのが無難でしょう。よってaptlyを実行するユーザーのホームディレクトリに「~/.aptly.conf
」を次のような内容で作成します。もしくは「/etc/aptly.conf
」としてシステムグローバルな設定にしてもかまいません。
「pomera」として公開するリポジトリを「/srv/aptly
」以下に作るよう設定しています。当然のことながらaptlyコマンドを実行するユーザーは該当ディレクトリへの書き込み権限が必要になります。architectures
にはアーキテクチャー非依存とソースパッケージ、それにarmhfを記述していますが、限定しないのであれば空でもかまいません。この設定は個々のaptlyコマンドの-architecture
オプションで上書き可能です。
またローカルリポジトリも作りましょう。
「-distribution
」は公開時のディストリビューション名であり、Ubuntuのリポジトリ(/etc/apt/sources.list
)でいうところの「xenial」や「zesty」です。「-component
」はUbuntuでいうところのmain・universeのようにパッケージの種別ごとに別のディレクトリにしたいときに使用します。最後の「xenial-armhf」がaptlyにおけるリポジトリの名前になります。
パッケージのリポジトリへの取り込み
aptlyのローカルリポジトリにパッケージを取り込みます。第487回でも説明したように、パッケージは「ソースパッケージ」と「バイナリパッケージ」の二種類にわかれます。またそれぞれの種類のパッケージは複数のファイルから構成されます。aptlyはこれらのパッケージを取り込むことでリポジトリを構築するのです。
個々のパッケージを構成するファイル群は「.changes
ファイル」としてリストアップされます。.changes
ファイルにはファイル名だけでなくそのハッシュ値も記録されているために、そのファイルにGPGによる署名を加えるだけでパッケージを構成するファイル群の正当性を担保できるわけです。第487回では話を簡単にするために特に署名のことは考慮せずdebファイルを直接取り込みました。しかしなら単一のソースパッケージから複数のバイナリパッケージを生成する場合は.changes
ファイルを用いて一度に取り込めたほうが便利ですし、よりまっとうな方法と言えます。今回はその方法を紹介しましょう。
まずは.changes
ファイルに署名を行う人のGPG公開鍵をaptlyユーザーの鍵束に取り込んでおきます。
上記の手順でエクスポートした公開鍵ファイルshibata.asc
をaptlyが動くマシン上に何らかの安全な経路を使ってコピーしておきます[1]。もちろん鍵サーバーを経由する方法でもかまいません。
aptlyが動いているマシン上で、この公開鍵を取り込みます。aptly自身はaptlyコマンドを実行したユーザーの「~/.gnupg/trustedkeys.gpg
」を鍵束として使用しますので、「--keyring
」オプションで指定する必要があります。
最後に取り込んだGPG公開鍵で署名された.changes
ファイルをリポジトリに取り込んでみましょう。第487回のやり方に沿ってパッケージをビルドしていれば、ソースパッケージについてはGPG公開鍵による署名が行われているはずです。このソースパッケージをaptlyを実行するマシン上にコピーし、次のコマンドを実行してください。
「-repo
」オプションで取り込むリポジトリ名を指定します。省略した場合は、.changes
ファイルの「Distribution
」フィールドの名前が使われます。また.changes
ファイルの代わりにディレクトリを指定した場合は、そのディレクトリ内部の.changes
ファイルを順番にチェックしていきます。
「-uploaders-file
」オプションを使うと、ユーザー単位でリポジトリへのアップロード権限を細かく設定するJSONファイルを指定できます。詳細は公式ドキュメントの「UPLOADERS.JSON」の項目を参照してください。このオプションを指定しない場合は、すべてのユーザーが自由にパッケージを取り込める状態となります。ただしその場合もオプションで無効化しない限り、.changes
ファイルの署名のチェックは行います。ちなみにaptly repo create
のときにも指定できます。
同じ名前・アーキテクチャー・バージョンのファイルを同じリポジトリ上に取り込みたい場合は、明示的に「-force-replace
」オプションを付けなくてはなりません。
リポジトリにパッケージを取り込むことに成功したら、オリジナルのパッケージファイルは削除されます。もし残したい場合は「-no-remove-files
」オプションを付けてください。
「aptly repo show
」コマンドで、そのローカルリポジトリ上にあるパッケージのリストを得られます。
バイナリパッケージへの署名
一般的なDebianパッケージの開発フローにおいて、パッケージのメンテナーがバイナリパッケージに署名を行うことはありません。バイナリパッケージへの署名はパッケージをビルドするサーバーが自動的に行うためです。しかしながらaptlyで作ったローカルリポジトリーに自分でビルドしたバイナリパッケージを取り込む場合は、自分で署名を行う必要が出てきます。
もっとも手っ取り早い方法はdevscriptsパッケージに所属するdebsign
コマンドを使うことです。
これだけで.changes
ファイルが署名済みのファイルに置き換わります。オプションなどの詳しい使い方についてはdebsignのマニュアルページを参照してください。
あとはソースパッケージと同じように.changes
ファイルを指定すれば、バイナリパッケージ一式がローカルリポジトリに取り込まれます。
「aptly repo show
」コマンドを使うと、バイナリパッケージも追加されていることがわかります。
パッケージリポジトリを公開状態にする
ローカルリポジトリのデータを元にパッケージリポジトリを作成しましょう。第485回でも説明したように公開するパッケージリポジトリはリポジトリの流儀に沿ってHTTPでアクセス可能なディレクトリツリーです。
まずあらかじめ~/.aptly.conf
で指定した公開リポジトリ用のディレクトリを作っておきます。
さらにローカルリポジトリのスナップショットを作成します。そうすることでローカルリポジトリの状態と公開リポジトリの状態を独立して管理できます。
最後に作ったスナップショットを公開します。第485回と異なるのは公開するストレージ(エンドポイント)を明示的に指定することです。~/.aptly.conf
ではFileSystemPublishEndpoints
としてpomera
を作成しましたので、エンドポイント名は「filesystem:pomera
」になります。
エンドポイントとしてローカルストレージ以外にAmazon S3やOpenStack Swiftといったクラウドストレージも指定可能です。また最後のコロンの後ろにパス名を指定することで、サブディレクトリの下にリポジトリを作ることもできます。
作られたディレクトリの中身は次のような構造になっています。
たとえばjp.archive.ubuntu.comの同じディレクトリを見てみると、似たような構造になっていることがわかりますね。ちなみに個々のパッケージファイルは「~/.aptly/
」以下のファイルに対するハードリンクになっているため、ローカルファイルシステムを用いてパッケージを公開するだけであればストレージの使用量は増えません。
Nginxを用いて外部からアクセスできるようにする
ここまでの状態だとローカルファイルシステム上にパッケージディレクトリが配置されているだけです。リポジトリとして運用するためには、これを外部からHTTPでアクセスできるようにしなくてはなりません。といっても難しい話ではなく、他の静的なコンテンツと同様にたとえばHTTPサーバーを使って見えるようにするだけです。
たとえばNginxを使う場合、次のような内容の設定ファイルを「/etc/nginx/sites-avialable/aptly
」として用意し、「/etc/nginx/sites-enabled/
」からシンボリックリンクをはることになるでしょう。server_name
部分をリポジトリのドメイン名にしておきます。またautoindex on
にしておくことで、リポジトリのディレクトリの中身の構造が見えるので何かあったときにユーザーにとっては便利です。ちなみにReleaseファイルなどからリポジトリに属するパッケージファイルのパスを辿れるため、リポジトリ上のパッケージのパスが見えてはいけない場合は別途何らかの対策が必要になります。もちろん単にアクセスするユーザーを制限したい場合は、Basic認証などの手法を使うというのもひとつの手です。
設定したら「sudo service nginx configtest
」「sudo systemctl restart nginx
」などで設定のチェックとサーバーの再起動を行いましょう。ブラウザーでアクセスできることを確認したら、サーバー側の設定は完了です。
クライアント側ではリポジトリの公開鍵とURLを登録します。リポジトリの公開鍵は、aptlyを実行するユーザーがあらかじめエクスポートしておき、何らかの信頼できる経路でクライアント側がそれを取得できるようにしておきます。
一般的には上記ファイルをHTTPS経由で取得できる場所に置いておきます。もしくは鍵サーバー上に公開鍵を登録しておき、その鍵IDのみHTTPS上に記載するというのもひとつの手です。PPAなどはUbuntuの鍵サーバー上に公開鍵を登録し、HTTPS経由で鍵IDを取得する流れになっています。
あとはこのリポジトリ鍵を登録し、sources.list
を設定します。ここでaptlyが動いているマシンのアドレスを「aptly.example.com
」だとしています。
先程登録したtmuxのバックポートパッケージのバージョンが表示されたら成功です。
パッケージのアップロードを簡単にする
パッケージをビルドするマシン(sbuildなどを実行するマシン)と公開するマシン(aptlyを実行するマシン)が異なる場合、.changes
ファイルをはじめとしたビルドした成果物を公開するマシンにコピーする必要があります。このときdput
コマンドを使うと手間が省けて便利です。dputはDebianパッケージのメンテナーが新しいパッケージをアップロードキューに送ったり、UbuntuでもPPAでビルドキューに送る場合に使われています。
dput自体は必要なファイルを指定したサーバーに送るだけの単なるPythonスクリプトであり、/etc/dput.cf
もしくは~/.dput.cf
で設定すれば、簡単に任意のアップロードサーバーを追加できます。
たとえばaptly.example.comの/srv/aptly/queue/
ディレクトリに、aptlyユーザーでscpを使ってポート2222を経由してアップロードするなら次のような設定になります。
dput
コマンドに「対象マシン名」と.changes
ファイルを指定すればアップロードできます。
署名済みかどうかもチェックしてくれるので便利です。ちなみにローカルで一度アップロードすると「changesファイル名.対象マシン名.upload
」というファイルが作られて、多重アップロードを抑止します。もし同じファイルを強制的に再アップロードしたい場合は「--force
」オプションを付けてください。
aptly側でsystemd.timerやcronなどを利用して定期的に/srv/aptly/queue
をチェックするようにしておけば、ローカル側からのアップロード処理だけで新しいリポジトリの公開までを自動化できます。もちろんaptlyのREST APIなどを用いてCIを間に挟むことも可能です。