分享一下我的开发栈-基于 docker

最近,看到很多小伙伴在讨论开发栈,我也来分享下我的开发栈。

一开始我也是走过本地自建、PHP study、Homestead 这些路,但是一遇到要同时支持多个版本就变得很麻烦。后来就开始用 docker,一个项目一个环境,互不干扰,互不影响,配置好后,一键启动关闭,真的不要太省心。期间有不断适应调整,基于当前开发栈已经用了4年,公司项目加上自己的娱乐项目,有40+个项目,PHP 的版本从 5.6 到 8.3 每个主版本都有。

架构大概就这个样子:

开发栈

PHP 镜像 php-nginx-alpine

最开始是用的 Laradock,但这玩意儿里面东西太多了,调整起来很麻烦。后来就想着自建镜像,于是基于 Laravel 项目要求,东学西凑的编写自己的 Dockerfile,编译自己的镜像。自己建就简单了,只需要能让项目跑起来的东西就够了。
这个镜像主要包含两部分,PHP 和 Nginx,具体内容详见: github.com/chuoke/php-nginx-alpine
后来工作公司用的 ThinkPHP,于是将 Laravel 和 ThinkPHP 的默认 nginx 配置内置进来,添加了启动脚本。

反向代理 Treafik

项目多,端口绑定就会变得混乱,于是开始加反向代理,只需要绑定 80 端口就行。刚开始用的 Nginx Manager,但是吧,这个东西配置之后,要是某个项目没运行,就会报错,反正折腾了一个周就放弃了。然后就看到 Treafik,这家伙最开始好像是专为 docker 反向代理而生,是开源的。
Treafik 的配置超灵活,只要首次配置好,启动项目就可以开始代理,停止就注销,完全不用管其它的,感兴趣可以看它的文档 Traefik Proxy 文档
这里给出我本地的配置:

# docker-compose.yml

services:
  reverse-proxy:
    image: traefik:v2.8
    container_name: traefik
    restart: unless-stopped
    ports:
      - target: 80
        published: 80
        mode: host
    volumes:
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./conf:/var/usr/traefik/conf
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-dash.entrypoints=web"
      - "traefik.http.routers.traefik-dash.rule=Host(`traefik.test`)"
      - "traefik.http.routers.traefik-dash.service=api@internal"
# traefik.yml

# Docker configuration backend
providers:
  docker:
    exposedByDefault: false
  file:
    directory: "/var/usr/traefik/conf"
    watch: true

# API and dashboard configuration
api:
  # insecure: true
  dashboard: true

## Static configuration
entryPoints:
  web:
    address: ":80"
    forwardedHeaders:
      insecure: true

  web-secure:
    address: ":443"
    forwardedHeaders:
      insecure: true

主要就两个文件,docker-compose.yml 和 traefik.yml,4年前写的配置就这样,中间就做了下版本升级,是不是超省心。

Acrylic DNS

我这项目是真的多,自带的 DNS 不支持通配符,加上 hosts 会经常莫名其妙的被重置,于是就找到了一个本地 DNS 服务–Acrylic DNS。可以设置开机启动,配置是在它独立 accrylic host 文件,除基础的接口,还支持通配符,不会和主机的 hosts 冲突。
我还体验过其它几个,但都没让我满意,就这个最方便好用,遗憾的是,它只支持 Windows 系统。

其它服务

另外项目基本都会用到 MySQL 、Redis 这些,也都是 docker 方式运行。

项目环境

docker 中的每个系统都是独立的,那么如何让他们串在一起相互访问呢?那就是通过网络,只要让他们在同一个网络,就可以相互访问到。以下展示我本地的一个项目案例说明:

networks:
  traefik:
    name: traefik_default
    external: true
  mysql:
    name: mysql_default
    external: true
  redis:
    name: redis_default
    external: true

services:
  app:
    image: chuoke/php-nginx-alpine:8.2
    container_name: ${COMPOSE_PROJECT_NAME}
    environment:
      - APP_CODE_PATH=${APP_CODE_PATH}
      # NGINX_SERVER_TYPE: laravel(默认) thinkphp
      - NGINX_SERVER_TYPE=laravel
      # 这里是示例,NGINX_SERVER_ROOT 在 laravel 下默认就是这个
      - NGINX_SERVER_ROOT=${APP_CODE_PATH}/public
    working_dir:
      ${APP_CODE_PATH}
    volumes:
      # 这个可以提升下性能
      - ${APP_CODE_PATH}/vendor
      - ${APP_PATH_HOST}:${APP_CODE_PATH}
      - ./nginx/logs:/var/log/nginx
      # 如果需要,可以自定义 nginx 站点配置,就不需要上面的环境变量
      # - ./nginx-site.conf:/etc/nginx/sites-available/site.conf
      # 已默认启动 nginx 和 php-fpm,可以自定义
      # - ./supervisord.conf:/etc/supervisor/conf.d/supervisord.d/site.conf
    # 让该服务加入以下网络,就可以访问它们对应的服务啦
    networks:
      - traefik
      - mysql
      - redis
    expose:
      - 80
    # 让 treafik 知道,我要加个代理转发服务
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_default"
      - "traefik.http.routers.${COMPOSE_PROJECT_NAME}-router.rule=HOST(`laravel-11.test`)"
      - "traefik.http.routers.${COMPOSE_PROJECT_NAME}-router.entrypoints=web"

supervisord.conf 中设置的是相关启动服务,主要启动并守护服务进程,这里主要有3个:php-fpm、nginx、scheduler:

[program:php-fpm]
command=php-fpm -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3

[program:nginx]
command=nginx
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3

[program:laravel-scheduler]
process_name=%(program_name)s_%(process_num)02d
command=/bin/sh -c "while [ true ]; do (php /var/www/site/artisan schedule:run --verbose --no-interaction &); sleep 60; done"
; command=/bin/sh -c "php /var/www/site/artisan schedule:work"
autostart=true
autorestart=true
numprocs=1
user=www-data
redirect_stderr=true

这样就可以启动项目了,另外要注意一点,在项目里访问其它服务,需要使用设置的对应网络的名称,比如 MySQL,根据这个示例,配置就得是这样: DB_HOST=mysql,此处的 mysql 是 MySQL 服务在名为 mysql_default 网络中的名字,可以通过 docker network inspect mysql_default 查看,当然也可以把 MySQL 服务加入其它网络中。

本作品采用《CC 协议》,转载必须注明作者和本文链接
? 我的导航网站已经可以公开使用啦:Cootab
讨论数量: 4

我之前用的是 CoreDNS,用 Nginx 的 Unit 替代 Nginx + PHP-FPM 的组合。

Scheduling 则是用的 mcuadros/ofelia

这样所有的基础设施都基于容器来运行,最大程度保证环境的一致性!

3周前 评论
chuoke (楼主) 3周前

hyperf项目 基于docker的环境 项目大了执行phpstan扫描代码 电脑发烫 cpu跑满 实在没法用

3周前 评论
chuoke (楼主) 2周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!