SVX日記
2021-08-12(Thu) dockerでcronを使わずに周期実行
諸君、私はdockerが好きだ。諸君、私はdockerが好きだ。諸君、私はdockerが大好きだ。KubernetesやOpenShiftも便利には違いないが、個人で使うにはアレは重すぎるものだ。では、どんなコンテナ管理を望むか? よろしい、ならばdocker-composeだ。
自分は長らく自宅サーバを運用しているが、過去記事によれば立ち上げたのは2002年の4月頃らしいから、もうすぐ20年というところ。当然、何度もサーバの移行を繰り返してきたが、この作業が面倒で仕方なかった。
昔はPCのアプリの導入も「実行ファイルをコピーするだけ」だったが、いつのまにか「インストーラ」なるものを使うのが普通になった。まぁ、構成ファイルが一定数以上になれば仕方ないのだが、それは「システムに永続的な変更をもたらすにも関わらず、何をしでかすかを知りえないプログラム」であるから、いまだ実行するには抵抗がある。
Linuxの場合、RPMを使う限り安心して導入できるが、データや設定の引き継ぎや、バージョンで仕様に差異があるなど、どうしても細々とした作業が必要となってしまう。長らくどうにかならないものかと思っていたが、ある日、そんな解決方法があったのかと目からウロコが落ちた。それがdockerだ。
データや設定を分離し、OS環境とアプリと構築手順をまとめてカートリッジ化してしまう。一度、そうしてしまえば、docker/docker-composeが使える環境でありさえすれば、どのカートリッジだろうが、ほぼ共通の僅かなコマンドだけでサービスが起動できてしまう。想像もできなかった解決方法だ。しかし、欲しかったのはまさにこれなのだ。
そして、意外と楽しいのが、Dockerfileとdocker-compose.ymlを書く作業だ。できるだけ無駄なく、美しく、構築手順を詰めていく。つまり、最低限のコマンド以外の全てを削ぎ落として箱詰めしてカートリッジ化する……おやおや、おやおやおやおや、なんと……なんと素晴らしい……。
# Dockerfile 中の設定スクリプトを抽出するスクリプトを出力、実行
COPY Dockerfile .
RUN echo $'\
cat Dockerfile | sed -n \'/^##__BEGIN0/,/^##__END0/p\' | sed \'s/^#//\' > startup.sh\n\
' > extract.sh && bash extract.sh
# docker-compose up の最後に実行される設定スクリプト
##__BEGIN0__startup.sh__
#
# # easy cron
# now=`date +%s`
# target0=$((now - now % ${CYCLE0:=86400} + ${SCHED0:=$(( 5 * 60 + 4 * 3600 - 32400))})) # day
# while [ $target0 -lt $now ]; do
# ((target0 += CYCLE0))
# done
# target1=$((now - now % ${CYCLE1:=604800} + ${SCHED1:=$(( 5 * 60 + 2 * 3600 + 0 * 86400 - 378000))})) # week
# while [ $target1 -lt $now ]; do
# ((target1 += CYCLE1))
# done
# target2=$((now - now % ${CYCLE2:=2419200} + ${SCHED2:=$(( 5 * 60 + 3 * 3600 + 0 * 86400 - 378000))})) # 4weeks
# while [ $target2 -lt $now ]; do
# ((target2 += CYCLE2))
# done
#
# s=S
# while true; do
# pgrep -f httpd > /dev/null
# if [ $? -ne 0 ]; then
# echo "`date`: ${s}tart httpd."
# /usr/sbin/httpd
# fi
# s=Res
#
# # easy cron
# if [ `date +%s` -ge $target0 ]; then
# ((target0 += CYCLE0))
# echo "`date`: Job easy cron 0 started."
# (cd /var/lib/pv/hyperestraier; find documents/ -type f -name "*.$FILE_TYPE" | estcmd gather -cl $GATHER_OPTS -cm casket - | grep -v ' passed ')
# fi
# if [ `date +%s` -ge $target1 ]; then
# ((target1 += CYCLE1))
# echo "`date`: Job easy cron 1 started."
# (cd /var/lib/pv/hyperestraier; estcmd purge -cl casket | grep -v ' passed')
# fi
# if [ `date +%s` -ge $target2 ]; then
# ((target2 += CYCLE2))
# echo "`date`: Job easy cron 2 started."
# (cd /var/lib/pv/hyperestraier; estcmd optimize casket)
# fi
# sleep 5
# done
#
## target0=$((now - now % ${CYCLE0:=3600} + ${SCHED0:=$(( 0 * 60))})) # hour
## target0=$((now - now % ${CYCLE0:=86400} + ${SCHED0:=$(( 0 * 60 + 0 * 3600 - 32400))})) # day
## target0=$((now - now % ${CYCLE0:=604800} + ${SCHED0:=$(( 0 * 60 + 0 * 3600 + 0 * 86400 - 378000))})) # week
## target0=$((now - now % ${CYCLE0:=2419200} + ${SCHED0:=$(( 0 * 60 + 0 * 3600 + 0 * 86400 - 378000))})) # 4weeks
#
##__END0__startup.sh__
ENTRYPOINT ["bash", "startup.sh"]