このサーバで使用しているDynamic DNSはMyDNS.JPなのだが、当然QNAPは海外のメージャーなDDNSしか対応していない=MyDNS.JPには対応していないので、DDNSのIPアドレスの更新を自前で行う必要がある。
そこでDDNSのIPアドレス更新コマンドをcrondで定期的に実行することになるのだが、当初QNAPネイティブのcrondを使っていたのだが、QNAPのファームウェアを更新してからQNAPネイティブなcrondでのコマンド実行が正常に動作しなくなった。
QNAPネイティブで動かしている限りQNAPに開発者登録をして常に最新情報をウォッチし続けなければ今回のような仕様変更に追随できなくなる。それどころか今回のようにファームウェアのアップデート時のQNAP再起動に伴うアプリの停止&起動が行われた瞬間にアプリが動かなくなるのが怖い。
そこでDDNSの更新コマンドをContainer Station(docker)上でcrondを動かす方向でQPKGを再作成するのだが…
どうせならcrondの実行計画は固定にしないでQNAPのWebUI上で変更できる汎用アプリにしたいと思ったので、docker上で動くcrondにホスト側の設定ファイルを読み込ませようと思ってネット上で「docker + crond」情報を検索するがヒットするのはDockerfileで「RUN echo 〜 >crontabs」か「COPY file crontabs」を記述する固定方式ばかり。
しかもQNAPではQPKGアプリをインストールした時のユーザーでホスト側のファイルオーナーが設定されてしまうが、docker内はrootで動いてて。crond固有の制限事項(crontabsファイルのオーナーやアクセス権限などの制限事項)の影響もあって、ホスト側のcrontabsファイルを直接docker内のcrondの設定ファイルにmountする方法では正常に動作しないことも考えられる。
そこで考えたのが、dockerのENTRYPOINTで指定・実行するシェルスクリプト内でcrontabコマンドをを使って設定ファイルを読み込ませることに。そして完成したのが以下のようなDockerfileとdocker-entrypoint.sh。
Dockerfile
FROM alpine:latest
RUN apk add --no-cache tzdata
COPY ./docker-entrypoint.sh /
RUN chmod 755 /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]
CMD [ "crond", "-f" ]
docker-entrypoint.sh
#!/bin/sh
set -e
# Update crontabs settings
CRONTABS="/root/crontabs"
if [ -f ${CRONTABS} ]; then
crontab ${CRONTABS}
fi
exec "$@"
あとは「docker build -t crond:latest .」って感じでビルドして、「docker run -d -v ./crontabs:/root/crontabs crond」って感じで実行するだけ。更新もホスト側でcrontabsファイルを編集して「docker restart crond」するだけ。