聊聊 PHP 容器应用的最佳实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dzdh
V2EX    问与答

聊聊 PHP 容器应用的最佳实践

  •  
  •   dzdh 2022-08-16 09:48:11 +08:00 4076 次点击
    这是一个创建于 1198 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近公司正在推进容器化建设,主要是扩容方便。
    然后有几个问题,问一下。

    项目是 laravel 。那么附带的还有他的 queue 和 cron artisan schedule:run 。

    是都放在一个容器里吗?弄个 supervisor 启动 nginx 、fpm 、cron -f 、和 queue:work ?

    总觉得哪里不对,有啥最佳实践推荐一下吗?
    38 条回复    2023-09-19 15:42:25 +08:00
    cooper
        1
    cooper  
       2022-08-16 09:49:24 +08:00
    我们就是一个 docker 中,没啥不好。已经用三年了。
    KagurazakaNyaa
        2
    KagurazakaNyaa  
       2022-08-16 09:49:37 +08:00
    ss098
        3
    ss098  
       2022-08-16 10:00:16 +08:00
    可以构建成一个容器,但不要在一个容器内使用 supervisor 或其他进程管理工具启动,要作为多个容器启动。
    dzdh
        4
    dzdh  
    OP
       2022-08-16 10:02:28 +0800
    @ss098

    emmm.. 构建成 1 个容器 .... 多个容器启动。 啥。

    一个 image ,根据参数启动不同的进程作为独立 container 是吧。
    shoaly
        5
    shoaly  
       2022-08-16 10:06:24 +08:00
    @XiLingHost 这个是啥? readme 里面光做了一个 logo , 有点蒙蒙的
    LexLuth0r
        6
    LexLuth0r  
       2022-08-16 10:26:01 +08:00
    一个 Pod 中启动多个 container ,如 nginx 、php-fpm 服务、queue 服务。如果 queue 启动较多防止单个 Pod 资源不足,queue 服务也可以单独部署在一个 Pod 中,cron 同理。如果某一个 container 会频繁扩容就单独放到一个 Pod 中方便增加副本数。
    dzdh
        7
    dzdh  
    OP
       2022-08-16 10:29:46 +08:00
    @LexLuth0r 不是 k8s 呢
    zyh94946
        8
    zyh94946  
       2022-08-16 10:35:36 +08:00
    不是 k8s 用什么?
    xuelu520
        9
    xuelu520  
       2022-08-16 10:38:09 +08:00
    我们的 laravel 项目,queue 和 console 的脚本都有单独的容器来。
    Rache1
        10
    Rache1  
       2022-08-16 10:38:17 +08:00
    镜像都是同一个,queue 和 schedule 这些可以放到一个单独的容器里面去跑,使用 queue 使用 supervisor 守护
    dusu
        11
    dusu  
       2022-08-16 10:51:15 +08:00 via iPhone
    肯定拆开来用 docker compose
    redis mysql 这种放一个容器
    升级起来不是要命么
    而且基本上他们升级频率不高吧

    另外 简单说两个坑 可自行试试
    1. network 如果用 bridge ,性能可能会比裸跑低 30%
    2. 不用 volume ,用挂载代码,性能可能会比裸跑扣一半以上
    dusu
        12
    dusu  
       2022-08-16 10:57:39 +08:00 via iPhone
    @dusu 哦 看错了 没有 redis/mysql
    nginx 的话基本上看业务会不会后期扩展了
    如果会就拆出来 如果不考虑就放一块
    queue 和 cron 可以考虑同镜像不同容器
    y830CAa5nink4rUQ
        13
    y830CAa5nink4rUQ  
       2022-08-16 11:12:52 +08:00
    说一下我的做法,目前感觉用起来非常舒服:

    web 一个容器,里面用 supervisor 同时跑 nginx + php-fpm
    queue 、cron 单独一个容器

    #3 三楼所说的「不要在一个容器内使用 supervisor 」不适用于传统 php 项目
    leo108
        14
    leo108  
       2022-08-16 11:22:09 +08:00
    #13 传统 PHP 项目也是可以把 PHP 和 Nginx 拆开成两个容器的
    slowgen
        15
    slowgen  
       2022-08-16 11:44:21 +08:00 via Android
    上 nginx unit 就可以把 php 和 nginx 二合一了
    goodSleep
        16
    goodSleep  
       2022-08-16 11:46:40 +08:00 via Android
    我们没用容器,但是 artisan queue supervisor 都是单独部了一套业务
    dzdh
        17
    dzdh  
    OP
       2022-08-16 11:52:48 +08:00
    @shuimugan #14 一直没研究明白这个东西。这个东西没有配置文件。必须只能是 http post 配置然后存在内存里吗?
    dzdh
        18
    dzdh  
    OP
       2022-08-16 11:53:18 +08:00
    @dusu #11

    compose 一个 service 的存储是共享的吗?
    reter
        19
    reter  
       2022-08-16 11:55:37 +08:00   1
    没有人规定容器里面不能使用 supervisor 。

    但是容器只能监控第一个启动进程,如果使用了 supervisor ,那么容器监控到的是 supervisor 状态,而不是具体服务的状态。
    在容器内使用 supervisor 带来比较明显的缺点:
    - 进程监控( docker 只能看到 supervisor 的存在,无法感知 supervisor 背后启动的服务, 比如 docker ps )
    - 日志管理(如果服务直接往 stdout 输出日志,日期可以被 docker 收集,如果加了 supervisor 显然不能直接收集)
    - 信号处理+服务重启 (docker 重启服务时,会先向进程发送信号 SIGTERM ,此时服务可进行后续处理,超时才发送 SIGKILL. 使用 supervisor 可能需要进行额外配置,同时重启 supervisor 会将后面所有的服务都重启)

    同时一个服务一个容器,可以很好的利用现有的容器监控方案,然而使用 supervisor 就失去了这些优势。

    没有人规定容器里面不能使用 supervisor 。
    y830CAa5nink4rUQ
        20
    y830CAa5nink4rUQ  
       2022-08-16 12:07:23 +08:00
    @leo108
    #14
    分是能分,但是呢,传统 php 项目经常在 nginx 、fpm 共用 public 文件目录的。

    典型情况是 fpm 保存文件到 public/uploads 目录,nginx 提供静态文件服务,分开了会很麻烦。
    KagurazakaNyaa
        21
    KagurazakaNyaa  
       2022-08-16 12:29:30 +08:00
    @shoaly 这就是一个基于 docker 的 php laravel 项目
    gesse
        22
    gesse  
       2022-08-16 13:43:27 +08:00
    容器里应该少用 supervisor ,用 s6 多
    iyaozhen
        23
    iyaozhen  
       2022-08-16 13:46:30 +08:00
    容器里面不要用 supervisor ,挂了就让容器自己重启

    nginx 可以放进去,但应该轻量点,只是本地和 php 配合,把更多的功能做到网关层

    cron 啥的单独建集群和接受 http 请求的分开
    superchijinpeng
        24
    superchijinpeng  
       2022-08-16 13:47:06 +08:00
    拆到多个容器中
    superchijinpeng
        25
    superchijinpeng  
       2022-08-16 13:47:25 +08:00
    富容器没有意义
    toomoy
        26
    toomoy  
       2022-08-16 14:21:03 +08:00
    https://github.com/imbossa/docker_dev
    这个就包含 supervisor
    luyaolu
        27
    luyaolu  
       2022-08-16 16:22:08 +08:00
    我现在的就是一个 docker 中 大半年了 没啥问题
    slowgen
        28
    slowgen  
       2022-08-16 16:30:04 +08:00
    @dzdh nginx unit 说白了就是更容易编程化的 nginx ,你也可以把 json 写到文件,然后给 post json 文件的 curl 命令做个 alias ,就能达到修改配置文件 + nginx -s reload 的效果
    dzdh
        29
    dzdh  
    OP
       2022-08-16 17:08:41 +08:00
    @shuimugan #28 那我的配置一辈子不变就不能直接读取个文件吗? docker file 也好写啊

    CMD ["unitd","-c","/etc/service.json"] 他不香吗。。。。
    dzdh
        30
    dzdh  
    OP
       2022-08-16 17:08:57 +08:00
    @shuimugan 我在容器里为啥要 reload 啊
    xiaochong0302
        31
    xiaochong0302  
       2022-08-16 20:41:53 +08:00
    酷瓜云课堂的实践: https://gitee.com/koogua/course-tencent-cloud-docker

    php + cron + workerman (supervisor)
    nginx
    mysql
    redis
    xunsearch
    wangningkai
        32
    wangningkai  
       2022-08-16 23:15:34 +08:00 via iPhone
    GitHub 搜 dnmp ,用 docker- compose 编排
    slowgen
        33
    slowgen  
       2022-08-17 05:55:53 +08:00
    @dzdh 我觉得主要看你们是否把调整配置当成一次发版(更新容器)进行操作,如果不会线上 reload 那的确可以直接单个文件一把梭。

    reload 用于一般用于蓝绿部署,nginx unit 的条件路由可以很好的控制流量,比如通过特定 header 字段和值进行流量切换,比如把测试账号引流到特定节点。

    另外不建议把 nginx 和 php-fpm 分开部署,因为 php 的 curl 功能过于强大,如果代码逻辑不严谨或者缺乏安全团队测试,不恰当使用 curl 的话,会被和 gopher 组合构造出任意代码给 php-fpm 执行(相当于后门)。
    julyclyde
        34
    julyclyde  
       2022-08-17 12:14:14 +08:00
    在容器内就没必要 supervisord 或者 systemd 了

    该出错的时候能正确的出错,是一种较佳实践
    julyclyde
        35
    julyclyde  
       2022-08-17 12:16:17 +08:00
    @shuimugan 换个说法就是,把容器当作短期的“运行”还是当作长期的“机器”
    如果是后者,各种操作产生的结果会累积起来形成状态,这个状态不一定是期望的
    gaoxu387
        36
    gaoxu387  
       2023-09-18 17:36:26 +08:00
    @reter 很赞同你的观点,容器的 12 要素的也提到了一个关键的点,一个进程: https://12factor.net/zh_cn/processes
    而 supervisor 的模式是违反了这种理念,虽然也可以用但不是最佳的方法。

    对于 PHP 的容器化特别是 Laravel 的容器化的个人建议:
    1 、打包成一个镜像
    2 、nginx 运行 pod 、php-fpm 运行一个 pod 、laravel 的 schedule:run 运行一个 cron 的镜像

    业务流量是 Ingress (不配置规则)-> service -> nginx (具体规则) -> php-fpm (中间件不要部署在 k8s 里)
    cron 单独运行一个常驻的 pod ,启动 crond ,并配置一分钟运行一次 schedule:run
    dzdh
        37
    dzdh  
    OP
       2023-09-18 18:30:24 +08:00
    @gaoxu387 nginx 运行 pod 、php-fpm 运行一个 pod 代码在放在哪里。

    nginx 有个 try_files , 必须要能访问到.php 文件。

    php-fpm fcgi 协议是 nginx 传递过来的 filepath 。

    那么程序代码放在哪里?
    gaoxu387
        38
    gaoxu387  
       2023-09-19 15:42:25 +08:00
    @dzdh 代码运行在 php-fpm 这个 pod 里啊,nginx 通过服务名称转发 proxy_pass 到 php-fpm 的容器. nginx 一般用这个配置转发:
    location ~ \.php$ {
    fastcgi_pass php-fpm:9000;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    include fastcgi_params;
    }
    如果你需要用 try_files 那你把代码也打包一份在 nginx 的 pod 也是可以的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5810 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 02:06 PVG 10:06 LAX 18:06 JFK 21:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86