poudriereを使ったので経緯を記す。
poudriereは自前のpkgngレポジトリを作るツール。
自前のレポジトリを作るのは、自前のpackageを置きたいときや、オフラインマシンにpackageを提供したいとき、である。

poudriereの構築は、以下二つのサイトに沿えばできる。
ただ、簡潔にまとめられているので、本記事では補足も併せてまとめる。
http://blog.etoilebsd.net/post/Home_made_pkgng_repo
http://w.vmeta.jp/tdiary/?date=20130205

仕組み

poudriereがどのようにしてpackageを作るかというと。
OS/アーキテクチャごとにjailを作り、そこでportsからpackagesを作る。
つまりホストのOS|アーキテクチャと違っていても大丈夫だが、ホストは最新にしておいた方がよい。

packagesはあるディレクトリにまとめられる。
ディレクトリはそのままwebで公開できる形式になっている。
他のマシンから、pkgngでつなげば、自家製packagesを取得できる。

作成するpackagesは自分で選ぶことができる。
また、オプションも選ぶことができる。
オプションはまた別途。

必要なもの

zpoolを最低7GB用意しておくこと。

インストール

ports-mgmt/poudriereからportsでもpkgでもよいのでインストール。

設定ファイル

まず設定ファイルを作る。
/usr/local/etc/poudriere.conf.sampleをもとに。

/usr/local/etc/poudriere.conf

# 作成しておいたzpoolの名前をここで指定
ZPOOL=vault

# 上記のzpoolから切り出したzfsを、
# ここで示したディレクトリにマウントしておく。
ZROOTFS=/poudriere

# FreeBSDの部品の取得先。国内にしておこう。
FREEBSD_HOST=ftp://ftp2.jp.freebsd.org

# デフォルトのまま
RESOLV_CONF=/etc/resolv.conf

# デフォルトでいいでしょう。
BASEFS=/usr/local/poudriere

# デフォルトでいいでしょう。
USE_PORTLINT=no

# デフォルトでいいでしょう。
USE_TMPFS=yes

# デフォルトでいいでしょう。
DISTFILES_CACHE=/usr/ports/distfiles

# proxyの指定が必要であれば
export HTTP_PROXY="http://proxy:8080/"
export FTP_PROXY="http://proxy:8080/"

poudriere作業用zfsの準備

zpoolからzfsを切り出し、/poudriereにマウント。
poudriere.confを参照すると、最低でも7GBとある。

zfsの操作はよろしければこちらをどうぞ。
../../../?p=1827

結果として以下のような環境。
20.0Gのzpoolをvaultとして作成している。

$ zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
vault  19.9G   190K  19.9G     0%  1.00x  ONLINE  -
$ zpool status
  pool: vault
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        vault       ONLINE       0     0     0
          ada1      ONLINE       0     0     0

errors: No known data errors

ここからpoudriereとして切り出し。

$ zfs list
NAME              USED  AVAIL  REFER  MOUNTPOINT
vault            45.7M  19.5G    31K  /vault
vault/poudriere  45.0M  19.5G  45.0M  /poudriere

それを/poudriereにマウント。

$ mount
/dev/ada0p2 on / (ufs, local, journaled soft-updates)
devfs on /dev (devfs, local, multilabel)
vault/poudriere on /poudriere (zfs, local, nfsv4acls)

再起動しても大丈夫なようにfstabに書き込み

$ cat fstab
# Device        Mountpoint      FStype  Options Dump    Pass#
/dev/ada0p2     /               ufs     rw      1       1
/dev/ada0p3     none            swap    sw      0       0
vault/poudriere /poudriere      zfs     rw      0       0

以降、本格的な作業に。

デフォルトのportstreeを作る。: poudriere ports

jailごとにportsディレクトリを持っていてはディスクがいくらあっても足らない。
そこでportsディレクトリは全jailsで共有する。
そのportsディレクトリ、portstreeを作る。

poudriere ports -cで作成。
場所は/poudriere/ports/defaultに作られる。

ちなみに、二回目からは-uで更新。
指定がなければportsnapが使われる。
svnとかが使いたければ-m svnなどと指定する。

作成例

$ sudo poudriere ports -c
====>> Creating default fs... done
====>> Extracting portstree "default"...
Looking up portsnap.FreeBSD.org mirrors... none found.
Fetching public key from portsnap.FreeBSD.org... done.
Fetching snapshot tag from portsnap.FreeBSD.org... done.
Fetching snapshot metadata... done.
Fetching snapshot generated at Fri Nov  1 21:00:43 JST 2013:
98c3a00130d24348ff5bcca8474e4c6cb777d838e8f5d2100% of   69 MB 3590 kBps 00m19s
Extracting snapshot... done.
Verifying snapshot integrity...
(略)

二回目以降の例
すでにportsがある状態で-cを指定すると怒られる。

$ sudo poudriere ports -c
====>> Error: The ports tree default already exists

$ sudo poudriere ports -u
====>> Updating portstree "default"
Looking up portsnap.FreeBSD.org mirrors... none found.
Fetching snapshot tag from portsnap.FreeBSD.org... done.
Fetching snapshot metadata... done.
Updating from Fri Nov  1 21:27:07 JST 2013 to Fri Jan 17 22:08:55 JST 2014.
Fetching 4 metadata patches... done.
Applying metadata patches... done.
Fetching 4 metadata files... done.
Fetching 11146 patches.....10
(略)

各システム向けのJailを作る: poudriere jail

いよいよ個別のjail。
pkgを提供したいシステムに合わせてjailを作る。

jailを作るにはpoudriere jailを使う。
poudriere jailでオプション一覧が表示される。

-jでjailname指定、-vでFreeBSDバージョン、-aでアーキテクチャ(i386かamd64)を指定。
-cで作成、-dで削除、-lで一覧、-sで開始、-kで停止、-uで更新。

後で見返した時に分からなくなるので、jail名にはシステム関連の情報を入れておくとよい。
たとえば9.2-RELEASE i386向けなら92i386というように。

実行例

$ sudo poudriere jail -c -j 92i386 -v 9.2-RELEASE -a i386
====>> Creating 92i386 fs... done
====>> Fetching base.txz for FreeBSD 9.2-RELEASE i386
/poudriere/jails/92i386/fromftp/base.txz      100% of   60 MB 6703 kBps 00m10s
====>> Extracting base.txz... done
====>> Fetching src.txz for FreeBSD 9.2-RELEASE i386
/poudriere/jails/92i386/fromftp/src.txz       100% of   95 MB 6049 kBps 00m16s
====>> Extracting src.txz... done
====>> Fetching games.txz for FreeBSD 9.2-RELEASE i386
/poudriere/jails/92i386/fromftp/games.txz     100% of  861 kB 4705 kBps 00m00s
====>> Extracting games.txz... done
====>> Cleaning up... done
====>> Jail 92i386 9.2-RELEASE i386 is ready to be used

一覧の例

$ sudo poudriere jail -l
JAILNAME             VERSION              ARCH    METHOD
92i386               9.2-RELEASE          i386    ftp

削除例

$ sudo poudriere jail -d -j 92i386
====>> Removing 92i386 jail... done
$
$ sudo poudriere jail -l
JAILNAME             VERSION              ARCH    METHOD
$

このときのmountの出力
えらいことに。

$ mount
/dev/ada0p2 on / (ufs, local, journaled soft-updates)
devfs on /dev (devfs, local, multilabel)
vault/poudriere on /poudriere (zfs, local, nfsv4acls)
vault/poudriere/data on /usr/local/poudriere/data (zfs, local, nfsv4acls)
vault/poudriere/ports on /poudriere/ports (zfs, local, nfsv4acls)
vault/poudriere/ports/default on /usr/local/poudriere/ports/default (zfs, local, nfsv4acls)
vault/poudriere/jails on /poudriere/jails (zfs, local, nfsv4acls)
vault/poudriere/jails/92i386 on /usr/local/poudriere/jails/92i386 (zfs, local, nfsv4acls)

jailの作成が失敗するとき

失敗しなかったらこの章は読み飛ばしてOK.
最初のCreatingで失敗するときは、以前に作った何かが邪魔しているはず。

$ sudo poudriere jail -c -j 92i386 -v 9.2-RELEASE -a i386
====>> Creating 92i386 fs... done
mkdir: /poudriere/jails/92i386: No such file or directory
====>> Fetching base.txz for FreeBSD 9.2-RELEASE i386
fetch: /poudriere/jails/92i386/fromftp/base.txz: open(): No such file or directory
fetch: /poudriere/jails/92i386/fromftp/base.txz: open(): No such file or directory
====>> Error: Failed to fetch from ftp://ftp2.jp.freebsd.org/pub/FreeBSD/releases/i386/i386/9.2-RELEASE/base.txz
====>> Error while creating jail, cleaning up.
====>> Removing 92i386 jail... done

zfs listすると同じ名前の残骸がある。

$ zfs list
NAME                            USED  AVAIL  REFER  MOUNTPOINT
vault                          2.06G  17.5G    31K  /vault
vault/poudriere                2.06G  17.5G   561M  /poudriere
vault/poudriere/data             32K  17.5G    32K  /usr/local/poudriere/data
vault/poudriere/jails          1000M  17.5G    32K  /poudriere/jails
vault/poudriere/jails/92i386   1000M  17.5G  1000M  /poudriere/jails/92i386
vault/poudriere/ports           545M  17.5G    31K  /poudriere/ports
vault/poudriere/ports/default   545M  17.5G   545M  /usr/local/poudriere/ports/default

削除。オプションなしではうまくいかないので-rで再トライ。

$ sudo zfs destroy vault/poudriere/jails/92i386
cannot destroy 'vault/poudriere/jails/92i386': filesystem has children
use '-r' to destroy the following datasets:
vault/poudriere/jails/92i386@clean
$ sudo zfs destroy -r vault/poudriere/jails/92i386
$

きれいになった。

$ zfs list
NAME                            USED  AVAIL  REFER  MOUNTPOINT
vault                          1.08G  18.5G    31K  /vault
vault/poudriere                1.08G  18.5G   561M  /poudriere
vault/poudriere/data             32K  18.5G    32K  /usr/local/poudriere/data
vault/poudriere/jails            32K  18.5G    32K  /poudriere/jails
vault/poudriere/ports           545M  18.5G    31K  /poudriere/ports
vault/poudriere/ports/default   545M  18.5G   545M  /usr/local/poudriere/ports/default

作成したいpackagesのリストを作る

作成したいpackagesを指定する。
テキストファイルにpackagesを並べればよい。

ただしOriginで記載すること。
Originっていうのは…たとえばrsyncならnet/rsyncと書く。
Originが分からなければ、pkg searchするときに-oを付ければよい。

$ pkg search -o rsync
net/grsync
net/librsync
mail/maildirsync
net/rsync
sysutils/rsyncbackup
sysutils/rsyncmanager
sysutils/rsyncrypto

psearch(ports-mgmt/psearch)でもできる。

$ psearch rsync
archivers/rvm             Archive manager that uses rsync to manage backups
devel/p5-File-DirSync     Perl5 module for synchronizing two directories rapidly
mail/maildirsync          Online synchronizer for Maildir-format mailboxes
net/grsync                GTK frontend for rsync
net/librsync              Library for delta compression of streams
net/p5-File-Rsync         Perl convenience wrapper for the rsync(1) program
net/p5-File-RsyncP        Perl Rsync client
net/rsync                 Network file distribution/synchronization utility
sysutils/dirvish          Network backup system based off of rsync
(略)

試しにrsyncだけ書く。

$ cat ./pkg.list
net/rsync

packagesの作成: poudriere bulk

いよいよ作成。
作成にはpoudriere bulkを使う。
poudriere bulkでオプションを一覧できる。

-fで作成するパッケージリストを指定。さっき作ったやつ。

特定のjailでのみ実施したい場合は-jでjailname指定。
-cで作成したpackagesをすべて吹き飛ばす。
-C -f に書かれたpackagesのみ消す。

では実行。
初回なのでpkgも作ってくれているようですな。

$ sudo poudriere bulk -j 92i386 -f ./pkg.list
====>> Creating the reference jail... done
====>> Mounting system devices for 92i386-default
====>> Mounting ports/packages/distfiles
====>> Mounting packages from: /usr/local/poudriere/data/packages/92i386-default
====>> Logs: /usr/local/poudriere/data/logs/bulk/92i386-default/2014-01-20_22h03m21s
====>> Appending to make.conf: /usr/local/etc/poudriere.d/92i386-make.conf
/etc/resolv.conf -> /usr/local/poudriere/data/build/92i386-default/ref/etc/resolv.conf
====>> Starting jail 92i386-default
====>> Calculating ports order and dependencies
====>> pkg package missing, skipping sanity
====>> Cleaning the build queue
====>> Building 2 packages using 1 builders
====>> Starting/Cloning builders
====>> Hit CTRL+t at any time to see build progress and stats
====>> [01] Starting build of ports-mgmt/pkg
====>> [01] Finished build of ports-mgmt/pkg: Success
====>> [01] Starting build of net/rsync
====>> [01] Finished build of net/rsync: Success
====>> Stopping 1 builders
====>> Creating pkgng repository
Generating repository catalog in /packages: done!
====>> Cleaning up
====>> Umounting file systems
====>> Built ports: ports-mgmt/pkg net/rsync

====>> [92i386-default] 2 packages built, 0 failures, 0 ignored, 0 skipped
====>> Logs: /usr/local/poudriere/data/logs/bulk/92i386-default/2014-01-20_22h03m21s
$

自家製packagesの公開

さて。
作成したpackagesはどこにあるかというと、今回の場合は以下である。

/usr/local/poudriere/data/packages/92i386-default/

このディレクトリをwebサーバで公開する。
※もちろん、webサーバで公開しているディレクトリに中身を移しても可。

この場所は、poudriere.confのPOUDRIERE_DATAで決まる。
${POUDRIERE_DATA}/packages/<jailname>-default/となる。
もしこの場所が気に食わなかったら、POUDRIERE_DATAを変える。

lsで中身を見てみると、オフィシャルpkgsiteのものと全くそっくりな内容になっている。

$ ls /usr/local/poudriere/data/packages/92i386-default/
All             Latest          digests.txz     packagesite.txz

ではこれをwebサーバで公開する。
ここではnginxを例にとる。
nginx.confは下記のように。

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            autoindex on; #Here!
            root   /usr/local/poudriere/data/packages; #Here!
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }
    }
}

デフォルトからほとんど変えていない。
変えたのは、#Here!と記載した箇所。
rootを/usr/local/poudriere/data/packagesに向ける。
autoindexをonにする。
nginxは、デフォルトではautoindex offなので、明示的に指定しないとForbiddenを食らってしまう。

nginxを起動して;

$ sudo service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

接続確認。良さそうですな。

$ w3m http://localhost/92i386-default/
Index of /92i386-default/

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

../
All/                                               20-Jan-2014 22:24
Latest/                                            20-Jan-2014 22:06
digests                                            20-Jan-2014 22:24
digests.txz                                        20-Jan-2014 22:07                 3
packagesite.txz                                    20-Jan-2014 22:07                12
packagesite.yaml                                   20-Jan-2014 22:24

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

webサーバを他の用途にも使っている場合には、以下のようにlocation /packages/を/usr/local/poudriere/dataに向ければよい。
※冗長なのでserverディレクティブの中しか引用しない。

server {
        listen       80;
        server_name  localhost;
        location / {
            root   /usr/local/www/nginx;
            index  index.html index.htm;
        }
        location /packages/ {
            autoindex on;
            root   /usr/local/poudriere/data;
        }

クライアント側の設定

やっとたどり着いた。
クライアント側では/etc/pkg/の下か、/usr/local/etc/pkg/repos/の下に以下のような設定ファイルを作る。
ここで192.168.200.111はサーバのアドレス。

/etc/pkg/homebrew.conf

homebrew: {
  url: "http://192.168.200.111/92i386-default",
  enabled: yes
}

こうしておき、pkg -vvとすると見えるはず。

Repositories:
  homebrew: {
    url             : "http://192.168.200.111/92i386-default",
    enabled         : yes
  }

pkg updateするとさっき作ったpackagesも見える。

$ sudo pkg update
Updating repository catalogue
digests.txz                         100%  352     0.3KB/s   0.3KB/s   00:00
packagesite.txz                     100% 1904     1.9KB/s   1.9KB/s   00:00
Incremental update completed, 2 packages processed:
0 packages updated, 0 removed and 2 added.

いろんな工夫については別途。