`
hongtoushizi
  • 浏览: 362904 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

基于Docker的PHP开发环境

阅读更多

转载自: http://dockone.io/article/117

 

基于Docker的PHP开发环境

【编者的话】本文作者是Geoffrey,他是一个PHP的Web开发者,喜欢DevOps和Docker。本文主要介绍了如何使用Docker构建PHP的开发环境,文中作者也探讨了构建基于Docker的开发环境应该使用单容器还是多容器,各有什么利弊。推荐PHP开发者阅读。

 

现在很多开发者都使用Vagrant来管理他们的虚拟机开发环境,Vagrant确实很酷, 不过也有不少缺点(最主要的是它占用太多的资源)。在容器技术、Docker和更多类Docker技术出现后,解决这个问题就变得简单了。

免责声明

由于boot2docker的工作方式,本文所述的方法在你的环境中可能无法正常运行。如果需要在非Linux环境下共享文件夹到Docker容器,还需要注意更多额外的细节。后续我会写篇文章专门来介绍实际遇到的问题。

怎样才算是好的开发环境

首先,我们得知道什么才是好的开发环境, 对于我而言,一个好的开发环境需要具备以下几个特点:

  1. 可随意使用。我必须可以随意删除和创建新的环境。
  2. 快速启动。我想要用它工作时候,它立马就能用。
  3. 易于更新。在我们行业中,事物发展变化非常快,必须能让我很容易将我的开发环境更新到新的软件版本。

 

而Docker都支持以上这些特点,甚至更多。你几乎可以即时销毁和重建容器,而更新环境只需要重建你当前使用的镜像即可。

什么是PHP开发环境

目前Web应用错综复杂,PHP开发环境需要很多的东西,为了保证环境的简单性,需要做各种各样的限制。

我们这次使用Nginx、PHP5-FPM、MySQL来运行Synmfony项目。由于在容器中运行命令行会更复杂,所以这方面的内容我会放到下一篇博客中再说。

Pet 与 Cattle

另一个我们要讨论的重点是:我们要把开发环境部署在多容器还是单容器中。 两种方式各有优点:

  • 单容器易于分发、维护。因为它们是独立的,所有的东西都运行在同一个容器中,这点就像是一个虚拟机。但这也意味着,当你要升级其中的某样东西(比如PHP新版本)的时候, 需要重新构建整个容器。
  • 多容器可以在添加组件时提供更好的模块化。因为每个容器包含了堆栈的一部分:Web、PHP、MySQL等,这样可以单独扩展每个服务或者添加服务,并且不需要重建所有的东西。

 

因为我比较懒,加上我需要在我的笔记本上放点别的内容,所以,这里我们只介绍单个容器的方法。

初始化工程

首先要做的是初始化一个新的Symfony工程. 推荐的方法是用composercreate-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

 

帅呆了!下面来点实在的工作。(省略了博主自娱自乐的一堆balabla....原文:Awesome. Give yourself a high-five, get a cup of coffee or whatever is your liquid drug of choice, and get ready for the real work.)

 

容器

构建一个运行标准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/fpm/php-fpm.conf

RUN sed -e 's/;listen\.owner/listen.owner/' -i /etc/php5/fpm/pool.d/www.conf

RUN sed -e 's/;listen\.group/listen.group/' -i /etc/php5/fpm/pool.d/www.conf

RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

 

ADD vhost.conf /etc/nginx/sites-available/default

ADD supervisor.conf /etc/supervisor/conf.d/supervisor.conf

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/fpm/php-fpm.conf

RUN sed -e 's/;listen\.owner/listen.owner/' -i /etc/php5/fpm/pool.d/www.conf

RUN sed -e 's/;listen\.group/listen.group/' -i /etc/php5/fpm/pool.d/www.conf

RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

 

这里我们要做两件事。 首先配置PHP5-FPM和Nginx让他们在前台运行以便supervisord可以追踪到他们。

然后,配置PHP5-FPM以指定的用户运行Web-Server,并处理好文件权限。

 

接下来需要安装一组配置文件,首先是Nginx的虚拟主机配置文件vhost.conf:

server {

    listen 80;

 

    server_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。

 

这样的脚本看起来类似下面这样:

/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

 

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_NAMEINIT环境变量了吧,干嘛用的呢:用于自定义你的环境。 基本上你可以通过 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 一下看看。

$ curl http://localhost:49153

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。

现在再curl的时候就可以正常工作了,或者用浏览器访问 http://localhost:49153/

 

 

 

 

很容易吧! 现在我们可以快速的启动、更新环境了,但还是有很多地方需要改进。

 

 

原文链接:A PHP development environment with Docker (翻译:何林冲 审校:郭蕾)

分享到:
评论

相关推荐

    基于 docker-compose 开发的运行在 Docker 上的 LNMP 开发环境,包含 Nginx、 PHP.zip

    基于 docker-compose 开发的运行在 Docker 上的 LNMP 开发环境,包含 Nginx、 PHP

    Docker构建PHP开发环境Docker-PHP.zip

    Docker-PHP 是基于 Docker 构建的集成开发环境。特性自定义配置文件数据存储在主机中软件栈MongoDBRedisMySQLPHP 7.1 PHP-FPMNginx with LuaJit  标签:Docker

    基于docker的开发者集成环境 (docker,nodejs,php,nginx,mongo,mysql,redis等)

      它是基于docker的开发者集成环境,包含丰富的软件,但它是未来开发者的趋势,因为基于docker,使你本机电脑有云开发的效果。 一键安装所有程序,或者单独使用某个程序;方便版本切换,因为它是基于docker,所以...

    基于docker的thinkphp5框架的lnmp开发环境

    基于docker的thinkphp5框架的lnmp开发环境 mysql默认端口为:`33060` nginx默认端口为:`8080` redis默认端口为:`63790` 具体配置可修改根目录`.env`文件 docker-compose up --build -d #构建并后台执行

    dev-environment:我基于Docker的开发环境

    我基于docker的开发环境。 我是Vim,但是我的设置不是git clone,因此,我决定构建基于docker的IDE,以在服务器上编辑实际代码。 目录 建立它 docker build -t nemanjan00/dev . 运行 docker run -ti nemanjan00/...

    Docker的完整PHP开发环境。-PHP开发

    基于Docker的完整PHP开发环境。 支持各种通用服务,所有这些都预先配置为提供完整PHP开发环境。 首先使用Docker-然后再了解它! 基于Docker的完整PHP开发环境。 支持各种通用服务,所有这些都预先配置为提供完整PHP...

    Docker 如何布置PHP开发环境

    本文主要介绍了如何使用Docker构建PHP的开发环境,文中作者也探讨了构建基于Docker的开发环境应该使用单容器还是多容器,各有什么利弊。推荐PHP开发者阅读。

    搭建基于Docker的PHP开发环境的详细教程

    现在很多开发者都使用Vagrant来管理他们的虚拟机开发环境,Vagrant确实很酷, 不过也有不少缺点(最主要的是它占用太多的资源)。在容器技术、Docker和更多类Docker技术出现后,解决这个问题就变得简单了。 免责声明...

    基于Docker容器化PHP开发环境解决方案.zip

    方案是为解决特定问题或...通过定期的评估,可以及时调整方案,以适应变化的环境或新的挑战。 总体而言,方案的作用在于提供一种有序、有计划的方法,以解决问题、实现目标,并在实施过程中最大化资源利用和风险管理。

    DockerPHP:基于Docker容器化PHP开发环境解决方案

    Docker容器化PHP开发环境搭建-DVWA (含xdebug调试)Docker容器化技术在过去的2015年得到了大面积的普及应用,特别是以灵雀云、数人云、阿里云以及阿里百川TAE2.0等为代表的服务商的推动,可以预见2016会是云服务大...

    Docker搭建自己的PHP开发环境

    本文给大家介绍的是如何在docker中搭建一个PHP的开发环境,将用 zPhal-dockerfiles 做为例子,有需要的小伙伴可以参考下

    基于Docker的PHP调用基于Docker的Mysql数据库

    docker简介: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可...2:建立基于docker的php image 在当前目录,建立Dockerfile,内容如下 FROM php:7.0-cli MAINTAINER Terry Zhang R

    Ubuntu 搭建基于Docker的LNMP+Redis的开发环境(图文)

    Ubuntu 搭建基于Docker的LNMP+Redis的开发环境 服务器环境:Ubuntu 14.04 1.安装Docker 1.1 执行update命令,和服务器同步软件包,执行apt-get install * 时可以下载最新的软件。   1.2 安装Docker和创建软链接   ...

    development:基于Docker的本地开发环境

    基于Docker的本地开发环境。 Php和Npm用户与当前用户同步,因此我们将拥有使用容器命令修改和访问所生成内容的所有权利。 我们这里有什么 首先: 阿帕奇2.4 启用xDebug,启用远程调试和错误报告PHP 7.4 fpm 带有管理...

    development-docker:基于Docker容器的CS-Cart开发环境

    基于Docker的开发环境: PHP版本:8.0、7.4、7.3和5.6。 MySQL 5.7数据库服务器。 Nginx Web服务器。 安装git , docker和docker-compose 。 克隆环境存储库: $ git clone git@github....

    codeEnv:基于Docker的代码开发环境

    codeEnv说明团队中每进入一个新... 他是一个基于docker的开发环境。能让同事在本地编程, 代码实时同步到开发服务器。同事在本地新建一个代码目录, 服务器就会自动为他启动一个这个代码目录对应的docker容器。举一个

    基于docker容器alpine系统构建nginx+php+mariadb环境.zip

    软件开发设计:PHP、应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与学习资料 硬件与设备:单片机、EDA、proteus、RTOS、包括计算机硬件、服务器、网络设备、存储...

    基于Docker的一键LNMP安装程序

    DNMP(Docker + Nginx/Openresty + MySQL5,8 + PHP5,7...DNMP的集成使得用户可以快速搭建起一个完整的Web开发环境,支持Arm CPU架构的特性使得用户可以在不同的硬件平台上灵活部署应用,提升了开发效率和部署的灵活性。

    php-docker-dev:一个简单的基于DockerPHP开发环境,带有一些安装程序脚本

    适用于PHP开发人员的基于Docker的环境 一个简单的基于DockerPHP开发环境,带有* NIX的一些安装程序脚本。 如果您正在使用* NIX系统,并且只想使用WordPress开发主题,请考虑参考此仓库 要求 (用于跨平台运行脚本...

Global site tag (gtag.js) - Google Analytics