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
文件,把自己不需要的服务注释掉,需要的加上。例如:默认会同时安装mysql5
和mysql8
,根据自己的需求,只保留其中一个;
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
即可正常启动容器
本作品采用《CC 协议》,转载必须注明作者和本文链接
我没装DockerDesktop,我直接在 wsl 里跑 docker
我在Dockerfile写composer install 构建完成后没有vendor目录,把composer install写到docker-compose的command上就有是啥原因