👋

LaravelにDockerファイルでcronを導入して定期的にメール送信する方法

2021/01/02に公開

dockerでcronを導入する方法が日本語では見つからなかったので書きました。

dockerファイルの書き方が全くわからない人は難しいです。

以下の例ではdocker内部ではprojectフォルダにソースを入れています。

あとdocker-composeでマウントする場合はCOPY . /project/が不要、 最後のRUN 以降で、chmod 0644 /etc/cron.d/cronとtouch /var/log/cron.log以外は不要です。
通常のLaravelで立ち上げるdockerファイルとは分けましょう。

app/docker/cron/dockerfile

FROM php:7-fpm

ENV DEBIAN_FRONTEND noninteractive

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get -y install git cron libicu-dev libonig-dev libzip-dev unzip &&\
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* &&\
    docker-php-ext-install pdo_mysql &&\
    composer config -g process-timeout 3600 && \
    mkdir -p /project
COPY . /project/
COPY ./docker/cron/php.ini /usr/local/etc/php/php.ini
COPY ./docker/cron/root /etc/cron.d/cron

WORKDIR /project

RUN composer install &&\
    chmod -R a+w storage/ bootstrap/cache &&\
    chmod 0644 /etc/cron.d/cron &&\
    touch /var/log/cron.log &&\
    php artisan cache:clear &&\
    php artisan config:clear &&\
    php artisan route:clear

CMD cron -f

project/docker/cron/root

* * * * * root /usr/local/bin/php -q -f /project/artisan schedule:run --no-ansi >> /dev/null 2>&1

project/app/Console/Kernel.phpで、

    protected function schedule(Schedule $schedule)
    {
        $schedule->command('email:send')->hourly()->onOneServer();
    }

コマンドは公式を参照しましょう。
https://readouble.com/laravel/7.x/ja/scheduling.html

php artisan make:command SendMailTest

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\User;
use App\Mail\SendMail;
use Illuminate\Support\Facades\Mail;
use Carbon\Carbon;

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'メールを定期的に配信する';


    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
	// 対象者を絞ったり
        $user = User::find(対象者);

	// 内容をDBから取り出しておいたり、
	$contents = ~~~
	
	Mail::to($user)->send(new SendMail($contents));
    }
}

php artisan make:mail SendMail

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class SendMail extends Mailable
{
    use Queueable, SerializesModels;

    // 引数で受け取る変数
    protected $user;
    protected $contents;

    // コンストラクタ設定
    public function __construct($user,$contents)
    {
        // 引数で受け取ったデータを変数にセット
       $this->user = $user;
       $this->contents = $contents;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this
	->subject('メールのタイトル')
	->view('emails.content')
	->with([
	    'user' => $this->user,
	    'contents' => $this->contents,
	]);
    }
}

resources/views/emailsディレクトリを作成し、content.blade.phpを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <style type="text/css">
 <!-- 何かしらの内容 -->
    </style>
</head>
<body>
 <!-- 何かしらの内容 -->
</body>
</html>

内容面は適宜カスタマイズしてください。

Discussion