今日、7月13日は「日本標準時制定記念日」です。
というわけで、この日にちなんだネタを1つ紹介します。
ウェブアプリケーションやウェブサービスを作っていると「数値のカンマ表示」を求められることがあります。数値が4桁以上の場合に "1234" を "1,234" と表示する、というやつです。"1234567890" だと "1,234,567,890" になります。画面上で数値を表示する場合はこのようなカンマを必要に応じて加えた上で表示してほしいという面倒なもの。
静的な HTML でページを作る場合は当然ハードコーディングする形で "1234" を "1,234" に書き換える必要がありますが、アプリケーションとしてページを作っていて、その中でアプリケーション的には変数となるような情報をカンマ表示する、という場合はプログラミングコードの中で自動処理をすることもできるので、それほど神経質にならなくても実現できたりします。
特に Node.js を使っている "大抵の" 場合であれば、JavaScript の標準機能を使って実現することができます。それが Number.toLocaleString() です。この関数、正確には「数値をカンマ表示にする関数」ではなく「数値をロケールに合わせた表示に変換する関数」という名前の通りの機能を持っているのですが、日本であれ欧米であれ、ほとんどのロケールにおいて「数値をロケールに合わせて表示」すると3桁ずつのカンマ表示になります。つまり事実上、この関数を通すことで数値をカンマ表記に切り替えることができるようになります。めでたし、めでたし・・・:
・・・が、今回のブログエントリはこれが上手くいかない例外ケースに関する情報です。それも何故かここで一見すると無関係なはずの docker や k8s といったコンテナ環境が関わってくる話だったりします。
コンテナ環境においては、コンテナイメージを小さくすることが求められているように感じています。その背景には「小さい方が速い」ことや「無料で利用できるコンテナサイズ枠」の問題などが関わっているように感じています。コンテナイメージのサイズを小さくする上で Alpine 製の Linux イメージが多く使われているようです。例えば Node.js アプリケーションのコンテナイメージを作ろうとすると、以下のような Dockerfile ファイルを用意してビルドします(1行目で alpine 製の Node.js v14 イメージを使うよう指定しています):
この alpine イメージはたしかに標準イメージと比較して(余計なものが含まれていないため)軽量で、イメージサイズを小さくすることができます。コンテナイメージでディスク容量を圧迫するような使い方をしている人(自分)にとっては少しでも小さいイメージで使えるだけでも嬉しいし、無料の非公開レジストリを使おうとすると容量制限が厳しいので、こちらも少しでもイメージを小さくしたいという要望が多くあると思いますが、そういった需要を解決する便利なベースイメージだと認識しています。
ところが、この「余計なものが含まれていない」ことが問題になるケースもあります。その1つが「ロケール情報」です。alpine イメージにはロケールに関する情報が含まれていません。それもあっての軽量化なのですが、ロケールが含まれていないということは上述の Number.toLocaleString() 関数も使えないことを意味しています。ローカルの PC で動作確認している時は(ロケールが有効になって)問題と認識できない部分が、コンテナ化されて動かすと動かない、ということが起こり得るわけです。かなり気をつけていないと気付けない点であることも含めて厄介な制約だと感じます。
ちなみに、ロケールが使えない環境下で数値をカンマ表記するにはどうすればよいか・・・ ここは「困った時の正規表現」をおすすめします。例えばこんな感じで関数化して使う、とか:
この部分だけではないのですが、コンテナ環境だけでロケール依存の実装がうまく動かない場合は各種 alpine イメージを使っているかどうかの確認にお気をつけください。そしてこの情報が参考になれば幸いです。
7月13日 #日本標準時制定記念日 : 明石市の蓋は、明石天文科学館と子午線(汚水) https://t.co/alivTQwzju #manhotalk @SatoMachiya
— きむらけい (@dotnsf) July 12, 2021
というわけで、この日にちなんだネタを1つ紹介します。
ウェブアプリケーションやウェブサービスを作っていると「数値のカンマ表示」を求められることがあります。数値が4桁以上の場合に "1234" を "1,234" と表示する、というやつです。"1234567890" だと "1,234,567,890" になります。画面上で数値を表示する場合はこのようなカンマを必要に応じて加えた上で表示してほしいという
静的な HTML でページを作る場合は当然ハードコーディングする形で "1234" を "1,234" に書き換える必要がありますが、アプリケーションとしてページを作っていて、その中でアプリケーション的には変数となるような情報をカンマ表示する、という場合はプログラミングコードの中で自動処理をすることもできるので、それほど神経質にならなくても実現できたりします。
特に Node.js を使っている "大抵の" 場合であれば、JavaScript の標準機能を使って実現することができます。それが Number.toLocaleString() です。この関数、正確には「数値をカンマ表示にする関数」ではなく「数値をロケールに合わせた表示に変換する関数」という名前の通りの機能を持っているのですが、日本であれ欧米であれ、ほとんどのロケールにおいて「数値をロケールに合わせて表示」すると3桁ずつのカンマ表示になります。つまり事実上、この関数を通すことで数値をカンマ表記に切り替えることができるようになります。めでたし、めでたし・・・:
var num = 12345; var str = num.toLocaleString(); // "12,345"
・・・が、今回のブログエントリはこれが上手くいかない例外ケースに関する情報です。それも何故かここで一見すると無関係なはずの docker や k8s といったコンテナ環境が関わってくる話だったりします。
コンテナ環境においては、コンテナイメージを小さくすることが求められているように感じています。その背景には「小さい方が速い」ことや「無料で利用できるコンテナサイズ枠」の問題などが関わっているように感じています。コンテナイメージのサイズを小さくする上で Alpine 製の Linux イメージが多く使われているようです。例えば Node.js アプリケーションのコンテナイメージを作ろうとすると、以下のような Dockerfile ファイルを用意してビルドします(1行目で alpine 製の Node.js v14 イメージを使うよう指定しています):
FROM node:14-alpine
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package*.json ./
COPY . .
EXPOSE 8080
CMD ["node", "app.js"]
この alpine イメージはたしかに標準イメージと比較して(余計なものが含まれていないため)軽量で、イメージサイズを小さくすることができます。コンテナイメージでディスク容量を圧迫するような使い方をしている人(自分)にとっては少しでも小さいイメージで使えるだけでも嬉しいし、無料の非公開レジストリを使おうとすると容量制限が厳しいので、こちらも少しでもイメージを小さくしたいという要望が多くあると思いますが、そういった需要を解決する便利なベースイメージだと認識しています。
ところが、この「余計なものが含まれていない」ことが問題になるケースもあります。その1つが「ロケール情報」です。alpine イメージにはロケールに関する情報が含まれていません。それもあっての軽量化なのですが、ロケールが含まれていないということは上述の Number.toLocaleString() 関数も使えないことを意味しています。ローカルの PC で動作確認している時は(ロケールが有効になって)問題と認識できない部分が、コンテナ化されて動かすと動かない、ということが起こり得るわけです。かなり気をつけていないと気付けない点であることも含めて厄介な制約だと感じます。
ちなみに、ロケールが使えない環境下で数値をカンマ表記するにはどうすればよいか・・・ ここは「困った時の正規表現」をおすすめします。例えばこんな感じで関数化して使う、とか:
function myLocaleString( num ){ return String(num).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'); } var num = 12345; var str = myLocaleString( num ); // "12,345"
この部分だけではないのですが、コンテナ環境だけでロケール依存の実装がうまく動かない場合は各種 alpine イメージを使っているかどうかの確認にお気をつけください。そしてこの情報が参考になれば幸いです。