Docker中运行Crontab的踩坑

@CoderMing 2018-09-07 06:51:25发表于 CoderMing/blog GitLinux/Docker踩坑

本人最近将服务器中的项目全转为Docker容器了。由于docker打包的特性(每次都要安装各类依赖),导致每次更新的时候都需要等待很久。
后面考虑到Linux下有crontab,是都可以在Docker中实现脚本自动运行呢?于是就有了以下的探索。
直接说要实现的功能吧:
项目是Node的,希望实现定期从远程仓库pull && build

思路

crontab我相信大家都会了,就是一个定时运行特定代码的工具。
对于这个需求,我们的大致思路是定时运行一个脚本。然后脚本的内容是对特定的仓库pull && build

踩过的坑

踩坑的过程说起来就太难受了= = 我们这里节约时间,直接说坑的内容吧:

CronTab不存在于Docker官方的Node镜像中

大家可以尝试一下,Docker官方的Node镜像(无论是不是slim版本)都是不带有CronTab的。具体我在Docker Hub上查找,发现Node的Docker底包是buildpack-deps:jessie,然后继续追溯下去,发现是debian的jessie版本(https://github.com/docker-library/buildpack-deps/blob/b0fc01aa5e3aed6820d8fed6f3301e0542fbeb36/jessie/curl/Dockerfile):

FROM debian:jessie

又经过查询,这个版本是非常“干净”的,这也就意味着Node的底包的确没有CronTab。
那我们就需要自己安装一个了。因为是Debian,所以我们用apt安装器:

RUN apt-get update && apt-get -y install cron

但这样还是不够的,因为CronTab只是被安装,还没启动。你可能会想在包构建的时候就直接启动server就可以了,但经过踩坑,这样做是不行的。你必须在CMD字段运行才会生效。具体原因也搜索了一下,这是Docker的基础知识: RUN字段运行的指令会在打包完成后被结束。 所以此处应该这样填写CMD字段:

CMD service cron start && 其他指令

CronTab运行的shell脚本无法正确执行,但手动执行却没问题 ---- 环境变量的问题

现在我们已经可以使用CronTab了,于是我正如之前想的一样,设置定时执行一个脚本。在脚本中执行pull && build操作。
但发现CronTab无法正确执行,但手动执行却没问题。后面经过检查和查资料,发现是环境变量的问题。具体请看 https://blog.csdn.net/frankcheng5143/article/details/78575176
正确的处理方法就是在shell脚本最前面添加这一段话:

source /etc/profile

当Git远程分支的协议为git:时,需要验证RSA指纹导致脚本无法顺利执行。

就如问题所说。因为如果使用git:协议而不是https时,系统会像ssh一样,要进行指纹验证。
经过查看,git 没有提供像apt-get-y选项这样的默认确认的参数。网上有一部分信息是说可以自动处理输入,但经过试验都不可行。
最后的解决方法是将git:协议替换为https协议:
Dockerfile:

RUN git remote remove origin \
    && git remote add origin https://github.com/coderming/resume.git

update.sh:

git pull -u origin master

最后的处理结果

直接po代码吧~
Dockerfile:

FROM node

WORKDIR /app
COPY . /app

ADD /script/crontab /etc/cron.d/cron
RUN chmod 0644 /etc/cron.d/cron

RUN apt-get update && apt-get -y install cron

RUN git remote remove origin \
    && git remote add origin https://github.com/coderming/resume.git

RUN chmod +x /app/script/update.sh

RUN npm config set registry "https://registry.npm.taobao.org/" \
    && npm install \
    && npm run build
    
EXPOSE 3000

CMD service cron start && node prod-serve.js

crontanb:

0 * * * * root /app/script/update.sh

update.sh:

#!/bin/bash
source /etc/profile

touch /update.log
cd /app
echo "`date`: 开始拉取更新" >> /uptate.log

git pull -u origin master
npm config set registry "https://registry.npm.taobao.org/"
npm install
npm run build

echo "`date`: 更新完成" >> /uptate.log