SYSZUX
首发于SYSZUX
Docker容器中添加中文字符的支持

Docker容器中添加中文字符的支持

背景

最近在新制作的Docker容器中运行python3 web服务(Django框架)的时候,如果要print的东西含有中文字符的时候,会报如下错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position xx-xx: ordinal not in range(128)


如果不含中文字符,那么代码会正常运行。很明显,这是缺少了中文字符支持。在docker环境中使用python3打印中文字符的时候报这个错误。这是因为当前系统(或者docker容器环境)没有安装中文字符支持。


解决方案

1 使用locale -a命令先查看下当前系统(当前容器)支持的字符集

root@gemfield:~# locale -a
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_COLLATE to default locale: No such file or directory
C
C.UTF-8
POSIX


2 安装locales 包

root@gemfield:~# apt-get update
root@gemfield:~# apt-get install -y locales
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  locales
0 upgraded, 1 newly installed, 0 to remove and 16 not upgraded.
Need to get 3220 kB of archives.
After this operation, 14.0 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 locales all 2.23-0ubuntu9 [3220 kB]
Fetched 3220 kB in 3s (956 kB/s)   
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = (unset),
        LC_ALL = (unset),
        LANG = "zh_CN.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package locales.
(Reading database ... 14628 files and directories currently installed.)
Preparing to unpack .../locales_2.23-0ubuntu9_all.deb ...
Unpacking locales (2.23-0ubuntu9) ...
Setting up locales (2.23-0ubuntu9) ...
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)
debconf: falling back to frontend: Readline
Generating locales (this might take a while)...
Generation complete.


3 使用locale-gen命令生成中文本地支持

root@gemfield:~# locale-gen zh_CN
Generating locales (this might take a while)...
  zh_CN.GB2312... done
Generation complete.
root@gemfield:~# locale-gen zh_CN.utf8
Generating locales (this might take a while)...
  zh_CN.UTF-8... done
Generation complete.


4 现在来看看,中文支持确实已经添加

#看看当前启用的本地支持
root@gemfield:~# locale -a
C
C.UTF-8
POSIX
zh_CN
zh_CN.gb2312
zh_CN.utf8


5 设置当前默认字符集

export LANG=zh_CN.UTF-8

export LC_ALL=zh_CN.UTF-8

export LANGUAGE=zh_CN.UTF-8

root@gemfield:~# export LANG=zh_CN.UTF-8
root@gemfield:~# export LC_ALL=zh_CN.UTF-8
root@gemfield:~# export LANGUAGE=zh_CN.UTF-8
#现在来看看当前的字符集
root@gemfield:~# locale
LANG=zh_CN.UTF-8
LANGUAGE=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=zh_CN.UTF-8


持久化

很明显,上面的设置只是更改了当前bash会话中的默认字符集,如何改变Docker容器启动后默认的字符集呢?

那要看是在哪个层面上了:容器层面还是镜像层面?

容器(container)层面,Gemfield使用 update-locale命令(这个命令会更新/etc/default/locale文件)来全局设置系统的默认字符集,也就是只要这个容器存在(不管是stop再start还是restart),这个设置都会在容器层面生效的:

root@gemfield:/# update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8
root@gemfield:/# cat /etc/default/locale
#  File generated by update-locale
LANGUAGE=zh_CN.UTF-8
LANG=zh_CN.UTF-8
LC_ALL=zh_CN.UTF-8


但是,如果从image重新启动一个新的容器,那肯定是不会有这个设置的。因为image并没有这样的设置,所以在镜像(Image)层面,正确的做法是在Dockerfile中来进行设置:

# Set the locale
RUN locale-gen zh_CN.UTF-8  
ENV LANG zh_CN.UTF-8
ENV LANGUAGE zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8


庆祝

事实上Gemfield并没有进行Docker容器级别的全局设置,而只是通过supervisor的配置文件将LANG环境变量传递给了python程序。日志里的中文字符已经在哗哗流淌了。

#/etc/supervisor/conf.d/supervisor.conf
[program:django]
environment=LANG=zh_CN.UTF-8
command=uwsgi --chdir /home/gemfield/celeryproducer/ --http-workers 10 --lazy --enable-threads --socket 127.0.0.1:4242 --logto /home/gemfield/celeryproducer/logs/uwsgi.log --module celeryproducer.wsgi

编辑于 2017-11-15

文章被以下专栏收录