Help us understand the problem. What is going on with this article?

Docker+Laravelでタスクスケジューラ

目的

通常サーバのタスクスケジューラはcronにて行うが、

  • 少し面倒であること
  • Laravelにタスクスケジューラの機能があること

から、画面を作成して画面経由でタスクスケジュール設定を行えるものを作成してみる。

前提

下記の環境で実装した。

  • PHP7.1.x
  • Laravel6.x+AdminLTE3
  • PostgreSQL11.4
  • Docker phpfpm

サンプル仕様

サーバのタスクスケジュールのため、画面操作するためにログインが必要とした。

タスク自体は別途実装済みであるとして、タスク名と実行スケジュールを設定する画面を
用意する。

タスクの実行はLaravelにタスクスケジューラをcron経由で実行するものとして、タスクスケジューラの設定を先の画面で設定したものを反映させるものとする。

タスクの実装

詳細は省略するが、タスクの雛形をartisanで作成できる。

% php artisan make:command タスク名

とりあえず、タスクが動いたか確認したいため、下記のタスクを実装した。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class Shout extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:shout';

〜省略〜

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Log::info("start shout!!");
    }
}

見ての通り、実行されたらログが出力されるだけのタスクである。

モデル定義

定義するモデルはScrapingCommandである。
migrateの内容を下記に示す。

 ?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateScrapingCommandsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('scraping_commands', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string("name",200);
            $table->string("cmd",200);
            $table->integer("cron1")->nullable();
            $table->integer("cron2")->nullable();
            $table->integer("cron3")->nullable();
            $table->integer("cron4")->nullable();
            $table->integer("cron5")->nullable();
            $table->integer("flg")->default(0);
            $table->softDeletes();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('scraping_commands');
    }
}

画面実装

ログイン画面

AdminLTEのものをそのまま使用した。

タスク一覧画面

登録されているタスクの一覧表示している。

タスクスケジュールはcronと同じ形式である。スケジュールとは別に有効/無効の設定が可能である。
img_tsk2.png

タスク設定画面

タスクの設定を行う。コマンド名はartisanで使用するコマンド名(\$signatureに設定しているもの)を設定する。

設定内容はScrapingCommandモデルに保存される。
img_tsk3.png

Laravel側のスケジュール定義

LaravelのタスクスケジュールはApp\Console\Kernelのscheduleメソッドで定義するため、
同メソッドを下記のように修正した。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Support\Facades\Log;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\ScrapingCommand;

class Kernel extends ConsoleKernel
{
〜省略〜
    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $lst = ScrapingCommand::where("flg",1)->get();
        foreach($lst as $rec) {
            Log::info("cmd:".$rec->cmd);
            Log::info("cron:".$rec->cronStr());
            $schedule->command($rec->cmd)->cron($rec->cronStr());
        }
    }
〜省略〜
}

Cron側の設定

Cron側はLaravelのタスクスケジューラを実行するだけなので、

* * * * * /usr/local/bin/php /svr/app/artisan schedule:run >> /var/log/cron.log 2>&1

(注)/svr/appはLaravelをインストールしたディレクトリ  

本来はcrontab -e で上記のファイルを作成することになるが、今回はDockerなので、
rootファイルとして作成しておく。

以上で、要望を実装済みであるが、今回はDockerで実装したため、コンテナ上でcronのインストールが必要になる。

そこで、cronのインストールはDockerイメージ作成時に行う。よってDockerファイルは

FROM php:fpm

# For composer
RUN apt-get update \
    && apt-get install -y gcc make zlib1g-dev libzip-dev libpng-dev unzip libmcrypt-dev libjpeg-dev libfreetype6-dev \
    && docker-php-ext-install zip \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include \
    && docker-php-ext-install -j$(nproc) gd

# Install composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
  && php composer-setup.php \
  && php -r "unlink('composer-setup.php');" \
  && mv composer.phar /usr/local/bin/composer

# Set composer environment
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin

# Install laravel installer
RUN composer global require "laravel/installer"

# PHP's DB setting
RUN apt-get update \
    && apt-get install -y libpq-dev \
    && docker-php-ext-install pdo_mysql pdo_pgsql

# Install Node.js
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - \
    && apt-get update \
    && apt-get install -y nodejs

RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN apt-get install -y cron

RUN mkdir /debugbar
RUN chmod go+w /debugbar
WORKDIR /svr

とした。

次にcrontabの登録とcron起動が必要になるが、今回は手動で行うものとした。
よって、上記で作成したイメージからコンテナを起動して、コンテナ上で

% cp root /var/spool/cron/crontab
% service cron start

を実行する。
rootファイルはあらかじめ/svrにコピーしておくこと。

考察

cronの設定って結構面倒なものである。何よりわざわざサーバにログインして作業しないと行けないのである。
この仕組みだと、画面で設定するだけなので大分楽である。タスクはLaravel上で動くため、
DB接続とかログ出力とかの考慮が必要なくなる。

問題点は

  • crontabの設定とcronの起動をコンテナ起動後手動で行わなければならない。
    Dockerイメージでcronの起動もできるらしいが、今回は割愛した
  • 5分毎等のスケジュールに対応できてない
    これは実装の問題であるが。。。

サンプルで実装したプロジェクトはGitHubにアップしたので、必要であれば参照していただきたい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした