windows环境下用docker搭建php开发环境dnmp

安装WSL


WSL即Linux子系统,比虚拟机占用资源少,安装的前提是系统必须是win10以上。

WSL的安装比较简单,网上有很多教程,例如:WSL简介与安装流程(Windows 下的 Linux 子系统)_wsl安装-CSDN博客,我这里就不多赘述了

安装DockerDesktop


官网下载:Docker Desktop: The #1 Containerization Tool for Developers | Docker

汉化包(可选):asxez/DockerDesktop-CN: Docker汉化 Docker中文版 Docker汉化包 DockerDesktop汉化 Docker Windows Docker MAC

修改镜像存储目录(可选):由于镜像比较大,为了不占用c盘用空间,可以设置修改镜像存储目录

下载dnmp


我们直接用github上star比较多的,虽然有点缺陷,很多东西文档上也没说,不过该有的都有,没有的我会补充

项目github地址:garymengcom/dnmp: Docker LNMP (Nginx, PHP7/PHP5, MySQL, Redis)

git clone https://github.com/garymengcom/dnmp.git

配置文件


1.复制配置文件

cd dnmp
copy env.sample .env
copy docker-compose.sample.yml docker-compose.yml

2.修改.env文件配置

  • 修改php代码目录,把SOURCE_DIR修改为你的php代码所在目录,默认是dnmp/www,假如我的是D:/wwwroot目录,则修改为

    SOURCE_DIR=D:/wwwroot
  • 增加php扩展,默认安装php扩展比较少,根据需要需要在对应的php配置中添加额外的扩展,如redis,exif,bcmath

  • 修改mysql端口、root密码

3.修改docker-compose.yml文件,把自己不需要的服务注释掉,需要的加上。例如:默认会同时安装mysql5mysql8,根据自己的需求,只保留其中一个;

4.默认配置文件都在services目录下对应的程序目录里面,保持默认即可

启动服务


docker-compose up -d

如果下载镜像的过程中报错网络问题无法下载,可以看下面的【更换镜像源】这一节解决,或者尝试手动执行docker pull 单独拉取镜像试试

等待镜像下载完成,容器运行了就可以了。如果安装了Docker Desktop,按照提示按v键可以跳转到Docker Desktop中查看跑起来的服务

访问http://localhost即可访问到默认的网站

更换镜像源


如果启动服务过程中报下面的错,镜像无法下载,则需要更换docker镜像源

可以上网找一下当前可用的docker镜像源,例如:https://cloud.tencent.com/developer/article/2485043,然后在或DockerDesktop的配置中增加镜像配置registry-mirrors,镜像地址自己找最新可用的地址

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://docker.1ms.run"
  ]
}

安装PHP扩展


参考官方文档即可:garymengcom/dnmp: Docker LNMP (Nginx, PHP7/PHP5, MySQL, Redis)

新建站点


默认有一个localhost网站,目录在dnmp\www\localhost,按照下面的步骤可以新建一个站点,以创建www.test-site.net为例

  • 1.创建nginx站点配置文件

    进入dnmp\services\nginx\conf.d目录,新建文件www.test-site.net.conf,文件内容如下(将www.test-site.net全部替换为你自己的域名即可, 注意修改fastcgi_pass配置项对应的php容器)

    server {
        server_name  www.test-site.net;
        listen       80;
    
        root   /www/www.test-site.net;
        index  index.php index.html index.htm;
        #charset koi8-r;
    
        access_log /dev/null;
        #access_log  /var/log/nginx/nginx.www.test-site.net.access.log  main;
        error_log  /var/log/nginx/nginx.www.test-site.net.error.log  warn;
    
        #error_page  404              /404.html;
    
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
    
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        # 注意修改fastcgi_pass中对应的php容器
        #
        location ~ [^/]\.php(/|$) {
            fastcgi_pass   php74:9000;
            include        fastcgi-php.conf;
            include        fastcgi_params;
        }
    
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
  • 2.修改本地hosts文件,增加一条记录

    127.0.0.1 www.test-site.net
  • 3.新增php代码

    在php代码目录(默认是dnmp\www)下新建站点目录dnmp\www\www.test-site.net,里面存放该站点的php文件

  • 4.重启nginx,浏览器访问http://www.test-site.net/即可,需要注意的是如果你开了代理可能会导致hosts文件映射失效!

  • 5.如果每个网站需要不同的php版本,那么需要启动对应版本的php容器并且网站的nginx配置文件中的fastcgi_pass配置项需要修改为对应的php版本

注意事项

如果项目是thinkphp或laravel等web框架,需要将www.test-site.net.conf配置中的root /www/www.test-site.net;修改为public目录,如:root /www/www.test-site.net/public,然后增加伪静态配置

  Laravel伪静态:
  location / {  
      try_files $uri $uri/ /index.php$is_args$query_string;  
  }  


  ThinkPHP5.x伪静态:
  location / {
      try_files $uri $uri/ /index.php?$query_string;
  }

  ThinkPHP6.x伪静态:
  location / {
      if (!-e $request_filename) {
          rewrite  ^(.*)$  /index.php?s=$1  last;
          break;
      }
  }

SSL证书


  • 1.生成证书

    本地自签名证书推荐mkcert:Windows下安装mkcert_windows安装mkcert-CSDN博客

    生产环境免费证书推荐Let‘s Encrypt:[SSL]Let‘s Encrypt生成免费的SSL证书_let’s encrypt 证书-CSDN博客

    当然,也可以选择其他付费SSL证书,证书包括.crt.key格式的两个文件,在dnmp\services\nginx\ssl目录创建跟网站域名一致的文件夹,然后将两个证书文件放到文件夹里即可

  • 2.在对应站点的nginx配置文件最后增加下面这段配置,注意将证书路径替换为你的

    listen 443 ssl;
    ssl_certificate /ssl/www.test-site.net/www.test-site.net+2.pem;
    ssl_certificate_key /ssl/www.test-site.net/www.test-site.net+2-key.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:!LOW:!aNULL:!eNULL;
  • 3.重启nginx生效

    docker-compose restart nginx

解决dnmp环境下php运行慢问题

你有没有发现使用WSL+Docker这种方式运行php连输出简单的hello world都要4秒钟,为什么会这么慢???

  • 原因

    WSL2 的跨文件系统的io读写性能非常非常差,官方已经告诉了我们关键问题和解决方案:不要将项目挂载到 Windows 系统中,
    而是挂载到 WSL 文件系统中。

  • 思路

    1.参考文章 解决Docker使用WSL2项目运行慢的问题 | Laravel China 社区,将原本.env配置文件中的SOURCE_DIR路径(也就是windows与docker容器映射的目录)改为WSL路径,也就是windows与docker容器目录映射改为wsl与docker容器目录映射,然后进入WSL,在WSL中执行docker-compose up命令。然后把php代码复制一份到这个WSL目录中,这样就不存在跨文件系统读写问题了,再次访问docker中的php网站,快到飞起!!!但是又产生新的问题:代码文件怎么同步?用FTP有点麻烦,linux定时同步也很麻烦。。。

    2.不知道你发现没有,在DockerDesktop中勾选Enable integration with my default WSL distro的话,你的电脑中会多出一个Linux文件目录,你可以直接在windows下访问WSL中的文件。通过查询资料得知,在WSL中,/mnt目录是与windows的硬盘目录是连通的,也就是在WSL中也能直接读取到你在windows中的php代码目录!!!

  • 解决

    有了上面两个前提,那就好解决了,直接把WSL中/mnt代码目录(与windows中的代码目录相同)和docker容器的目录映射起来,按照下面两个步骤操作就可以了

    1.修改.env中的php代码目录SOURCE_DIR为WSL目录,例如我的代码目录为D盘下的D:\dnmp\www,那么就改为SOURCE_DIR=/mnt/d/dnmp/www/

    2.通过cmd进入WSL(直接输入wsl命令)然后在WSL中运行docker-compose up -d即可,就是这么简单。千万不要在windows下启动docker-compose, 因为windows下没有/mnt/d/dnmp/www目录,会映射失败。当然,第一次在WSL启动成功之后,也可以在dockerDesktop界面中直接点按钮一键启动!再次访问docker中的网站看看是不是快多了!

如果myql容器无法正常启动,请参考下面的【常见问题 · 在WSL中docker启动mysql容器失败】解决

自定义镜像


项目使用的镜像都是官方镜像,有时候会满足不了我们的需求,比如php扩展比较少,增加扩展之后如果要多机部署又要安装一次php扩展,非常不方便。目前可用的解决方法是打包并发布自己的镜像,然后修改dnmp\services目录下对应的程序Dockerfile文件中的镜像名称再执行docker-compose up

新增PHP版本


以新增PHP8.4为例

  • 1.在docker-compose.yml文件中复制一份PHP8.2的配置并替换为PHP8.4,注意先不要做目录映射,因为还没有默认的配置文件

    php84:
        build:
          context: ./services/php84
          args:
            DEBIAN_MIRROR_DOMAIN: deb.debian.org
            PHP_EXTENSIONS: "$PHP84_EXTENSIONS"
            TZ: "$TZ"
        container_name: php84
        expose:
          - 9501
        volumes:
          - ${SOURCE_DIR}:/www/:rw
          - ${PHP84_LOG_DIR}:/var/log/php
          - ${PHP84_DATA_COMPOSER}:/tmp/composer
        restart: always
        cap_add:
          - SYS_PTRACE
        networks:
          - default
  • 2.在.env文件中复制一份PHP8.2的配置并替换为PHP8.4,修改配置文件位置,注意将扩展删除,只保留curl即可,不然可能会安装报错

    #
    # PHP84
    #
    # Available PHP_EXTENSIONS:
    #
    # pdo_mysql,zip,pcntl,mysqli,mbstring,exif,bcmath,calendar,
    # sockets,gettext,shmop,sysvmsg,sysvsem,sysvshm,pdo_rebird,
    # pdo_dblib,pdo_oci,pdo_odbc,pdo_pgsql,pgsql,oci8,odbc,dba,
    # gd,intl,bz2,soap,xsl,xmlrpc,wddx,curl,readline,snmp,pspell,
    # recode,tidy,gmp,imap,ldap,imagick,sqlsrv,mcrypt,opcache,
    # redis,memcached,xdebug,swoole,pdo_sqlsrv,sodium,yaf,mysql,
    # amqp,mongodb,event,rar,ast,yac,yar,yaconf,msgpack,igbinary,
    # seaslog,varnish,xhprof,xlswriter,memcache,rdkafka,zookeeper,
    # psr,phalcon,sdebug,ssh2,yaml,protobuf,hprose
    #
    # You can let it empty to avoid installing any extensions,
    # or install multi plugins as:
    # PHP84_EXTENSIONS=pdo_mysql mysqli gd curl opcache
    # Note::that it is a space
    
    PHP84_VERSION=8.4.3
    PHP84_PHP_CONF_FILE_DEVELOPMENT=./services/php84/php.ini-development
    PHP84_PHP_CONF_FILE_PRODUCTION=./services/php84/php.ini-production
    PHP84_FPM_CONF_FILE=./services/php84/www.conf
    PHP84_LOG_DIR=./logs/php84
    PHP84_DATA_COMPOSER=./data/composer
    PHP84_EXTENSIONS=curl
  • 3.在dnmp项目中新建php84目录和Dockerfile文件

    cd service && mkdir php84
    cd php82 && copy Dockerfile ..\php84\

    编辑php84/Dockerfile,将里面的FROM php:8.2-fpm改为FROM php:8.4-fpm并保存

  • 4.在WSL中执行docker-compose up -d创建容器

  • 5.在WSL中执行下面的命令复制配置文件到宿主机

    首先查看php84容器/usr/local/etc目录下有什么配置文件

    然后将3个需要的文件复制到宿主机

    docker cp php84:/usr/local/etc/php/php.ini-development /mnt/d/dnmp/services/php84/php.ini-development
    docker cp php84:/usr/local/etc/php/php.ini-production /mnt/d/dnmp/services/php84/php.ini-production
    docker cp php84:/usr/local/etc/php-fpm.d/www.conf /mnt/d/dnmp/services/php84/php-fpm.conf
  • 6.修改docker-compose.yml目录映射配置文件,注意变量要跟.env文件中对应

    php84:
        build:
          context: ./services/php84
          args:
            DEBIAN_MIRROR_DOMAIN: deb.debian.org
            PHP_EXTENSIONS: "$PHP84_EXTENSIONS"
            TZ: "$TZ"
        container_name: php84
        expose:
          - 9501
        volumes:
          - ${SOURCE_DIR}:/www/:rw
          - ${PHP84_PHP_CONF_FILE_DEVELOPMENT}:/usr/local/etc/php/php.ini-development
          - ${PHP84_PHP_CONF_FILE_PRODUCTION}:/usr/local/etc/php/php.ini-production
          - ${PHP84_FPM_CONF_FILE}:/usr/local/etc/php-fpm.d/www.conf
          - ${PHP84_LOG_DIR}:/var/log/php
          - ${PHP84_DATA_COMPOSER}:/tmp/composer
        restart: always
        cap_add:
          - SYS_PTRACE
        networks:
          - default
  • 7.在WSL中删掉php84容器并重新创建

    docker rm php84
    docker-compose up -d

    到此新增PHP版本成功

常见问题


  • php编译失败

    php在编译过程中可能会遇到扩展安装报错导致编译失败

    可以尝试修改.env文件中的CONTAINER_PACKAGE_URL,这一行的上面有提供几个url,可以逐个尝试看看能不能解决。如果还不能解决,打开.env文件,在对应的PHP扩展中删除部分扩展,例如只保留curl扩展,其他扩展等容器跑起来后手动安装。

  • 在WSL中docker启动mysql容器失败

    mysql无法启动,查看日志发现报错没有权限[ERROR] Could not set file permission for ca-key.pem,原因是wsl.conf文件没有metadata信息,需要修改wsl的配置才能支持修改文件属性。进入WSL,然后编辑/etc/wsl.conf文件增加下面的配置信息,重启WSL即可

    [automount]
    enabled = true
    options = "metadata"
    mountFsTab = false

    在windows cmd下重启WSL

    # 关闭wsl
    wsl --shutdown
    # 启动并进入wsl
    wsl

    再次进入WSL执行docker-compose up -d即可正常启动容器

    参考文章:blog.csdn.net/x356982611/article/d...

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 7

我没装DockerDesktop,我直接在 wsl 里跑 docker

1天前 评论
jian1098 (楼主) 1天前

我在Dockerfile写composer install 构建完成后没有vendor目录,把composer install写到docker-compose的command上就有是啥原因

1天前 评论
浮心 1天前
jian1098 (楼主) 1天前
Deftlhhhhh (作者) 1天前
jian1098 (楼主) 1天前

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