Linux
CentOS
docker

Dockerfileで日本語ロケールを設定する方法。およびロケールエラーの回避方法。

日本語処理を行う開発時などDockerfileで日本語ロケールの設定を行う場合の設定です。

せっかちな人のために

次の記述をglibcの更新処理(yum updateやyum reinstall glibc)より後方に記述します。
後方に記述しないと、glibcの更新によってlocaledefによるja_JP.UTF-8ロケールの追加がリセットされ、エラーが発生します。

RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

上記はCentOS7の場合です。Ubuntuの場合は次のサイトなどを参照すると良いかもしれません。
https://qiita.com/suin/items/856bf782d0d295352e51

本文

テスト環境

  • ホストOS: CentOS Linux release 7.4.1708 (Core)
  • Docker: Docker version 17.12.0-ce, build c97c6d6
  • コンテナOS: CentOS Linux release 7.4.1708 (Core)

ディストリビューションの設定コマンドは使えない

CentOS7のロケール設定コマンドである localectl はコンテナ上で実行できません。
systemctlなどと同様にエラーになります。

[user@container ~]# sudo localectl
Failed to create bus connection: No such file or directory

環境変数を直接設定する

Dockerfileでは環境変数を直接セットして日本語ロケールを設定するようです。
ところが、CentOS7の公式イメージでは設定できる既定ロケールが次の3つだけです。

[user@container ~]# locale -a
C
POSIX
en_US.utf8

このため、Dockerfileでは次のコマンドでロケールの追加を行う必要があります。
(この方法で作成するロケールをカスタムロケールというらしいです)

RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8

localedefコマンドの詳細については次のサイトなどを参照ください。
https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxa500/comlcdf.htm

上記で作成した日本語ロケールを次のコマンドで環境変数にセットします。

ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

これで日本語環境のコンテナを作成できます。

ロケールエラーが発生する場合の回避方法

上記までの方法でDockerfileを作成したところ、テスト用コンテナでは問題なかったのですが、
複数の設定を入れた実用のDockerfileで次のようなエラーが発生するようになりました。
RUNコマンドの実行時などに発生します。

(error)
/bin/sh: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
Failed to set locale, defaulting to C

作成されたコンテナで locale を確認すると LC_ALLなどの設定が落ちているようです。

[user@container ~]# locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

どうやら glibc関連のパッケージを更新すると、カスタムロケールが消えてしまうようです。
(なぜ、LANGなどの環境変数には値が残っているのか不思議ですが)
作成したja_JP.UTF-8が消えてしまったので、環境変数の内容と不整合が起きてエラーが発生しているようです。
例えばyumは実行時にLC_ALLの内容を確認しているようです。

回避策は
・ yum update などglibcを更新するようなタスクはlocaledefより先に実行する

**2018/7/10追記**
次の記事で解説されている方法で回避可能と思われます。
https://qiita.com/teruo-oshida/items/08cb84efc2b581b0a439
(コメントいただきありがとうございます。)

私の場合日本語設定に関する記述をDockerfileの比較的上の方に記載していたので、後方で実施していたyum updateでglibcが更新され、追加したロケールが消えていたようです。

参考

次のサイトを参考にしています
Ubuntuでの設定方法
https://qiita.com/suin/items/856bf782d0d295352e51

Ubuntu / CentOSでの設定方法
https://qiita.com/yuki2006/items/6cea8c352e38f047b52a#comment-8e863c71962008035d0d

glibcとロケールについて
(こちらではカスタムロケールを保存場所を指定して作成する回避策が紹介されています)
https://qiita.com/kaikusakari/items/9fa7fcab0bb07b5122be

localeの詳細
https://qiita.com/aosho235/items/58e2e7acd5c2ee3641ff

localedefコマンドの詳細
https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxa500/comlcdf.htm