阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

基于Docker的PHP开发环境

456次阅读
没有评论

共计 7080 个字符,预计需要花费 18 分钟才能阅读完成。

【编者的话】本文作者是 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 工程. 推荐的方法是用 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

帅呆了!下面来点实在的工作。(省略了博主自娱自乐的一堆 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 -'s/;daemonize = yes/daemonize = no/' -/etc/php5/fpm/php-fpm.conf
RUN sed -'s/;listen\.owner/listen.owner/' -/etc/php5/fpm/pool.d/www.conf
RUN sed -'s/;listen\.group/listen.group/' -/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 -'s/;daemonize = yes/daemonize = no/' -/etc/php5/fpm/php-fpm.conf
RUN sed -'s/;listen\.owner/listen.owner/' -/etc/php5/fpm/pool.d/www.conf
RUN sed -'s/;listen\.group/listen.group/' -/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=1while [[ RET -ne 0 ]]; do
    sleep 1;
    mysql -'exit' > /dev/null 2>&1; RET=$?done

DB_NAME=${DB_NAME:-symfony}

mysqladmin -u root create $DB_NAME

if [ -"$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 ----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 ----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 ---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) 800.0.0.0:49153

docker ps -aql 1 是个好用的命令,可以方便的检索到最后一个容器的 id,在我们的例子中,Docker 把容器的 80 端口映射到了 49153 端口。我们 curl 一下看看。

$ curl http://localhost:49153You 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/:

result.png

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

CentOS 6/ 7 系列安装 Docker http://www.linuxidc.com/Linux/2014-07/104768.htm

Docker 的搭建 Gitlab CI 全过程详解 http://www.linuxidc.com/Linux/2013-12/93537.htm

Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm

在 Docker 中使用 MySQL http://www.linuxidc.com/Linux/2014-01/95354.htm

在 Ubuntu Trusty 14.04 (LTS) (64-bit)安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm

Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm

Ubuntu 14.04 安装 Docker  http://www.linuxidc.com/linux/2014-08/105656.htm

阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm

Docker 的详细介绍:请点这里
Docker 的下载地址:请点这里

原文:http://geoffrey.io/a-php-development-environment-with-docker.html 作者:Geoffrey
译文:http://dockerone.com/article/117 译者:何林冲

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-01/111302.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计7080字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19350
评论数
4
阅读量
7959446
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

  星哥带你玩飞牛 NAS-16:不再错过公众号更新,飞牛 NAS 搭建 RSS 对于经常关注多个微...
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸 前言 作为天天跟架构图、拓扑图死磕的...
星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛 NAS-4:飞牛 NAS 安装 istore 旁路由,家庭网络升级的最佳实践 开始 大家好我是...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
安装并使用谷歌AI编程工具Antigravity(亲测有效)

安装并使用谷歌AI编程工具Antigravity(亲测有效)

  安装并使用谷歌 AI 编程工具 Antigravity(亲测有效) 引言 Antigravity...
仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

还在忍受动辄数百兆的“全家桶”监控软件?后台偷占资源、界面杂乱冗余,想查个 CPU 温度都要层层点选? 今天给...
每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年 0.99 刀,拿下你的第一个顶级域名,详细注册使用 前言 作为长期折腾云服务、域名建站的老玩家,星哥一直...
国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号 AI 知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率 大家好,我是星哥,...
星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

  星哥带你玩飞牛 NAS-16:不再错过公众号更新,飞牛 NAS 搭建 RSS 对于经常关注多个微...