ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

renderd から Mapnik を使うときに 「no datasource plugin directories have been successfully registered」 って言われる問題

背景

renderd (mod_tile から使われるマルチスレッドのプロセス) から Mapnik を使って地図タイルをレンダリングしようとしている。

Linux ディストリビューションとして Ubuntu 18.04 を使用して、renderd は APT リポジトリ ppa:osmadmins/ppa の renderd パッケージを使用。 Mapnik もこのパッケージの依存パッケージ (libmapnik3.0) としてインストールされる。

上記パッケージで renderd をインストールした場合に自動的に生成される設定ファイルは /etc/renderd.conf に置かれ、その内容は下記のようになっている。

[renderd]
stats_file=/var/run/renderd/renderd.stats
socketname=/var/run/renderd/renderd.sock
num_threads=4
tile_dir=/var/lib/mod_tile

[mapnik]
plugins_dir=/usr/lib/mapnik/2.0/input
font_dir=/usr/share/fonts/truetype/ttf-dejavu
font_dir_recurse=false

[default]
URI=/osm/
XML=/etc/mapnik-osm-data/osm.xml
DESCRIPTION=This is the standard osm mapnik style
;ATTRIBUTION=&copy;<a href=\"http://www.openstreetmap.org/\">OpenStreetMap</a> and <a href=\"http://wiki.openstreetmap.org/w\
iki/Contributors\">contributors</a>, <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a>
;HOST=tile.openstreetmap.org
;SERVER_ALIAS=http://a.tile.openstreetmap.org
;SERVER_ALIAS=http://b.tile.openstreetmap.org
;HTCPHOST=proxy.openstreetmap.org

遭遇した問題 : エラーが発生する

renderd のプロセスを起動した後、下記のようなエラーが発生していた。

An error occurred while loading the map layer 'ajt': Could not create datasource for type: 'shape' (no datasource plugin directories have been successfully registered) encountered during parsing of layer 'ocean-lz' in Layer at line 269 of '/home/renderaccount/src/openstreetmap-carto/mapnik.xml'

とか

An error occurred while loading the map layer 'ajt': Could not create datasource for type: 'postgis' (no datasource plugin directories have been successfully registered) encountered during parsing of layer 'landcover-low-zoom' in Layer at line 755 of '/home/renderaccount/src/openstreetmap-carto/mapnik.xml'

調べたこと

解決

設定ファイルのプラグインディレクトリ名が違っていたので 「no datasource plugin directories have been successfully registered」 って言われていたのだった。 ディレクトリ名を修正したら解決した。

読んだ : JUnit 実践入門 〜 体系的に学ぶユニットテストの技法

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

既に JUnit 5 が出ているし今更感はある (本書は JUnit 4 を題材にしている) けど、テストの全体的な話も学べるかなって思って読んだ。 JUnit 4 の話もありつつテスト全般に関する知見も書かれているので、(類書も少ないので) 読む機会がある人はさらっと読んでみるといいかもしれない。

新しく学んだこと

テスト全般

  • テストフィクスチャ (test fixtures) : テストの対象やテストの入力値や検証用の値、外部リソースなどの実行環境やテストの実行前に必要なオブジェクトの操作などのこと。
    • 狭義にはテストデータだけを指して 「テストフィクスチャ」 と呼ぶこともあるらしい。
  • 振舞駆動開発 (behavior driven development; BDD) : ソフトウェアの相互作用に着目してソフトウェアがどのように振る舞うかを定義することを起点とした開発技法
    • テスト駆動開発と似ている部分もあるが、ソフトウェア全体がテスト対象で、ユースケースシナリオのシナリオの粒度でシステムをテストするという違いがある。
    • 語彙として、Given (前提) / When (条件) / Then (ならば) というものが使われる。 それぞれテスト駆動開発の arrange (set up) / act (exercise) / assert (verify) に対応する。

JUnit 4 について

docker build 時の apt install が遅い問題 (docker build の --add-host オプションを使って APT のパッケージリポジトリを国内ミラーに設定できる)

こんにちは、Docker ビルドおじさんです。

ubuntu:18.04 ベースで Dockerfile を書いてビルドしまくってるのですが、apt install がとにかく遅い!!! なぜなら日本に住んでいるから!! archive.ubuntu.com が遠い!!!


解決方法

調べてみたらいろいろ解決策がありそうだった。

解決策 その 1

日本を出る。 archive.ubuntu.com の近くに行きましょう。

解決策 その 2

Dockerfile をいじって (一時的にでも) APT のパッケージリポジトリの URL を国内ミラーに変更する。 「apt docker 遅い」 みたいなキーワードで検索するとこの方法がひっかかる。

解決策 その 3

apt-cacher みたいなやつでキャッシュしたり、Squid による透過型プロキシでキャッシュしたりする。 わりとこれが素直な方法な気もするが、ちょっと大変そうな気もする。

解決策 その 4

この記事で共有したいのはこの方法。 docker build コマンドの --add-host オプションを使って APT のリポジトリのホスト名に対応する IP アドレスを書き換えちゃう方法。

例えば ubuntu:18.04 をベースとするイメージの場合、リポジトリのホスト名として archive.ubuntu.com などが使われていて、国内ミラーは jp.archive.ubuntu.com となっているので、nslookup jp.archive.ubuntu.com で国内ミラーの IP アドレスを調べて、docker build --add-host="archive.ubuntu.com:xxx.xxx.xx.xx" . という感じで国内ミラーの IP アドレスを指定してやると良さそう。

セキュリティ的なところはちょっと気になる。

Ubuntu では ca-certificates パッケージで CA 証明書をインストールできるぞ

1 行まとめ

Ubuntu ベースの Docker コンテナSSL 接続をするために ca-certificates パッケージをインストールしましょう。

エラー内容

Ubuntu 18.04 (ubuntu:18.04) ベースの Docker コンテナで HTTPS 接続ができなくて npm install に失敗した。

root@068c8e545fca:/# npm install -g carto
npm ERR! Linux 4.9.125-linuxkit
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "-g" "carto"
npm ERR! node v8.10.0
npm ERR! npm  v3.5.2
npm ERR! code UNABLE_TO_GET_ISSUER_CERT_LOCALLY

npm ERR! unable to get local issuer certificate
npm ERR!
npm ERR! If you need help, you may report this error at:
npm ERR!     <https://github.com/npm/npm/issues>

npm ERR! Please include the following file with any support request:
npm ERR!     /npm-debug.log

見るからに CA 証明書のエラーっぽい。 /npm-debug.log の中身を見ると以下のような感じ。

0 info it worked if it ends with ok
1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'install', '-g', 'carto' ]
(略)
15 info attempt registry request try #1 at 10:34:44 AM
16 verbose request id 454780186dc942d1
17 http request GET https://registry.npmjs.org/carto
18 info retry will retry, error on last attempt: Error: unable to get local issuer certificate
19 info attempt registry request try #2 at 10:34:54 AM
20 http request GET https://registry.npmjs.org/carto
21 info retry will retry, error on last attempt: Error: unable to get local issuer certificate
22 info attempt registry request try #3 at 10:35:54 AM
23 http request GET https://registry.npmjs.org/carto
24 silly fetchPackageMetaData Error: unable to get local issuer certificate
24 silly fetchPackageMetaData at TLSSocket. (_tls_wrap.js:1105:38)
24 silly fetchPackageMetaData at emitNone (events.js:106:13)
24 silly fetchPackageMetaData at TLSSocket.emit (events.js:208:7)
24 silly fetchPackageMetaData at TLSSocket._finishInit (_tls_wrap.js:639:8)
24 silly fetchPackageMetaData at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38)
24 silly fetchPackageMetaData error for carto { Error: unable to get local issuer certificate
24 silly fetchPackageMetaData at TLSSocket. (_tls_wrap.js:1105:38)
24 silly fetchPackageMetaData at emitNone (events.js:106:13)
24 silly fetchPackageMetaData at TLSSocket.emit (events.js:208:7)
24 silly fetchPackageMetaData at TLSSocket._finishInit (_tls_wrap.js:639:8)
24 silly fetchPackageMetaData at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38) code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' }
(略)
30 verbose stack Error: unable to get local issuer certificate
30 verbose stack at TLSSocket. (_tls_wrap.js:1105:38)
30 verbose stack at emitNone (events.js:106:13)
30 verbose stack at TLSSocket.emit (events.js:208:7)
30 verbose stack at TLSSocket._finishInit (_tls_wrap.js:639:8)
30 verbose stack at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38)
31 verbose cwd /
32 error Linux 4.9.125-linuxkit
33 error argv "/usr/bin/node" "/usr/bin/npm" "install" "-g" "carto"
34 error node v8.10.0
35 error npm v3.5.2
36 error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY
37 error unable to get local issuer certificate
38 error If you need help, you may report this error at:
38 error <https://github.com/npm/npm/issues>
39 verbose exit [ 1, true ]

curl コマンドを試してみるも、当然ながらこちらも CA 証明書のエラー。

root@068c8e545fca:/# curl https://google.com/
curl: (77) error setting certificate verify locations:
  CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs

原因と対応

Ubuntu では基本的な CA 証明書が ca-certificates パッケージで提供されている。 これがインストールされていない状態で npm install コマンドや curl コマンドで HTTPS 通信しようとすると CA 証明書のエラーが発生する。 curl パッケージなどをインストールする際に、デフォルトでは推奨パッケージとして ca-certificates パッケージもインストールされるのでこのエラーには遭遇しづらいが、Docker イメージをビルドする際に apt install -y --no-install-recommends curl という感じで --no-install-recommends オプションを付けていると ca-certificates パッケージがインストールされずに、上記の状態になる。

対策としては、単純に ca-certificates パッケージをインストールすれば良い。

Java EE 技術から EE4J (Jakarta EE) 技術に移行する

2017 年に発表された Java EE の Eclipse Foundation への移管。 移管されたプロジェクトをまとめるルートプロジェクトの名前は Eclipse Enterprise for Java (EE4J) で、Java EE に相当するプラットフォームの名前は Jakarta EE となっている *1

EE4J には JAX-RSJSON Processing (JSON-P) などの Java EE の一部として使われていたプロジェクトも移管されている。 これらを単体で使う場合も今後は EE4J のものを使っていくべきだろう。 (古いリポジトリの方は更新されないだろうので。)

EE4J 傘下になってからの最初のリリースがぼちぼちなされていたりして、そろそろ EE4J の方に移行できるようになってきているので、移行について調べたことをまとめておく。

EE4J の各プロジェクト

EE4J 傘下のプロジェクトについては EE4J プロジェクトページ からリンクがあるので、それを辿ると見つけられる。 例えば JAX-RS のページや JSON-P のページは下記である。

EE4J 各プロジェクトの Maven リポジトリ

EE4J への移管に伴って、多くのプロジェクトの API や参照実装 (Reference Implementation; RI) の Maven リポジトリのグループ ID やアーティファクト ID が変更されている。 API については下記ページにまとめられている。

見た感じでは、javax という部分が jakarta に変更されている模様 *2

参照実装についてはプロジェクトごとに異なるようである。

例えば、JSON-P の参照実装については下記のように書かれており、org.glassfish:javax.json から org.glassfish:jakarta.json に変更されていることがわかる。

The main API jar file is now located at jakarta.json:jakarta.json-api and the main RI jar file is now located at org.glassfish:jakarta.json.

JSON Processing (JSON-P)

一方で、JAX-RS の参照実装である Jersery については、バージョン 2.28 が最初の Jakarta EE 実装としてリリースされているが、特にグループ ID やアーティファクト ID の変更はないようである。

ソースコードの変更は必要か?

Maven アーティファクトの名前が変わってはいつつも、API 自体に変更はない。 Java EE 時代の最後の API を使っているソースコードであれば、そのまま EE4J の最初のリリースに移行できるはず。

This is common for every Jakarta EE project this release: it was required not to provide any changes in API and functionality to ensure the compatibility between last Java EE and initial Jakarta EE releases.

Jersey 2.28 has been released | Jan's Blog

*1:EE4J と Jakarta EE の名前の使い方などは Jakarta EE の FAQ に書かれている。 が、これを読んでも正直なところ EE4J と Jakarta EE の使い分けがいまいちわからない……。

*2:正式な名前変更のルールについてはどこかで言及されているのかもわからないが、見つけられていない。