⽤docker搭建php环境,搭建基于Docker的PHP开发环境的详细
教程
现在很多开发者都使⽤Vagrant来管理他们的虚拟机开发环境,Vagrant确实很酷, 不过也有不少缺点(最主要的是它占⽤太多的资源)。在容器技术、Docker和更多类Docker技术出现后,解决这个问题就变得简单了。
免责声明
由于boot2docker的⼯作⽅式,本⽂所述的⽅法在你的环境中可能⽆法正常运⾏。如果需要在⾮Linux环境下共享⽂件夹到Docker容器,还需要注意更多额外的细节。后续我会写篇⽂章专门来介绍实际遇到的问题。
怎样才算是好的开发环境
⾸先,我们得知道什么才是好的开发环境, 对于我⽽⾔,⼀个好的开发环境需要具备以下⼏个特点:
可随意使⽤。我必须可以随意删除和创建新的环境。
快速启动。我想要⽤它⼯作时候,它⽴马就能⽤。
易于更新。在我们⾏业中,事物发展变化⾮常快,必须能让我很容易将我的开发环境更新到新的软件版本。
⽽Docker都⽀持以上这些特点,甚⾄更多。你⼏乎可以即时销毁和重建容器,⽽更新环境只需要重建你当前使⽤的镜像即可。
什么是PHP开发环境
⽬前Web应⽤错综复杂,PHP开发环境需要很多的东西,为了保证环境的简单性,需要做各种各样的限制。
我们这次使⽤Nginx、PHP5-FPM、MySQL来运⾏Synmfony项⽬。
Pet 与 Cattle
另⼀个我们要讨论的重点是:我们要把开发环境部署在多容器还是单容器中。 两种⽅式各有优点:
单容器易于分发、维护。因为它们是独⽴的,所有的东西都运⾏在同⼀个容器中,这点就像是⼀个虚拟机。但这也意味着,当你要升级其中的某样东西(⽐如PHP新版本)的时候, 需要重新构建整个容器。
多容器可以在添加组件时提供更好的模块化。因为每个容器包含了堆栈的⼀部分:Web、PHP、MySQL等,这样可以单独扩展每个服务或者添加服务,并且不需要重建所有的东西。
因为我⽐较懒,加上我需要在我的笔记本上放点别的内容,所以,这⾥我们只介绍单个容器的⽅法。
初始化⼯程
⾸先要做的是初始化⼀个新的Symfony⼯程. 推荐的⽅法是⽤composer的create-project命令。本来可以在⼯作站上安装composer,但是那样太简单了。这次我们通过Docker来使⽤它。
我之前发过⼀篇关于Docker命令的⽂章:make docker commands(好吧,我说谎了,我本来把它写在这篇⽂章中了,然后觉得把它独⽴出来会⽐较好)。
不管怎么样,你可以读⼀下。接下来如果还没有composer命令的话,你可以创建⼀个属于⾃⼰的composer 别名。
$ alias composer="docker run -i -t -v \$PWD:/srv ubermuda/composer"
现在你可以初始化Symfony⼯程了:
$ composer create-project symfony/framwork-standard-edition SomeProject
帅呆了!下⾯来点实在的⼯作。
容器
构建⼀个运⾏标准Symfony项⽬且⾃给⾃⾜的容器相当容易,只需要安装好常⽤的Nginx、PHP5-FPM和MySQL-Server即可,然后把预先准备好的Nginx的虚拟主机配置⽂件扔进去,再复制⼀些配置⽂件进去就完事了。
本容器的源代码在GitHub上的 ubermuda/docker-symfony仓库中可以到。 Dockerfile 是Docker构建镜像要⽤到的配置⽂件,我们来看⼀下:
FROM debian:wheezy
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update -y
RUN apt-get install -y nginx php5-fpm php5-mysqlnd php5-cli mysql-server supervisor
RUN sed -e 's/;daemonize = yes/daemonize = no/' -i /etc/php5/f
RUN sed -e 's/;listen\.owner/listen.owner/' -i /etc/php5/fpm/pool.f静态网页的定义>css如何设置透明度
RUN sed -e 's/;listen\.up/' -i /etc/php5/fpm/pool.f
RUN echo "\ndaemon off;" >> /etc/f
mysql入门基础教程f /etc/nginx/sites-available/default
f /etc/supervisor/conf.f
ADD init.sh /init.sh
EXPOSE 80 3306
VOLUME ["/srv"]
WORKDIR /srv
CMD ["/usr/bin/supervisord"]
我们通过扩展 debian:wheezy 这个基础镜像开始,然后通过⼀系列的sed命令来配置Nginx和PHP5-FPM。
RUN sed -e 's/;daemonize = yes/daemonize = no/' -i /etc/php5/f
RUN sed -e 's/;listen\.owner/listen.owner/' -i /etc/php5/fpm/pool.f
RUN sed -e 's/;listen\.up/' -i /etc/php5/fpm/pool.f
RUN echo "\ndaemon off;" >> /etc/f
这⾥我们要做两件事。 ⾸先配置PHP5-FPM和Nginx让他们在前台运⾏以便supervisord可以追踪到他们。
然后,配置PHP5-FPM以指定的⽤户运⾏Web-Server,并处理好⽂件权限。
接下来需要安装⼀组配置⽂件,⾸先是Nginx的虚拟主机配置⽂件f:
server {
listen 80;
importantandserver_name _;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
root /srv/web;
index app_dev.php;
location / {
try_files $uri $uri/ /app_dev.php?$query_string;
}
location ~ [^/]\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
}
}
因为我们不需要域名,所以把server_name设成了_(有点像perl的$_占位符变量), 并配置根⽬录(document root)为/svr/web, 我们会把应⽤程序部署在/srv下,剩下的就是标准的Mginx + PHP5-FPM配置.
因为⼀个容器每次只能运⾏⼀个程序, 我们需要supervisord(或者任何别的进程管理器,不过我⽐较中意supervisord)。幸运的是, 这个进程管理器会产⽣我们需要的所有进程!下⾯是⼀⼩段supervisord的配置:
[supervisord]
nodaemon=true
[program:nginx]
command=/usr/sbin/nginx
[program:php5-fpm]
command=/usr/sbin/php5-fpm
[program:mysql]
command=/usr/bin/mysqld_safe
[program:init]
command=/init.sh
autorestart=false
redirect_stderr=true
redirect_stdout=/srv/app/logs/init.log
这⾥我们需要做的是定义所有的服务, 加上⼀个特殊的program:init进程,它不是⼀个实际的服务,⽽是⼀个独创的运⾏启动脚本的⽅式。
这个启动脚本的问题在于,它通常需要先启动某些服务。⽐如,你可能要初始化⼀些数据库表,但前提是你得先把MySQL跑起来,⼀个可能的解决办法 是,在启动脚本中启动MySQL,然后初始化表,然后为了防⽌影响到supervisord的进程管理,需要停掉MySQL,最后再启动 supervisord。json格式解析器
这样的脚本看起来类似下⾯这样:
/
etc/init.d/mysql start
app/console doctrine:schema:update --force
/etc/init.d/mysql stop
exec /usr/bin/supervisord
看起来丑爆了有⽊有,咱换种⽅式,让supervisor来运⾏它并且永不重启。
实际的init.sh脚本如下:
#!/bin/bash
RET=1
while [[ RET -ne 0 ]]; do
sleep 1;
mysql -e 'exit' > /dev/null 2>&1; RET=$?
done
DB_NAME=${DB_NAME:-symfony}
mysqladmin -u root create $DB_NAME
spring依赖注入原理if [ -n "$INIT" ]; then
/srv/$INIT
fi
脚本先等待MySQL启动,然后根据环境变量DB_NAME创建DB,默认为symfony, 然后在INIT环境变量中查要运⾏的脚本,并尝试运⾏它。本⽂的结尾有说明如何使⽤这些环境变量。
构建并运⾏镜像
万事俱备只⽋东风。我们还要构建Symfony Docker镜像, 使⽤docker build命令:
$ cd docker-symfony
$ docker build -t symfony .
现在,可以使⽤它来运⾏你的Symfony⼯程了:
$ cd SomeProject
$ docker run -i -t -P -v $PWD:/srv symfony
我们来看看这⼀连串的选项分别是⼲嘛的:
-i 启动交互(interactive)模式, 也就是说,STDIO(标准输⼊输出)连接到了你当前的终端上。当你要接收⽇志或者给进程发送信号时,它很有⽤。
-t 为容器创建⼀个虚拟TTY, 它跟-i是好基友,通常⼀起使⽤。
-P 告诉Docker守护进程发布所有指定的端⼝, 本例中为80端⼝。
-v $PWD:/srv 把当前⽬录挂载到容器的/srv⽬录。挂载⼀个⽬录使得⽬录内容对⽬标挂载点可⽤。
现在你还记得之前提到的DB_NAME和INIT环境变量了吧,⼲嘛⽤的呢:⽤于⾃定义你的环境。 基本上你可以通过 docker run的-e选项在容器中设置环境变量,启动脚本会拿到环境变量,因此,如果你的DB名为some_project_dev, 你就可以这么运⾏容器:
$ docker run -i -t -P -v $PWD:/srv -e DB_NAME=some_project_dev symfony
INIT 环境变量就更强⼤了,它允许你启动时运⾏指定的脚本。⽐如, 你有⼀个bin/setup脚本运⾏composer install命令并且设置数据库schema:
#!/bin/bash
composer install
app/console doctrine:schema:update --force
⽤-e来运⾏它:
$ docker run -i -t -P \
-v $PWD:/srv \
-e DB_NAME=some_project_dev \
-e INIT=bin/setup
注意,-e选项可以在docer run中多次使⽤,看起来相当酷。另外,你的启动脚本需要可执⾏权限(chmod +x)。
现在我们通过curl发送请求到容器,来检查⼀下是否所有的东西都像预期⼀样⼯作。⾸先,我们需要取到Docker映射到容器的80端⼝的公共端⼝,⽤docker port命令:
$ docker port $(docker ps -aql 1) 80
0.0.0.0:49153
docker ps -aql 1 是个好⽤的命令,可以⽅便的检索到最后⼀个容器的id, 在我们的例⼦中,Docker 把容器的80端⼝映射到了49153端⼝。我们 curl ⼀下看看。
You are not allowed to access this file. Check app_dev.php for more information.
当我们不从localhost(译者注:容器的localhost)访问dev controller时,得到了Symfony的默认错误消息,这再正常不过了, 因为我们不是从容器内部发送 curl 请求的, 所以,可以安全的从前端控制器web/app_dev.php中移除这些⾏。
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server')
) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
这些⾏阻⽌了任何从localhost以外的地⽅访问dev controller。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论