在AWS Synthetics Canary中设置日语字体
使用Node.js和Puppeteer的运行时版本为syn-nodejs-puppeteer-3.7。
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这两个位置变成了/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发生了变化,导致无法再加载这些字体文件了。
修改
因此,我们决定将位于/opt/fonts/.fonts目录下的日文字体复制到lambda中更容易写入的/tmp/.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,那难度可能会高许多。然而,如果有提高Canary截图的再现性的目的,可能会考虑将字体包含在内。
但是考虑到使用Blueprint的监控等功能时,屏幕截图中的日语会出现乱码,以及 Canary 代码需要 zip 创建,我希望 AWS 可以在他们的端进行一些修复。以下是我能想到的三种选择。
-
- 将/opt/fonts/.fonts包括在fonts.conf文件中
-
- 在/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.8版本而不是3.7版本。结果发现在/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