首先还是从一个PHP在Docker容器下的Hello World实例开始。我们准备这样一个PHP文件`index.php`:
~~~
echo "PHP in Docker";
~~~
然后在同目录下创建文本文件并命名为`Dockerfile`,内容为:
~~~
# 从官方PHP镜像构建
FROM php
# 将index.php复制到容器内的/var/www目录下
ADD index.php /var/www
# 对外暴露8080端口
EXPOSE 8080
# 设置容器默认工作目录为/var/www
WORKDIR /var/www
# 容器运行后默认执行的指令
ENTRYPOINT ["php", "-S", "0.0.0.0:8080"]
~~~
构建这个容器:
~~~
docker build -t allovince/php-helloworld .
~~~
运行这个容器
~~~
docker run -d -p 8080:8080 allovince/php-helloworld
~~~
查看结果:
~~~
curl localhost:8080
PHP in Docker
~~~
这样我们就创建了一个用于演示PHP程序的Docker容器,任何安装过Docker的机器都可以运行这个容器获得同样的结果。而任何有上面的php文件和Dockerfile的人都可以构建出相同的容器,从而完全消除了不同环境,不同版本可能引起的各种问题。
想象一下程序进一步复杂,我们应该如何扩展呢,很直接的想法是继续在容器内安装其他用到的服务,并将所有服务运行起来,那么我们的Dockerfile很可能发展成这个样子:
~~~
FROM php
ADD index.php /var/www
# 安装更多服务
RUN apt-get install -y \
mysql-server \
nginx \
php5-fpm \
php5-mysql
# 编写一个启动脚本启动所有服务
ENTRYPOINT ["/opt/bin/php-nginx-mysql-start.sh"]
~~~
虽然我们通过Docker构建了一个开发环境,但觉不觉得有些似曾相识呢。没错,其实这种做法和制作一个虚拟机镜像是差不多的,这种方式存在几个问题:
- 如果需要验证某个服务的不同版本,比如测试PHP5.3/5.4/5.5/5.6,就必须准备4个镜像,但其实每个镜像只有很小的差异。
- 如果开始新的项目,那么容器内安装的服务会不断膨胀,最终无法弄清楚哪个服务是属于哪个项目的。