cronを理解できてなくてハマった。/etc/crontabではなく、/etc/cron.d/**を使おう

2018年1月8日

サーバー テクノロジー トラブル

Linuxにおける自動化処理で定時にプログラムを実行してくれるCRONhはとても便利で、頼もしい機能です。 普段はcrontabに書き込んで、shellプログラムを起動させていたんですが、とある複数のサービスを扱っているサーバーを使った時のことです。 「/etc/crontab」に追記して使っていたのでは、1つのサービスで何かしらの不具合が発生した時に、他のサービスに影響が発生する可能性があると指摘され、 「/etc/cron.d/」以下にプロジェクト毎のファイルで管理する方法でやってみることにしました。 その際に、何故かプログラムが実行されない事象にハマったので、対応完了までの流れを記述しておきます。

今回の構成

やりたかったことは、nodejsを使ってクローリングするプログラムを定期的に行なうというcrontabに書かれていた事を/etc/cron.d/projectというファイルを作って下記の様に記述しただけです。 */10 9-21 * * * web sh /var/www/html/crawl.sh >/dev/null 2>&1 crawl.shの中身は以下のようなシンプルなshellが書かれています。 #!/bin/bash DIR=`dirname $0` echo $DIR cd $DIR node crawl.js クロールする実プログラムは「crawl.js」に書かれているのでそれを実行するというシンプルな構成なのですが、これが上手く起動しないんです。

不具合を探せ! #1 「フォルダ権限」

crontabに書かれていた時は普通に動作していて、cron.d/projectに移した時に動かなくなったので、クロールプログラムの不具合では無いことは明確です。 という事は、cron.dを利用する時のお作法があるという事なんですね。 とりあえず、cronが正常に実行されているかどうか調べてみます。 cronの実行は、/etc/log/cronを見れば毎回書き込まれているはずです。 $ tail /var/log/cron Jan 4 16:00:01 ik1-304-12258 CROND[7298]: (CRON) ERROR chdir failed (/home/web): Permission denied まずは、パーミッションエラーが出ています。ここでピントきたのは、この処理を行なう直前に、webというアカウントを作って、それまでrootで行っていた実行権限をユーザーに引き継いでいました。 ここで怒られているのは、そのwebのhomeフォルダがアクセス権限を持っていないとの事だったので、apacheの権限を付与して、エラー解消が確認できた。 $ chown httpd:httpd -R /home/web でも、これでもまだクロール処理は実行されません。

原因を探せ! #2 「エラーメッセージを取得」

Jan 4 17:40:01 ik1-304-12258 CROND[7747]: (root) CMD (sh /var/www/html/crawl.sh >/dev/null 2>&1) /var/log/cronで得られる情報は、cronが実行されてプログラムが起動されたかどうかという所までなので、コマンド実行された際にエラーログが出ている内容を確認してみます。 今の時点では、「>/dev/null 2>&1」としているので、その後ゴミにしかならない実行ログは全て闇に葬っています。 これを下記のように書き換えることで、エラーログを見ることができます。 */10 9-21 * * * web sh /var/www/html/crawl.sh 2>> /var/www/html/error.log これで実行されたタイミングで「error.log」を見てみましょう。 一々書き換わったことを確認するのが面倒くさいので下記監視コマンドでターミナルを見ているだけで実行 watch -n 1 "cat error.log" 1秒毎にerror.logの中身が書き換わって画面表示されます。 すると、以下のようなメッセージが表示されていました。 /var/www/html/crawl.sh: line 6: node: command not found あれ?想定外のメッセージ・・・なんだこりゃ・・・

原因を探せ! #3 「環境PATH」

「node」コマンドが無い・・・ 普通に、nodeコマンドはパスが通っているのに、cronの時だけ通っていない・・・ crontabの時は通っていたのに、cron.dを利用すると通らなくなった・・・ そこで、cron.dフォルダに格納されている他のファイルを確認してみると、 $ vi /etc/cron.d/0hourly SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ 20 * * * * root run-parts /etc/cron.hourly なんと、PATHがセットされていますね。 これが無いので、nodeにPATHが通ってなかったんですね!!!

解決

$ which node /usr/local/bin/node nodeのパスを確認すると、「/usr/local/bin」だったので、PATHにこれも加えて以下のように追記しました。 PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin */10 9-21 * * * web sh /var/www/html/crawl.sh >/dev/null 2>&1 これでようやくクロール処理が動作することが確認できました。

最後に

今回は、cronの使い方を中途半端にしか理解できていなかったが為に数時間を要してしましました。 でも、仕様もわかり、ステップアップできたという事にしておきましょう。 ちなみに、今回のcron記述の「*/10 9-21 * * *」の箇所は、9時から21時台の間10分事にプログラムを実行するという記述です。 10分毎にWEBの情報を取ってきて、必要な情報を得られるなんて、なんて便利なんでしょう。 サーバー&クロールで、かなりの作業を自動化できますね。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。