例えば、Supervisorを使ってQueueに入ったJobを処理するWorkerサーバーを構築したり、CRON等で定期実行処理を行うSchedulerサーバーを構築したりする場合がよくあると思います。
本記事ではECS上でSupervisorを利用してLaravelのWorkerやSchedulerを構築する方法を解説します。
それぞれartisanコマンドの queue:work や schedule:work をSupervisorによって実行&監視するイメージになります。
Supervisorの設定ファイルを作成
さっそくSupervisorの設定ファイルを解説します。
下記ファイルを 「/etc/supervisor/conf.d」配下に設置することで、Supervisorが起動した際に自動的に必要なプロセスを起動してくれます。
[program:scheduler]
command=php /var/www/html/artisan schedule:work
# プロセス名を指定します("scheduler_00" のようになります)
# また "supervisorctl status" コマンドで実行中のプロセスを確認することができます
process_name=%(program_name)s_%(process_num)02d
# 並列で立ち上げるプロセス数を指定します
# Schedulerなので、並列実行する必要がないため1つにしています
numprocs=1
# trueに設定するとsupervisordが起動した際に自動でプロセスが開始されます
autostart=true
# プロセスが停止した際に自動で再開されます
autorestart=true
# このプロセスの実行ユーザーを指定します
# php-fpmでの実行のためwww-dataユーザを指定しています
user=www-data
# ログ出力の設定(詳しくは後述)
stdout_logfile=/proc/1/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/proc/1/fd/2
stderr_logfile_maxbytes=0
# プロセス が Supervisord に SIGCHLD を返すまで待機する秒数を指定します
# 詳しくは後述
stopwaitsecs=3600
# ここからはWorkerの設定です
[program:worker]
command=php /var/www/html/artisan queue:work
process_name=%(program_name)s_%(process_num)02d
numprocs=5
autostart=true
autorestart=true
user=www-data
stdout_logfile=/proc/1/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/proc/1/fd/2
stderr_logfile_maxbytes=0
stopwaitsecs=3600stdout_logfile=/proc/1/fd/1 について
`docker logs <container>` コマンドで特定コンテナのログを出力することができますが、その出力対象はメインプロセス(PID1)の標準出力のみとなっており、stdout_logfile設定ではPID1の標準出力である /proc/1/fd/1 を指定しています(標準エラー出力は/proc/1/fd/2)。またECSのログドライバーである awslogs は docker logsの出力を受け取ってCloudWatchにログを転送しています。
ここでいうメインプロセス(PID1)とは、CMDによって起動されるプロセスのことを指します。
ちなみに/dev/stdout(デバイスの標準出力)は現在のプロセスの標準出力であり、Dockerは拾いませんし、awslogsも拾いません。
stopwaitsecs=3600 について
サーバー再起動などでプロセスに対して停止信号(SIGTERM)が送信されます、この信号を受け取ったプロセスは現在実行している処理が完了したら正常終了(SIGCHLD)としプロセスを停止します。このとき中途半端にプロセスが無理やりKILLされてしまうとデータに不整合が出たりして危険です、そのためこの設定で正常終了を待つ秒数を指定します。
Dockerfileを作成
Supervisorの設定ファイルができたので、あとはDockerfileを作成します。
Laravelのセットアップをして、php-fpmとSupervisorの起動をするだけです。
以下はDockerfileの例です。
FROM php:8.0-fpm
WORKDIR /var/www/html
# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
build-essential \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
unzip \
curl \
sudo \
libzip-dev && \
docker-php-ext-install zip && \
docker-php-ext-install mysqli && \
docker-php-ext-enable mysqli && \
docker-php-ext-install pdo pdo_mysql pcntl && \
apt-get -y --purge remove build-essential && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
mkdir -p /var/www/html && \
chown www-data:www-data /var/www/html
RUN pecl install redis && docker-php-ext-enable redis
# PHPの設定ファイルを追加
ADD .ci/docker/php.ini /usr/local/etc/php/conf.d/local.ini
ADD .ci/docker/www.conf /usr/local/etc/php-fpm.d/www.conf
# Supervisorをインストール&設定
RUN docker-php-ext-install pcntl && \
apt-get update && \
apt-get install -y supervisor
COPY .ci/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# 後ほど解説
COPY .ci/docker/startup.sh /startup.sh
RUN chmod +x /startup.sh
# LaravelソースコードをDockerコンテナ内にコピー
COPY --chown=www-data:www-data {Laravelソースコードの場所} /var/www/html
# 必要なPHPライブラリをインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN sudo -u www-data composer install \
--no-interaction \
--prefer-dist \
--no-dev \
--optimize-autoloader
EXPOSE 9000
CMD ["/bin/bash","-c","/startup.sh"]「startup.sh」について、コンテナが起動したときの実行ファイルとして「CMD」に設定しています
以下はstartup.shの内容です。
#! /bin/bash
# このスクリプト内でエラーがあった場合に即座に処理が失敗するようにする
set -e
# Laravelのマイグレーション実行
cd /var/www/html/
sudo -E -u www-data php artisan migrate --force
# Supervisorを起動、設定ファイルに従って必要なプロセスが起動します。
supervisord -c /etc/supervisor/supervisord.conf
php-fpmこのDockerfileをCodePipelineまたはGitHub Actionsでビルドし、ECRにプッシュし利用します。



