怎样在 docker 中执行定时 Laravel 定时任务和消息队列

怎样在 docker 中执行定时 Laravel 定时任务和消息队列

本文编写时间:2023-08-12

需求

1、在正式服务器中使用 docker 容器来执行 php 代码
2、需要跑关于 php 的定时任务
3、其他服务比如 nginx,mysql 在哪里执行无关紧要,既可以放入其他 docker 容器,也可以放入宿主机。
4、代码是放宿主机的,不在镜像内。也就是,使用数据卷的代码。
5、最好还能跑消息队列,另起一个容器。

实现方案。

1、有一个镜像得包含 php
2、使用 docker-compose 编排容器。
3、同一个镜像提供一个 php-fpm 服务,且又提供一个 crond 服务,且又提供队列服务。
4、我为了省事,都用 centos 镜像打底,想轻便可以用专门的 php 官方镜像。

文件结构

/root/docker-image 文件夹
使用 tree 命令

.
|-- docker-compose.yml 自己写。
|-- logs
|   `-- php82
|       |-- fpm.slow.log 该文件是自动创建的,无视
|       `-- php.error.log 该文件是自动创建的,无视
`-- services
    `-- php82
        |-- crontab 自己写。
        |-- Dockerfile 自己写。
        |-- php-fpm.conf 自己写。官网抄,改。
        |-- myqueu.ini 自己写。官网抄,改。
        `-- php.ini 自己写。官网抄

php 的 Dockerfile

FROM centos:7.9.2009

ENV TZ Asia/Shanghai

WORKDIR /www

RUN yum -y install epel-release 

RUN yum makecache \
    && yum repolist \
    && yum install -y https://mirrors.aliyun.com/remi/enterprise/remi-release-7.rpm \
    && yum makecache \
    && yum repolist \
    && yum -y install yum-utils \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime  

RUN yum-config-manager --enable remi-php82 \
    && yum install -y php82 php82-php-devel  php82-php-fpm  php82-php-mbstring php82-php-memcache php82-php-memcached php82-php-redis  php82-php-mysqlnd  php82-php-pdo  php82-php-bcmath php82-php-xml php82-php-gd php82-php-gmp php82-php-igbinary php82-php-imagick   php82-php-mcrypt  php82-php-pdo_mysql php82-php-posix php82-php-simplexml  php82-php-opcache php82-php-xsl php82-php-xmlwriter php82-php-xmlreader php82-php-swoole php82-php-zip php82-php-phalcon  php82-php-yaml php82-php-yar php82-php-yaf php82-php-uuid php82-php-sodium  \
    && systemctl enable php82-php-fpm \
    && yum install -y  git wget vim redis zip unzip p7zip rsync crontabs supervisor net-tools python3 \
    && groupadd www -g 1000 \
    && useradd -u 1000 -g 1000 www 


RUN ln -s /usr/bin/php82 /usr/bin/php
CMD "/usr/sbin/init"

这里说明一下 www 和 1000,需要和 宿主机的 nginx 的用户保持一致,且 uid 和 nginx 的uid保持一致。比较重要。

docker-compose.yml 内容。

version: "3"
services:

  php82:
    build:
      context: ./services/php82
      args:
        TZ: Asia/Shanghai
    container_name: php82
    expose:
      - 9082
    ports:
      - "9082:9082"
    volumes:
      - /www/wwwroot:/www/wwwroot:rw
      - ./services/php82/php.ini:/etc/opt/remi/php82/php.ini:ro
      - ./services/php82/php-fpm.conf:/etc/opt/remi/php82/php-fpm.conf:rw
      - ./logs/php82:/var/log/php
    restart: always
    cap_add:
      - ALL
    command: ["/opt/remi/php82/root/usr/sbin/php-fpm", "--nodaemonize",  "--allow-to-run-as-root" ]
    networks:
      - default

  mycrond:
    build:
      context: ./services/php82
      args:
        TZ: Asia/Shanghai
    container_name: mycrond
    volumes:
      - /www/wwwroot:/www/wwwroot:rw
      - ./services/php82/php.ini:/etc/opt/remi/php82/php.ini:ro
      - ./services/php82/php-fpm.conf:/etc/opt/remi/php82/php-fpm.conf:rw
      - ./logs/php82:/var/log/php
      - ./services/php82/crontab:/etc/crontab:rw
    restart: always
    command: ["/usr/sbin/crond", "-n" ]
    networks:
      - default

  myqueue:
    build:
      context: ./services/php82
      args:
        TZ: Asia/Shanghai
    container_name: myqueue
    volumes:
      - /www/wwwroot:/www/wwwroot:rw
      - ./services/php82/php.ini:/etc/opt/remi/php82/php.ini:ro
      - ./services/php82/php-fpm.conf:/etc/opt/remi/php82/php-fpm.conf:rw
      - ./logs/php82:/var/log/php
      - ./services/php82/myqueue.ini:/etc/supervisord.d/myqueue.ini:rw
    restart: always
    command: ["/usr/bin/supervisord", "-n" ]
    networks:
      - default

networks:
  default:
    driver: bridge
    ipam:
      driver: default
  • 说明,mycrond 容器多了一个 crond 文件映射。这样,就只有 mycrond 容器才可能有定时任务,其他容器一定没有,可靠又方便。
  • 另外,只有 myqueue 容器有消息队列的配置,其余容器都没有。也非常安全。

crontab 内容。

这其实是容器在执行的。不是宿主机执行。
注意user www。

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
* * * * * www  cd /www/wwwroot/laravel项目文件夹 && php82 artisan schedule:run >> /dev/null 2>&1

myqueue.ini

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php82 /www/wwwroot/my_project_folder/artisan queue:work --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www
numprocs=1  ## 这是只跑一个队列的意思。可以设多个,比如 8,那样就并发 
redirect_stderr=true
stdout_logfile=/etc/supervisord.d/worker.log
stopwaitsecs=3600

注意上面的user www。

当队列处理代码修改后,需要容器内执行重启队列命令:supervisorctl restart all
因为这是守护进程,修改代码不影响正在执行的进程。所以我们修改代码后,需要重启让代码生效。

总结

  • docker-compose 的启动命令 :进入 docker-image目录,docker-compose up -d
  • 本文的内容是实际检测通过的,定时任务确实跑起来了。
  • myqueue 是消息队列,也跑起来了。
  • 用 docker 可以在服务器,主要是多 php 版本的情况会用到。以及通过 yum 安装失败,文件混乱的时候会用到。
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 5
sanders

我印象里如果这样跑队列的话,每次代码更新或配置修改后还得执行:

docker exec -it myqueue supervisorctl reload
1个月前 评论

定时任务的方案有两种:

  1. 使用宿主机系统自带的
  2. 用第三方的容器,例如这个项目 github.com/mcuadros/ofelia

感觉队列没必要再多装一个 supervisor,直接把启动队列的命令作为容器的 1 号进程就行了

1个月前 评论
sanders 1个月前
GeorgeKing (作者) 1个月前

一、用laravel任务调度。任务调度《Laravel 8 中文文档》

docker安装一个守护就行了。

apt-get install supervisor
配置守护进程路径 /etc/supervisor/supervisord.conf
[program:template]
command=php /var/www/html/artisan queue:work --queue=template
autostart=true
autorestart=true
priority=15
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stderr
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stopwaitsecs=3600
stopsignal=QUIT

二、用的docker-compose.yml的话,直接把supervisord.conf 映射到容器也行,方便随时更改。

正式环境我用第一种+linux的crontab结合。测试环境第二种。

这是我写的 博客:docker部署php+nginx环境

1个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
51
粉丝
7
喜欢
60
收藏
94
排名:588
访问:1.3 万
私信
所有博文
社区赞助商