第13章 编程语言
本章主要介绍如何使用Docker快速部署主流编程语言的开发环境及其常用框架,包括C、C++、Java、PHP、Python、Perl、Ruby、JavaScript、Ruby等。其中,笔者将重点介绍常用Web编程语言PHP的Docker使用。
13.1 PHP
13.1.1 PHP技术栈
PHP是一种广泛使用的动态脚本语言,尤其适用于各种Web方案。由于PHP易于入门,易于维护的特性,它在国内外被大量的用于快速Web开发。即使随着网站PV/UV的增长,需要支持更大的并发的时候,基于原有PHP系统进行分层优化和业务整合也是相对容易的。PHP的哲学是quickand dirty(快速有效为先),任何对交付速度、灵活性甚至招聘成本有要求的创业团队,可以大胆地选择PHP。
下面,笔者将重点讲解PHP语言的Docker环境,并简述PHP主流MVC框架的Docker环境。
1.使用官方镜像
首先,下载PHP官方基础镜像。
$ sudo docker pull php
下载成功后,读者已经可以使用一个PHP容器去运行PHP程序/站点了。
第一步 如果读者需要以CLI(command line interface命令行)方式运行PHP脚本,可以按照以下步骤操作:
1)在PHP程序/站点的根目录中新建一个Dockerfile,内容为:
FROM php:5.6-cli
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
CMD [ "php", "./your-script.php" ]
2)然后运行以下命令去构建Docker镜像:
$ sudo docker build -t my-php-app .
3)最后执行以下命令去运行Docker镜像:
$ sudo docker run -it --rm --name my-running-app my-php-app
第二步 如果读者需要运行简单的,甚至单文件的PHP项目,那么每次都写Dockerfile会很麻烦。这种情况下,你可以用以下命令直接运行PHP脚本:
$ sudo docker run -it --rm --name my-running-script -v "$(pwd)":/usr/src/myapp -w /usr/src/myapp php:5.6-cli php your-script.php
第三步 通常情况下,PHP项目需要和Apache httpd/Nginx一起运行。这样就需要PHP容器中内含Apache Web Server。读者可以使用带有apache标签的镜像,如php:5.6-apache。
1)在读者的PHP项目的根目录中新建一个Dockerfile,并使用Docker Hub官方的基础镜像:
FROM php:5.6-apache
COPY src/ /var/www/html/
src/是当前包含所有PHP代码的目录。
2)使用此Dockerfile构建自定义镜像:
$ sudo docker build -t my-php-app .
3)创建并运行此镜像:
$ sudo docker run -it --rm --name my-running-app my-php-app
笔者建议加入一个自定义的php.ini配置文件,将其拷贝到/usr/local/lib。这样读者可以对PHP项目做更多的定制化,如开启某些PHP插件,或者对PHP解释器进行一些安全/性能相关的配置。
添加方法很简单:FROM php:5.6-apache
COPY config/php.ini /usr/local/lib/
COPY src/ /var/www/html/
注意 src/是当前存放PHP代码的文件夹,config/文件夹包含php.ini文件。
如果读者希望直接使用Docker Hub官方镜像运行PHP项目,可以执行:
$ sudo docker run -it --rm --name my-apache-php-app -v "$(pwd)":/var/www/html php:5.6-apache
Docker Hub中的优质PHP镜像很多,笔者特别推荐tutum团队发布的系列镜像(包括apache-php),具体地址可以在Docker Hub中搜索php或者tutum php,也可以参见资源章节
2.定制镜像
笔者首先推荐读者基于本书第10章提供的SSHD镜像进行自定义PHP镜像的制作,如此一来,读者可以方便地使用SSH服务连接PHP容器,即方便地运行容器中的PHP站点。
下面,笔者将带领读者从头操作一次。
第一步,下载PHP官方基础镜像:
$ sudo docker pull php Pulling repository docker/php 7a0d03c7b9dc: Download complete 511136ea3c5a: Download complete 36fd425d7d8a: Download complete aaabd2b41e22: Download complete 35a6381b9f4d: Download complete afcdff084bd7: Download complete 31d7cb82d7f6: Download complete 8859f0d2ad74: Download complete a50bbc401f05: Download complete 01a6ed55fbf9: Download complete 1a74afd35a74: Download complete da565d6c25d3: Download complete Status: Downloaded newer image for docker/php:latest 下载完成后,可以使用docker images查看PHP基础镜像是否安装完成: $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE docker/php cli 7a0d03c7b9dc 6 days ago 394.7 MB docker/php latest 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5-cli 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5.6 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5.6-cli 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5.6.2 7a0d03c7b9dc 6 days ago 394.7 MB docker/php 5.6.2-cli 7a0d03c7b9dc 6 days ago 394.7 MB 命令结果显示,PHP 5.6.2已经安装完成(5.6.2即为目前最新的PHP官方镜像标签)。 第二步,笔者将在Docker中运行一条PHP命令(CLI): $ sudo docker run -it docker/php Interactive shell php > 可见CLI可以直接输出。 $ sudo docker run -it php echo 'hello docker!' hello docker! 第三步,笔者将在Docker中运行一段PHP代码: 首先,读者需要确定当前目录位置,笔者使用pwd命令,创建一个sample目录: $ pwd /home/core $ mkdir sample $ cd sample 此时笔者已经确定在此目录是有读写权限的,下面使用Vim文本编辑器新建一个PHP文件: $ vim demo.php 此时会打开一个空文件,然后输入i进入Vim的编辑模式,输入一下代码: <?php class demo { function __construct() { echo 'Building Object.'; echo "\n"; }f unction hello_world() { print 'Hello World!'; } }$ demo_object = new demo(); $demo_object->hello_world(); ?> 下面,我们基于本书创建的sshd镜像,构建一个能够方便地运行PHP业务代码(非单个PHP CLI命令)的镜像: FROM sshd:dockerfile # 安装基础镜像 ENV DEBIAN_FRONTEND noninteractive RUN apt-get update && \ apt-get -yq install \ curl \apache2 \ libapache2-mod-php5 \ php5-mysql \ php5-gd \ php5-curl \ php-pear \ php-apc && \ rm -rf /var/lib/apt/lists/* RUN sed -i "s/variables_order.*/variables_order = \"EGPCS\"/g" /etc/php5/apache2/php.ini RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN echo "Asia/Shanghai" > /etc/timezone && \ dpkg-reconfigure -f noninteractive tzdata #注意这里要更改系统的时区设置, 因为在web应用中经常会用到时区这个系统变量, 默认的ubuntu会让你的应用程序发生不可思议的效果哦 # 添加我们的脚本, 并设置权限, 这会覆盖之前放在这个位置的脚本 ADD run.sh /run.sh RUN chmod 755 /*.sh # 添加一个示例的php站点, 删掉默认安装在apache文件夹下面的文件, 并将我们添加的示例用软链接链到/var/www/html目录下面 RUN mkdir -p /var/lock/apache2 &&mkdir -p /app && rm -fr /var/www/html && ln -s /app /var/www/html COPY sample/ /app # 设置apache相关的一些变量, 在容器启动的时候可以使用-e参数替代 ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_SERVERADMIN admin@localhost ENV APACHE_SERVERNAME localhost ENV APACHE_SERVERALIAS docker.localhost ENV APACHE_DOCUMENTROOT /var/www # 使用80端口 EXPOSE 80 WORKDIR /app CMD ["/run.sh"] run.sh文件内容如下: #!/bin/bash /usr/sbin/sshd -D & chown www-data:www-data /app -R source /etc/apache2/envvars exec apache2 -D FOREGROUND 然后,构建此镜像: $ sudo docker build -t my-php:dockerfile . sudo docker build -t php . Sending build context to Docker daemon 7.68 kB Sending build context to Docker daemon Step 0 : FROM sshd ---> 2e89cae5f1b6 Step 1 : ENV DEBIAN_FRONTEND noninteractive ---> Using cache ---> cfdf02ec333c Step 2 : RUN apt-get update && apt-get -yq install curl apache2 libapache2-mod-php5 php5-mysql php5-gd php5-curl php-pear php-apc && rm -rf /var/l http://www.hzcourse.com/resource/readBook?path=/openresources/teach_ebook/uncompressed/15029/OEBPS/Text/... Removing intermediate container 6273e14f6a91 Successfully built bdb6460f17d7 构建镜像成功后,运行此镜像: $ sudo docker run -d -P php 55745292b34cb085fbf2425988d00a51c451c79071f0929f2ca4943d93e33dad 查看是否启动成功: $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 55745292b34c php:latest "/run.sh" 3 seconds ago Up 2 seconds 0.0.0.0:49159->22/tcp, 0.0.0.0:49160->80/tcp happy_blackwell 使用49160端口可以打开php页面,使用49159端口可以打开ssh服务。 $ curl 127.0.0.1:49160/demo.php Building Object. Hello World! 我们还可以通过浏览器访问http://宿主主机ip:49160来访问我们的示例程序,如图13-1所示。如果读者遇到命令行报错:ssh:connect to host coreos-ip port 10123:Connection refused,则请检查SSH连接所需的RSA密钥是否生成正确。
13.1.2 PHP常用框架
PHP MVC框架资源非常丰富。常用的Web解决方案中涉及的有Zend、Yii、CakePHP、ThinkPHP、CodeIgniter、Lavarel等。笔者将以CakePHP框架为主,其他框架为辅,阐述Docker的各种使用
方法。
1.CakePHP
CakePHP是Rails风格的全栈开源MVC框架(此处的全栈Full-stack Framework,是相对于Yaf这类微框架micro-framework而言的),CakePHP提供了完整的高级框架所需提供的所有组件,如脚手架(代码生成器)、模板引擎、功能全面的ORM,完整的面向对象的封装(包括CakeRequest、AppModel、AppController等)。CakePHP社区完善,企业级使用者众多,是优秀的快速开发框架。
使用官方镜像的方法如下。
第一步,下载Docker Hub镜像:
$ sudo docker pull vcarl/cakephp
第二步,使用docker run命令运行CakePHP容器:
$ sudo docker run -d -p 80:80 -p 443:443 -v /path/to/project:/var/www/html vcarl/apache
注意,/path/to/project不能指向app/文件夹内部,而应该指向项目根目录。
第三步,打开浏览器,打开localhost:80查看运行结果,如图13-2所示。
如果读者需要运行现有CakePHP项目,则可以选择使用上文的实战演练中的方法——基于第10章的SSHD镜像,自定义Dockerfile后,构建CakePHP镜像。这样可以方便地使用SSH服务连接CakePHP镜像。当然,读者也可以到Docker Hub自行搜索CakePHP第三方镜像。
2.Zend
Zend Framework(ZF)是用PHP 5来开发Web程序和服务的开源框架。ZF用100%面向对象编码实现。ZF的组件结构独一无二,每个组件几乎不依靠其他组件。这样的松耦合结构(use-at-will)可
以让开发者独立使用各种组件。正确使用Zend Framework可以保持良好的代码结构和高可维护性,即使是规模庞大的Web项目。Zend框架是PHP Web方案的常用选型之一。它比较适合业务逻辑复杂,
并且对拓展性、稳定性要求较高的中大型Web项目。
使用Zend Framework最简单的方式是安装Zend Server。下面笔者将介绍Zend Server及其Docker化部署。
Zend Server是针对于关键Web业务的Web应用服务器,适合企业级解决方案。笔者在此简略介绍一下Zend Server的特性:
·企业级PHP:一款最新的,经受测试以及支持PHP堆栈的服务器,它可以确保应用程序的高可靠性、提高应用程序的安全性以及效率。
·使部署更有信心:在开发中使用一个完整的和一致的环境,这样在部署过程中读者可以消除许多测试和运行所遇到的问题。·快速问题响应:利用先进的应用程序监测和诊断,能及早发现问题并能快速分析问题的根源。
·最好的应用性能:内置的优化和加速功能,确保了高性能和低资源利用率。
·代码加速:PHP的字节码缓存提高性能而没有使应用程序发生变化。
·完全页面缓存:以URL为基础的HTML输出缓存,它不需要任何应用程序的变。
·部分页面缓存:它允许开发人员能够在共享内存或磁盘中缓存数据。
使用官方镜像
Zend Server在Docker Hub上以php-zendserver的名称标示。首先,我们下载Zend Server的Docker Hub官方镜像:
$ sudo docker pull php-zendserver
如果读者对Zend Server的版本有要求,可以在以上命令中加入Tag标签,以便于在下一步的Dockerfile的FROM指令中明确Zend Server版本号。官方镜像都有明确的标签列表,具体地址可以参见后
面“相关资源”部分。
创建并运行单个Zend Server容器:
$ sudo docker run php-zendserver
注意以下几点:
1)如果你对PHP和Zend Server的版本都有要求,可以在docker run命令中加入::<php-version>或者:<ZS-version>-php<version>。目前可供使用的PHP版本有5.4和5.5(默认),Zend
Server版本为7(如:php-zendserver:7.0-php5.4)。
2)如果需要使用特定版本的Zend Server,也可以选择直接下载此版本的镜像:
Zend Server 5.4Docker官方镜像:docker pull zend/php-5.4-zend-server
Zend Server 5.5Docker官方镜像:docker pull zend/php-5.5-zend-server
3)如果读者需要搭建一个Zend Server集群,并在每个Zend集群节点(即Cluster Node)都使用来自官方镜像的Zend Server容器,那么可以在每个节点执行:
$ sudo docker run -e MYSQL_HOSTNAME=<db-ip> -e MYSQL_PORT=3306 -e MYSQL_USERNAME=<username> -e MYSQL_PASSWORD=<password> -e MYSQL_DBNAME=zend php-zendserver
如果读者需要执行自定义操作,可以自定义Dockerfile,以生成自定义的镜像,步骤如下:
1)修改Dockerfile,加入定制内容。在含有Dockerfile的根目录执行以下语句构建镜像:
$ sudo docker build .
执行完毕后,命令行会输出镜像的ID(image-id)。
2)通过镜像ID,启动单个Zend Server容器:
$ sudo docker run <image-id>
如果读者需要搭建一个Zend Server集群,并在每个Zend集群节点(即Cluster Node)都使用来自自定义镜像的Zend Server容器,那么读者可以在每个节点执行:
$ sudo docker run -e MYSQL_HOSTNAME=<db-ip> -e MYSQL_PORT=3306 -e MYSQL_USERNAME=<username> -e MYSQL_PASSWORD=<password> -e MYSQL_DBNAME=zend <image-id>
注意以下几点:
1)当运行多个容器(即Instance实例)时,只有一个实例只可以绑定至一个端口(命令中的port)。如果需要运行一个集群,可以有两个做法:a)将不同的若干端口分别定向至各个节点。b)将不
同的若干端口分别定向至各个容器。
2)使用环境变量。使用预定义的管理员用户名密码启动Zend Server:-ZS_ADMIN_PASSWORD。集群操作中的MySQL变量(以下指令都是节点正常加入集群所必须的):
·MYSQL_HOSTNAME:MySQL数据库的ip或hostname。
·MYSQL_PORT:MySQL监听的端口。
·MYSQL_USERNAME-MYSQL_PASSWORD-MYSQL_DBNAME:集群操作时Zend Server使用的数据库用户名密码(如果不存在将会新建)。
3)ZEND_LICENSE_KEY-ZEND_LICENSE_ORDER:使用已购买的许可证。
4)每个Zend Server的Docker容器至少需要1GB的可用内存。
3.Symfony
Symfony是一个优秀的以依赖注入为核心的全栈式PHP MVC开发框架。它以设计完善和性能优越著称。它提供模板系统,数据持久层,代码生成器,以及大量可复用的功能集合(Bundle)。同
时,Symfony以依赖注入的方式给开发者提供了近乎无限的扩展性。
使用Docker Hub镜像
运行Symfony最简便的方法是去Docker Hub直接搜索相关关键字并直接下载Symfony镜像:
$ sudo docker pull gregory90/php-symfony
或者
$ sudo docker pull teamrock/symfony2
由于这种方式有一定局限性,对于需要执行已有Symfony项目的用户并不实用,所以读者也可以如下文所示定制镜像。
定制镜像
读者可以基于SSHD镜像定制,也可以使用以下Dockerfile来定制镜像:
# 获取Apache基础镜像
FROM teamrock/apache2:production
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y php5-imagick php5-gd php5-intl php5-mcrypt php5-apcu php5-curl php5-mysql
# 添加vhost配置
ADD ./virtual-host.conf /etc/apache2/sites-enabled/0-virtual-host.conf
# 添加安装脚本
ADD ./run.sh /tmp/run.sh
# 设置启动脚本
ENTRYPOINT [ "/bin/bash", "/tmp/run.sh" ]