容器:crontab UNICODEENCODEERROR: ‘ASCII’ CODEC CAN’T ENCODE CHARACTERS

背景:开发需要pod中执行crontab脚本

思路

  • 修改Dockerfile,安装crond、vim(crontab需要编辑命令,vim,nano都行,不装好像会报错)、procps(主要用到ps命令看下进程起来没)包

  • 容器中的用户是root,crontab -e实际上创建了/var/spool/cron/root文件,文件中是脚本,所以这部分由开发完成,开发编辑root文件就行了,后续加载到容器中

  • 修改k8s deployment的yaml文件,再加上一个容器,使用的业务镜像,用来跑crontab,其实也可以不用再添加一个镜像,可以在业务容器启动后通过lifecycle中postStart执行cron命令,也可以跑crontab,但根据一个容器一个进程的原则以及开发需要看到执行脚本输出的日志,还是选择添加一个新的容器

实现

Dockerfile

一开始想的是把root文件直接丢到/var/spool/cron/下,但是crontab根本不执行,只能crontab /tmp/root才能加载脚本并正常执行

FROM xxx

COPY requirements.txt .
COPY root /tmp/root

RUN  apt-get update && apt-get install cron vim procps libmariadb-dev-compat libmariadb-dev gcc -y;pip install --no-cache-dir \
        -i https://pypi:9LmOBdpxKQ3B@pypi.weike.fm/ \
        -r requirements.txt \
    && rm requirements.txt

ADD . /app
WORKDIR /app

deployment.yaml

省略一部分,cron -f是前台运行crontab的服务端,如果你想要在业务容器中运行,只能是cron运行,因为你的服务命令就是前台执行的

containers:
containers:
- image: xxx
  name: cron
  lifecycle: # 启动后加载crontab脚本
    postStart:
      exec:
        command:
        - crontab
        - /tmp/root 
  volumeMounts:
  - mountPath: /app/superconf.json
    name: superconf
    readOnly: true
    subPath: superconf.json
  command:
  - cron
  - -f
  • 后续自己写了个简单的脚本测试,发现没有问题

问题出现

当执行完crontab脚本时,会重定向到文件中,从文件中得知报UnicodeEncodeError: 'ascii' codec can't encode characters in position 7-8: ordinal not in range(128) (类似)的错误,但是进入容器中手动执行确实可以正常执行的

出现这个问题,查了很多资料,在这总结下

    1. 加上python变量PYTHONIOENCODING=utf-8,举个例子:*/1 * * * * PYTHONIOENCODING=utf-8 python test.py。很遗憾没用
    1. 在python文件第一行加上# encoding=utf-8 或者下图那种,很遗憾,这是python2的玩法,python3默认就是utf-8编码
import sys
reload(sys) 
sys.setdefaultencoding('utf-8')
    1. crontab -e,在第一行加上LANG=zh_CN.UTF-8,很遗憾也没用
    1. source 变量文件,比如:*/1 * * * * source file && python test.py ,很遗憾没用
  • 网上的答案大概就是上面几种,我都测试了,但依然会报错,再一番测试折磨后,突然想既然终端可以正常运行脚本,那肯定是有依赖的变量,最后echo $LANG,得到C.UTF-8(以自己的环境变量值为准)。最后加上这个环境变量后脚本正常执行 */1 * * * * LANG=C.UTF-8 python test.py。