syn-nodejs-puppeteer-3.7 で修正されたようです。
Node.js と Puppeteer を使用するランタイムバージョン - syn-nodejs-puppeteer-3.7
syn-nodejs-puppeteer-3.4まではスクリーンショットを撮影した際に、普通に日本語フォントは表示されていたのですが、syn-nodejs-puppeteer-3.5以降でスクリーンショットの日本語フォント部分が豆腐になった人向けです。
AWS Synthetics Canaryの記事をよむと、リリース当初頃、日本語が豆腐になるというのを読むことがありますが、私はsyn-nodejs-puppeteer-3.3から始めたので、日本語フォントに苦労したことはなかったです。しばらくして 3.5で豆腐になりました。
AWSサポートにも問合せしましたが、同様の問い合わせをいただいていて開発にフィードバック中とのことでした。
そのうち修正されるかなとおもったのですが、3.6になっても修正されていないようなので調査をしました。
原因
fonts.conf の変更により、/opt/fonts/.fonts/ 以下においてある日本語フォントを読みにいかなくなったためです。
対応
canaryのスクリプトで/opt/fonts/.fonts/*.otf を /tmp/.fonts/以下にコピーして、synthetics.launch() しなおす。
fonts.confの変更点
syn-nodejs-puppeteer-3.4 と 3.6 のfonts.confの一部を下に示します。
fonts.confですが、$FONTCONFIG_PATH
が指定されているため、/tmp/aws/fonts.conf
になります。
<?xml version="1.0" ?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/tmp/aws/.fonts</dir>
<dir>~/.fonts</dir>
<!-- syn-nodejs-puppeteer-3.4 (中略)-->
</fontconfig>
syn-nodejs-puppeteer-3.6 のfonts.conf
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/tmp/aws/.fonts</dir>
<dir>/tmp/.fonts</dir>
<dir>/opt/.fonts</dir>
<!-- syn-nodejs-puppeteer-3.6 (中略)-->
</fontconfig>
3.4では /tmp/aws/.fonts
, ~/.fonts
だったものが、3.6から /tmp/aws/.fonts
, /tmp/.fonts
, /opt/.fonts
となっています。
~/.fonts
がなくなったことで、日本語フォントをよめなくなりました。
~/.fonts
ってどこだよ?って話ですが、$HOME
は /opt/fonts
です。
これはlambdaに移動して、スクリプトを読むとそうなっているのが分かります。22行目です。
const log = require('SyntheticsLogger');
const synthetics = require('Synthetics');
const syntheticsUploader = require('SyntheticsUploader');
const fs = require('fs');
exports.handler = async (event, context) => {
const PASS_RESULT = 'PASSED';
const FAIL_RESULT = 'FAILED';
const NO_RESULT = 'ERROR';
let canaryResult = NO_RESULT;
let canaryError = null;
let startTime = null;
let endTime = null;
let returnValue = null;
let resetTime = null;
let setupTime = null;
let launchTime = null;
let customerCanaryCompleted = false;
try {
// Setting HOME environment variable for fonts
process.env.HOME = '/opt/fonts'; // <-ココ
// 以下、略
/opt/fonts/.fonts を調べると以下のようになっています。
フォントはあるけど、3.4では読み込めて、3.5以降では読み込めていないんですね。
/opt/fonts/.fonts
- NotoSansCJKjp-Regular.otf
- NotoSansCJKsc-Regular.otf
- NotoSansCJKtc-Regular.otf
まとめると、これまではfonts.conf の ~/.fonts
の記述により、/opt/fonts/.fonts
以下のフォントファイルがよみこまれていたが、3.5からfonts.confが変わって、読み込まれなくなったということになります。
修正
ということでlambdaでも書き込みやすそうな /tmp/.fonts
に /opt/fonts/.fonts
以下にある日本語フォントをコピーすることにします。
以下のようなスクリプトで /tmp/.fonts
にフォントをコピーします。
const { exec } = require('child_process');
function sh(cmd){
return new Promise((ok, ng) => {
exec(cmd, (err, stdout, stderr) => {
if (err) {
ng(stderr);
} else {
ok(stdout);
}
});
});
}
await sh('mkdir -p /tmp/.fonts')
await sh('cp -t /tmp/.fonts /opt/fonts/.fonts/*.otf');
await synthetics.launch({});
他にも、以下のような方法が考えられます。
- x
/opt/.fonts/
に必要なフォントを含んだレイヤーを作成しておき、Canary作成後、Lambdaの方でレイヤーを挿入する- やってみたけど、うまくいかなかった。Canaryが呼び出すLambdaはバージョンが指定されていて、レイヤーを追加して、新しい関数バージョンを発行しても、Canary側でその関数バージョンを指定する方法がないためです。
- Canaryのコードzipに
.fonts
ディレクトリを作成し、フォントファイルを含めておく- ファイルサイズが大きくなりますが、これは成功します。以下のようなディレクトリレイアウトになります。
- nodejs
- node_modules
- .fonts
- NotoSansJP-Regular.otf
所感
Lambdaであれば、レイヤーとしてフォントファイルを含めたものを用意すればよいと思うのだけど、Canaryだとずいぶんハードルが高くないか? という気分になる。ただしカナリーのスクリーンショットの再現性を高める目的があれば、フォントを同梱することはあるかもしれない。
しかしBlueprintのモニタリングなどを使用してもスクリーンショットで日本語が豆腐になるし、カナリーのコードがzip作成が必須になってくる点を考えるとAWS側で何か修正を行ってほしい。思いつくのは以下の3つ。
-
fonts.conf
に/opt/fonts/.fonts
を含める -
/tmp/aws
以下に日本語フォントを入れておく - Canaryのオプションとして、作成されるLambdaに追加レイヤーを指定するオプションの追加
- 3.4 -> 3.5の変更時に
/opt/fonts/.fonts
を/opt/.fonts
に間違えたよね。これ。- それともCanaryのzipに.fontsファイルを含めることでカスタムフォントを使えるような修正なのだろうか?
追記 / syn-nodejs-puppeteer-3.8で確認
syn-nodejs-puppeteer-3.8がリリースされていたので3.7ではなく、3.8で確認しました。
結果的に /opt/.fonts に NotoSansCJK のフォントがありました。
ls -la /opt/.fonts
total 48117drwxr-xr-x 2 root root 114 Oct 17 17:19 .
drwxr-xr-x 6 root root 93 Nov 17 02:12 ..
-rwxr-xr-x 1 root root 16427228 Oct 17 17:19 NotoSansCJKjp-Regular.otf
-rwxr-xr-x 1 root root 16412332 Oct 17 17:19 NotoSansCJKsc-Regular.otf
-rwxr-xr-x 1 root root 16431292 Oct 17 17:19 NotoSansCJKtc-Regular.otf