有一天一不小心把mac里的开发环境搞炸了,又失手升级了brew。新版本的brew把php的tap迁移了,直接放弃对php5.3的支持了。疲于编译安装,就打算直接上基于全套docker的开发环境,然后就遇到N多坑。包括但不限于:
php53配置Session | docker-compose的 link循环 | docker运行php异常缓慢
php53配置session的文件优先级
php53的session优先级是php-fpm.d/www.conf.其次是php.ini
在php.ini设置session使用memcache的时候,同时用php53,56,72来观察phpinfo(),发现56还有72都能够正确的指向了memcache,但是53还是file。
最后发现,在53的默认www.conf中,也有设置session的位置,优先级高于php.ini。
Docker Compose2个容器互相link出现错误
总结
如果2个容器各自link了对方,会出现如下错误:
$ docker-compose up
ERROR: Circular dependency between nginx and php72
解决方案是引入docker-compose的版本2中出现的network
关键字,把大家都置于同一个局域网中。
业务场景
我的业务中,nginx和php-fpm分隔2个容器。(以下只展示了问题相关的关键字,业务相关的关键字都省略了)
1 | version: ‘2’ |
然后nginx的vhost文件中的fastcgi_pass中填写fpm72:9000
来挂载php72容器的php-fpm。
问题来了,正常流程是访问网站A,网站A回调向网站B请求鉴权(通过Nginx知道),网站B鉴权通过后返回网站A。
所以网站nginx发起的请求时用户
问题来了,如果网站A和鉴权网站B都在nginx容器的vhost管理下,网站A要通过网站B鉴权,那么首先要向Nginx路由处理A过来的请求给B,然后网站B鉴权通过后,就要通过Nginx来路由回网站B。
可是因为只有Nginx容器单向link了php72容器(所以Nginx容器能知道php72容器的IP地址),而php72容器并没有link向Nginx容器(所以php72容器并不知道Nginx容器的IP地址在哪),那么网站A在请求鉴权的时候,根本不知道Nginx的IP地址(实际情况会被指向127.0.0.1),导致鉴权失败。
但是如果给php72容器加上links: nginx:web
,就是让php72容器也link上nginx容器,就会出现如下错误:
$ docker-compose up
ERROR: Circular dependency between nginx and php72
意思翻译过来就是,在nginx和php72容器之间存在了循环依赖,所以报错了。
背后的原因是如果要link一个容器,那个被link的容器就要先确立IP地址,但如果2个容器互相link,docker就不知道从哪个容器先开始确立IP地址。
解决方案
解决方案有2种:
- 把Nginx和php72放在同一个容器内,不存在link问题,直接就像平时服务器一样,自己调用本地端口就能解决问题,但是这样,Nginx和php的耦合度较高,对于docker来说不是非常好的实现。
- docker实例运行起来后,手动进入php72的主机,在里面加入hosts,把鉴权服务器指向nginx的IP地址。但是这样,每次新构建就会被清空,对于后期维护不利,容易遗忘。
- 引入docker-compose.yml的版本2及其以上版本中出现的network关键字,让大家都处于同一个网络。
详解
docker-compose文件版本2的说明,可以戳这里查看官方文档。
修改docker-compose文件为如下:
1 | version: ‘2’ |
通过把php72容器和nginx容器都处于共同的lnmp-network网络(默认是网桥模式),就能够实现互访互通了。
php72容器通过http://web
就能访问nginx容器(可以设定多个别名),nginx容器也能通过php72容器的别名fpm72
来访问fpm72了。
One More Thing
回到上面的案例,架设鉴权服务器已经被写死了,只能是local.auth.com
,而不能通过web
来调用,怎么破?
可以通过添加这个容器的aliases的占位符来添加指定的域名.
1 | # docker-compose.yml |
占位符的具体解释文件是在与docker-compose.yml同目录下的.env
1 | #.env |
就可以了。
Docker PHP运行速度异常缓慢
问题
我把全套开发环境都放在docker上,而网站的文件,这通过Volume的形式,挂载本机的具体文件夹。
等我把所有Docker-Compose遇到的开发坑都解决完毕了,以为可以美滋滋的向各位打开网页并炫耀我成果的时候发现。
Docker上运行的Yii2框架异常的缓慢(打开一张网站要15s),比我在本地构建的LNMP慢上1-2个数量级(本来只要2-3s)。
在我google/baidu了一圈后发现,最主要的问题是因为docker for mac在挂载本地Mac的文件夹时,由于Mac的磁盘格式,导致读写忙出翔。大家如果遇到这种情况,你打开Chrome的Network你会发现,速度慢主要是因为卡在了Waiting(TTFB)上,也就是等待服务器返回的时间。
解决方案
解决这个IO读写问题,现在普遍有3种解决方案:
- 直接把网站的文件也丢到docker容器里面
- 使用docker-sync
- 使用docker volume cache特性
我开宗明义的告诉大家,我的实测效果:
什么优化都没有做的时候,是15s
- 这种方式我并没有采用,我认为耦合度太高,而且对宿主机不可见
- 5s.速度较快。但是因为docker-sync是一个第三方的插件,操作很烦琐,我弄了一上午才搞出来。
- 6s.速度较快,docker内置的新特性,操作非常简单!但是需要升级docker到预览版(也就是edge版本)
具体的评测可以看看这篇文章3 ways to get Docker for Mac faster on your Symfony app.,但是我实测用docker-sync和cached速度相当。
所以接下来,直接介绍如何使用docker内置的Volume Cache特性。
Docker Volume Cached
- 切换你的Docker版本,从稳定Stable版本到Edge版本(类似国内说的开发者版本)
- 修改docker-compose.yml中的Volume属性,从
:rw
=>:cached
范例:
1 | version: '2' |
就算用上了cached或者docker-sync,实际上速度也是比不上在本地直接构建的,所以还是期待docker官方能够在后续的版本内更好的解决问题。