ShipIt

  •  
  •  
  • Category:

PerlモジュールのCPANへのアップロードはShipItというのが良いらしいので使ってみたのだが、ちょいちょい詰まりどころがあったのでメモ

ShipItのインストールにはcpanminusを使用します。
cpanminusのインストール等はここでは書きません。

ShipItのインストール

$ cpanm ShipIt

ShipItの準備

設定ファイルの作成

設定ファイル.shipitをプロジェクトディレクトリの直下に作成します。
0から書いても良いですが、コマンドで自動生成できます。

$ shipit --write-config

これで以下のようなファイルが生成されます。

# auto-generated shipit config file.
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist
# svn.tagpattern = MyProj-%v
# svn.tagpattern = http://code.example.com/svn/tags/MyProj-%v
# CheckChangeLog.files = ChangeLog, MyProj.CHANGES

stepsがshipitで実行する処理の内容です。左から順番に実行されます。
CPANにアップロードする際は UploadCPAN というステップを書き足します。

ちなみに私の設定は以下です。

steps = FindVersion, ChangeVersion, Commit, Tag, MakeDist, UploadCPAN
git.push_to = origin

それぞれのステップの意味は以下のような感じです。

  • FindVersion: 現在のバージョンを取得、リリースを行うバージョンをユーザーの入力から設定します
  • ChangeVersion: ソースコード内に記載されたバージョンを変更します
  • Commit: 変更をコミットしてGithubにプッシュします
  • Tag: gitのタグ付けを行いGithubにプッシュします
  • MakeDist: モジュールを作成します
  • UploadCPAN: CPANにアップロードします

ShipItの実行①

$ shipit
...
Running step ShipIt::Step::UploadCPAN=HASH(0x14dbf1a90)
Upload to CPAN? [Y/n] Y
Upload failed.

cpan-uploadのインストール

Uploadに失敗したのはアップロードするために必要なcpan-uploadコマンドが入っていないからです。
cpan-uploadは以下でインストールします。
古い記事では"cpan-upload-http"や"App::cpanupload"などをインストールすると書いてあったりしますが、時代は流れ現在は以下のモジュールをインストールするのが良さそうです。

$ cpanm CPAN::Uploader

ShipItの実行②

$ shipit
...
Upload to CPAN? [Y/n] Y
Please provide a value for --user
Upload failed.

PAUSEの設定

これはCPANアップロード先のPAUSEアカウントの設定がされてないからです。
以下の設定を~/.pauseとして保存します。

user <username>
password <password>

ShipItの実行③

$ shipit
...
Upload to CPAN? [Y/n] Y
registering upload with PAUSE web server
POSTing upload for /Users/gucchi/shipit-dist/Devel-PatchPerl-Plugin-Darwin-v0.1.2.tar.gz to https://pause.perl.org/pause/authenquery?ACTION=add_uri
request failed with error code 500
  Message: Can't verify SSL peers without knowing which Certificate Authorities to trust
Upload failed.

Mozilla::CAのインストール

これは信頼できるCAを見つけられなくて失敗したということです。
MacではCAはキーチェーンで管理されていますがPerlからは読み込めてないという感じですね。

これはMozilla::CAをのインストールで解決するようです。

$ cpanm Mozilla::CA

ShipItの実行④

$ shipit
...
Upload to CPAN? [Y/n] Y
registering upload with PAUSE web server
POSTing upload for ...
PAUSE add message sent ok [200]

成功です!

ありがとうございました!

Docker Registry API v2を触る

  •  
  •  

なぜか忘れましたがDocker Registry APIをいじります

今回はDockerHubから grafana/grafana:latest のイメージ情報を取得してみます。

とりあえずAPIには認証がかかっておりtokenが必要ですのでまずはtokenを取得します。
取得したtokenはtokenという変数にセットします。
ちなみにshellはfish shellです。

set token (curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:grafana/grafana:pull" | jq -r '.token')

次にmanifestのリストを取得します。

manifestのリストはDocker Registryにはイメージが各アーキテクチャ毎に登録されているので、そのリストになります。

tokenの値はAuthorizationヘッダーに"Bearer <token>"という形で設定します。

curl -sSL -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" -H "Authorization: Bearer $token" "https://registry-1.docker.io/v2/grafana/grafana/manifests/latest" | jq . 677ms  土 4/13 23:22:59 2024
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2416,
"digest": "sha256:3aa2a03d88ad9628485f78e89adcd5b18bcde1aced3e6146bbbd7a718b82b797",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2411,
"digest": "sha256:173b46f35cdbcb4b137868a5488be265eb0bb8487d959bb970e62171225f202f",
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2411,
"digest": "sha256:06c16204fb61a9623d0a3910d0ca7933d751858b36ce0bc9676e507c9f9e3fec",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
}
]
}

次にアーキテクチャ別のmanifestを取得します。
今回はMacを利用しているということでarm64のイメージのmanifestを取得してみます。
digestの値を指定します。

curl -sSL -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -H "Authorization: Bearer $token" "https://registry-1.docker.io/v2/grafana/grafana/manifests/sha256:173b46f35cdbcb4b137868a5488be265eb0bb8487d959bb970e62171225f202f" | jq . 599ms  日 4/14 03:39:48 2024
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 7159,
"digest": "sha256:46becd7c39d0d018028287aa36463a747e4b1149abddeb494e66454849f67376"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 3347715,
"digest": "sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 140,
"digest": "sha256:0b9a5f2b0f5d5270e3efb34422e3a485380df63bc44f805762a8278aae8a22d8"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 3264743,
"digest": "sha256:fcc6842772413979645ab1a68f5a281b53f5c1b7957d8c2afbec10d0eae3e467"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 92,
"digest": "sha256:e1ca30b94fb8c90a259a124eedd07ee51865707386ca6572d443e07b38a30966"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 47122,
"digest": "sha256:c9b151a9c147058dd576609bea6d5ab3e6a8e956ce510e64a6cc01fbee849eea"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 23287,
"digest": "sha256:0b708c20c8dfe23bb6c3a4cab29597599ccb1a0da3722d379a6c33f614c97f0d"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 54154543,
"digest": "sha256:d81743f85f1a571db9633f3972d118d2648dffe75d2958936c961e6fa66d6670"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 50166186,
"digest": "sha256:21c7139cb50e2c66ca3e2bf9ab5f8288a49d4faaebf7dbdaf28463f210ae24bd"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 11936,
"digest": "sha256:a049ab0dfb1f13f3fe22786ef0dcac844db1c55ef440e0007d8664b32176da1b"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1226,
"digest": "sha256:43862b0c980ecbfe03f1033b43f01f80e3f9396de639e141b8a56d03a492b6ff"
}
]
}

Movable TypeをPSGIで動かす

Movable TypeはCGIプログラムですが、
CGIだとリクエストのたびにPerlを起動してプログラムの動かすため非常に遅いです。

とうわけでもう少し高速化したいと思います。

perlの高速化というとmod_perlやFastCGIが真っ先に思い浮かびますが、今回はもっとナウでヤングなPSGIで動かしたいと思います。

PSGIとはPerl Web Server Gateway Interfaceの略で、WebサーバーとWebアプリケーションを繋ぐインターフェイスになります。
PythonのWSGI、RubyのRackをインスパイアしたものみたいです。

というわけでPSGIで高速化してみました。

今回はApacheをリバースプロキシとし、PSGIサーバーはStarmanを使用する。



MTの設定

mt-config.cgiにPIDを保存するファイルを設定する
以下を追記(別にパーミッションさえちゃんとしていればパスはどこでも良い)

PIDFilePath /var/run/mt/mt.pid



Starman


インストール

$ cpanm Task::Plack
$ cpanm XMLRPC::Transport::HTTP::Plack

Task::PlackをインストールすればStarman他関連モジュールがインストールされるとのこと。


systemctlの設定

[Unit]
Description=starman for mt
After=syslog.target
After=network.target
After=mysql.service
[Service]
User=apache
Group=apache
Restart=always
SyslogIdentifier=starman
Environment=MT_HOME=/var/www/cgi-bin/mt
Environment=MT_CONFIG=${MT_HOME}/mt-config.cgi
ExecStart=/bin/sh -c "/usr/local/perl5/perls/perl-5.30.0/bin/starman ${MT_HOME}/mt.psgi --access-log /var/log/starman/access_log --error-log /var/log/starman/error_log --pid `perl -ne 'next if /^#/; print $1 if /^\s*PIDFilePath\s+(.*)/i' ${MT_CONFIG}`"
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

Unitセクションには依存の設定等を書く
movable typeはmysqlを使用するのでmysql起動後に起動するようにする

Serviceセクションにはサービスの起動設定等を書く
今回はExecStartにstarmanの起動コマンドを書いた

あとは以下のようにして自動的に起動するようにしておけば安心

$ sudo systemctl enable starman



Apacheの設定

安全にsslでアクセスするようにしたので443のVirtualHostで以下を設定した

<VirtualHost _default_:443>
...
<IfModule proxy_module>
ProxyPass /cgi-bin/mt/ http://localhost:5000/cgi-bin/mt/
ProxyPassReverse /cgi-bin/mt/ http://localhost:5000/cgi-bin/mt/
</IfModule>
...
</VirtualHost>



これで完了!

apacheとstarmanを起動すれば無事CGI版より早くなったMTを味わえるはず。

Docker on MacのVolumeマウント先

  •  
  •  

Dockerのvolumeはどこにマウントされているか?と言うお話

$ docker volume inspect 
[
    {
        "CreatedAt": "2020-08-19T14:55:42Z",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "volume",
            "com.docker.compose.version": "1.26.2",
            "com.docker.compose.volume": "vol"
        },
        "Mountpoint": "/var/lib/docker/volumes/volume_vol/_data",
        "Name": "volume_vol",
        "Options": null,
        "Scope": "local"
    }
]

これで分かるじゃないか。/var/lib/docker/volumes/volume_vol/_dataだろ。と思った方は大間違い。

$ ls /var/lib/docker/volumes/volume_vol/_data
ls: /var/lib/docker/volumes/volume_vol/_data: No such file or directory

こういうオチが待っている。。。

ない。。。

googleさんに聞いてみると

「Docker for MacのDocker EngineはVM上で動いているので、このMountpointはMac上のPathではなくVM上のPathである」

ということらしい。

なのでscreenでVMに入ってみると良いらしい

$ screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
Can not exec '~/Library/Containers/com.docker.docker/Data/vms/0/tty': Permission denied

。。。

$ ls ~/Library/Containers/com.docker.docker/Data/vms/0/tty
----------  1 user  staff  12  7 30 00:00 /Users/gucchi/Library/Containers/com.docker.docker/Data/vms/0/tty

というわけで、Permissionを変えたりsudoしてみたりしたがダメ


こんな時はnsenterを使えってVMに入るらしい。

$ docker run -it --privileged --pid=host alpine nsenter -t 1 -m -u -n -I sh
# ls /var/lib/docker/volumes/volume_vol/_data
hello.txt

あった!

しかし毎度毎度Docker for Macの特殊な点に悩まされるなぁ。。。

X509v3 Subject Key Identifier

X509証明書のv3拡張にはSubject Key Identifier (SKI)というものがある。

このSKIはそのままでX509証明書に含まれる公開鍵の識別子である。

$ openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 13130459247485585328 (0xb638c31e101f07b0)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN=root ca
        Validity
            Not Before: Aug  4 14:53:26 2020 GMT
            Not After : Aug  4 14:53:26 2021 GMT
        Subject: CN=server
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:18:76:24:20:7e:90:d5:8e:a9:76:3d:1b:0f:56:
                    01:f1:4e:6f:7f:43:71:2c:3f:86:15:45:08:03:2e:
                    d4:2d:d1:12:c9:f1:9e:4f:a6:03:dc:6b:50:ab:a7:
                    c0:4a:62:cc:0f:64:7b:00:fe:9a:d7:84:89:5b:35:
                    e4:e8:c2:50:32
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:localhost
            X509v3 Subject Key Identifier:
                5B:77:97:D1:B9:03:E2:C4:31:F6:84:3F:E6:70:51:BB:86:DD:DD:87
    Signature Algorithm: ecdsa-with-SHA256
         30:46:02:21:00:e0:39:08:21:72:e8:8c:0c:65:5f:e4:34:ed:
         04:bb:69:80:75:e8:d8:05:23:33:e3:6c:27:5d:49:50:a4:45:
         72:02:21:00:af:e8:84:50:95:fc:36:6f:01:13:03:90:f2:f0:
         21:20:cc:0d:42:70:98:c4:af:6a:78:5d:ef:7f:cf:d8:d3:a8

このSKIはopensslコマンドを使用する場合、証明書署名時に以下のような設定のextfileをオプションで与えると書き込まれる

subjectKeyIdentifier = hash

そしてこのhash、ただ公開鍵のハッシュを求めるのかと思ったら違った。。。

OpenSSLの説明(x509v3_config)を見ると2つの設定があるらしい。

  • hashが設定されていたらRFC5258に従って計算したハッシュ値が入る
  • 他の設定(違う文字列?)なら16進の文字列が入る(非推奨)

とのこと

そしてRFC5258には公開鍵からSKIを求める方法は一般的に2つあると書いてある

  • 1つは公開鍵のBIT STRING(excluding the tag, length and number of unused bits)のSHA1ハッシュ
  • もう1つは4bitのタイプフィールドとそれに続く公開鍵のBIT STRINGのSHA1ハッシュの最下位60bit

らしいが、

あくまで一般的な方法の例なので、ユニークな識別子を生成できるなら他の方法でも良い。

ここでopensslのhashという設定は前者になる模様

そんでもってここで言うBIT STRINGとは公開鍵ファイルからタグや長さ等のメタ情報を除いたもの。

これはopensslのasn1parseで求めることができる。

  1. まずパースして構造をチェック
    $ openssl asn1parse -in pub.key
        0:d=0  hl=2 l=  89 cons: SEQUENCE
        2:d=1  hl=2 l=  19 cons: SEQUENCE
        4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
       13:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
       23:d=1  hl=2 l=  66 prim: BIT STRING
    ここでは23がBIT STRINGのオフセットである(オフセットは鍵のアルゴリズムによって変わる)
  2. BIT STRINGのオフセットを設定してパース
    $ openssl asn1parse -in pub.key -strparse 23 -noout -out pub.bin


これでBIT STRINGが求められたのであとはハッシュ(SHA1)の計算をするだけ

$ openssl sha1 pub.bin
SHA1(pub.bin)= 5b7797d1b903e2c431f6843fe67051bb86dddd87


↓ 証明書のSKI(再掲)

X509v3 Subject Key Identifier:
                5B:77:97:D1:B9:03:E2:C4:31:F6:84:3F:E6:70:51:BB:86:DD:DD:87


ちょっと表現が違いますが、見比べてみると全く同じSHA1の160bitのハッシュ値ですねヽ(・∀・)ノ ワチョーイ♪