Docker部署LNMP完整教程

在Docker中部署LNMP环境可以分为以下几个步骤:

  1. 安装Docker
  2. 创建镜像
    1. 创建Dockerfile
    2. build Docerfile
    3. 复制/修改配置文件
  3. 运行镜像,并映射端口

为了方便分布式部署,Nginx、PHP、MySQL和Web目录会分别放在4个不同的容器中,最后我们会打包成4个镜像。

1 安装docker和docker-compose

具体安装步骤不作说明,详细步骤请参考:https://docs.docker.com/engine/installation/

Docker安装要求Linux 3.10以上版本,注意这一点就可以了。

安装之后,用这个命令查看版本:

$ yum install docker-io docker-compose
$ docker -v

1.1 镜像仓库

Nginx、PHP、MySQL在Docker官方都提供现成的镜像仓库,这些我们是可以直接使用的,各个仓库地址如下。

1.2 Dockerfile文件

Dockerfile 文件类似 Makefile,只是前者根据规则部署容器,后者根据规则编译项目。

Dockerfile规则请参考:https://docs.docker.com/engine/reference/builder/

接下来每个程序的部署都会用到Dockerfile,所以一定要提前了解每个命令的功能。

2 部署MySQL

因为安装MySQL相对简单,所以我们从MySQL开始。

从Docker的公共仓库 Dockerhub 下载 MySQL 镜像:

$ docker pull mysql

然后启动数据库:

$ docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql

就完成了MySQL的安装,接下来我们再在PHP-FPM容器中使用。

3 部署Nginx

安装Nginx

首先,从Docker的公共仓库 Dockerhub 下载nginx镜像:

$ docker pull nginx

这个命令会下载容器需要的所有部件,并且Docker会对它们进行缓存,所以在运行容器的时候,不需要每次都下载容器镜像。

然后,启动Nginx容器:

$ docker run --name nginx -p 80:80 -d nginx

运行成功后,终端会返回容器的ID号,上面的命令中,

  • run:创建一个新的容器
  • --name:指定容器的名称(如果留空,docker会自动分配一个名称)
  • -p:导出容器端口到本地服务器,格式:-p <local-port>:<container-port>。在本例中,我们映射容器的80端口到本地服务器的80端口。
  • nginx:是 Dockerhub 上下载nginx镜像名称(如果本地没有可用的镜像,Docker会自动下载一个)
  • -d:后台启动。

通过浏览器浏览:http://localhost 就会看到Nginx欢迎界面。接下来可能会用到这几个命令:

$ docker ps -a                       # 查看正在运行的容器
$ docker stop nginx                  # 停止正在运行的容器
$ docker start nginx                 # 启动一个已经停止的容器
$ docker rm nginx                    # 删除容器

映射HTML路径

默认情况下,Docker nginx服务器的HTML路径(网站根目录)在容器 /usr/share/nginx/html 目录下,现在需要把这个目录映射到本地服务器的 ~/www/html 目录。在上面命令的基础上加上-v参数,具体如下:

$ docker run --name nginx -p 80:80 -d -v ~/www/html:/usr/share/nginx/html nginx

 -v的参数格式为:<local-volumes>:<container-volumes>

在~/www/html下创建一个 index.html 文件,内容

here is ~/www/html/index.html

在浏览器上访问 http://localhost,刷新一下就可以看到新的内容了。

配置 Nginx

Nginx 的强大很大部分体现在配置文件上,对于一些高级的应用来说,自定义 Nginx 非常重要。所以,我们需要把 Nginx 的配置文件复制到本地服务器目录:

$ cd ~/www
$ docker cp nginx:/etc/nginx/conf.d/default.conf default.conf

再加一个-v参数,把本地的配置文件映射到容器上,在重启容器:

$ docker stop nginx
$ docker rm nginx
$ docker run --name nginx -p 80:80 -v ~/www/html:/usr/share/nginx/html -v ~/www/default.conf:/etc/nginx/conf.d/default.conf -d nginx

如果配置文件有修改,需要重启容器生效:

$ docker restart nginx

这样就可以直接在本地修改配置文件了。

4 部署PHP-FPM

下载 PHP-FPM 镜像:

$ docker pull php:fpm
$ docker run --name php-fpm -p 9000:9000 -d php:fpm
$ cd ~/www
$ docker cp php-fpm:/usr/local/etc/php-fpm.d/www.conf www.conf
$ docker cp php-fpm:/usr/src/php/php.ini-production php.ini

在本地服务器修改 php.ini 的内容,设置cgi.fix_pathinfo=0(要先删除前面的;注释符):

cgi.fix_pathinfo=0

然后重新启动容器:

$ docker stop php-fpm
$ docker rm php-fpm
$ docker run --name php-fpm --link mysql:mysql -v ~/www/html:/var/www/html -v ~/www/www.conf:/usr/local/etc/php-fpm.d/www.conf -v ~/www/php.ini:/usr/local/etc/php/php.ini -d php:fpm

这样PHP-FPM的容器就部署完成了。注意,要保证配置文件 php.ini 和 www.conf 没有错误,否则会无法启动容器。

5 让Nginx容器支持FPM

打开 nginx 的配置文件,修改内容如下:

server {
    listen       80;
    server_name  _;
    root /usr/share/nginx/html;
    index index.php index.html index.htm;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        #root   /usr/share/nginx/html;
        #index  index.php index.html index.htm;
	try_files $uri $uri/ =404;
    }

    error_page  404  /404.html;
    location = /40x.html {
        root    /user/share/nginx/html;     
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        fastcgi_pass   php-fpm:9000;
        fastcgi_index  index.php;
#        fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /\.ht {
        deny  all;
    }
}

然后启动 nginx:

$ docker run --name nginx -p 80:80 --link php-fpm -v ~/www/html:/usr/share/nginx/html -v ~/www/default.conf:/etc/nginx/conf.d/default.conf -d nginx

在 ~/www/html 下创建 index.php 文件,内容:

<?php
    phpinfo();
?>

 

参考资料:

  1. docker-lnmp: Dockerfiles for deploying applications of apporz.com anywhere
  2. How To Run Nginx in a Docker Container on Ubuntu 14.04
  3. Legacy container links
  4. How To Install Docker on CentOS 6

38 条评论

Y
Y小聪 says: 回复

docker run –name php-fpm -p 9000:9000 -d -v php:fpm
docker cp php-fpm:/usr/src/php/php.ini-production php.ini 这两句有问题

歪麦 says: 作者

什么问题呢?

蓝胖子 says:

docker run –name php-fpm -p 9000:9000 -d -v php:fpm 这一句好像多了一个-v
docker cp php-fpm:/usr/src/php/php.ini-production php.ini 这一句 php.ini-production此文件不存在 不知道是不是版本原因

Y
Y小聪 says: 回复

docker run –name php-fpm -p 9000:9000 -d -v php:fpm -v在这里会报错

docker cp php-fpm:/usr/src/php/php.ini-production php.ini 会报以下错误:

Error response from daemon: lstat /var/lib/docker/devicemapper/mnt/dec7ffb3e643f6e8779b03fd72f35559291fef510d7a40aefab38ce2
d723d512/rootfs/usr/local/etc/php/php.ini: no such file or directory

r
riven says:

/usr/local/etc/php/php.ini-production 这才是容器内的路径

c
copriwolf says: 回复

发现有几个问题:
1、docker run –name php-fpm -p 9000:9000 -d -v php:fpm 这里多了一个-v
2、事实上,php-fpm应该要跟nginx的网站目录地址保持一致,这里会导致docker run之后拿不到数据
3、docker cp php-fpm:/usr/src/php/php.ini-production php.ini 好像会拿不到文件,我是用php:5.6-fpm

歪麦 says: 作者

好的

一克拉的灵魂 says:

进去php容器后:要对 php.tar.xz 解压,才能获取到php.ini-production,然后拷贝到本地,然后在映射:php.ini. 是这样的吧?

歪麦 says: 作者

docker pull php:fpm会生成php.ini-production

c
coder says: 回复

教程很不错。 但是最后问题跟上面差不多,我查了其他资料,发现
1:配置文件中 fastcgi_pass php-fpm:9000; 改成 ip地址:9000; ip地址由命令docker inspect –format='{{.NetworkSettings.IPAddress}}’ myphp 获取 myphp是name
2:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;改为fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
改了这两个地方就可以了,之前访问php文件就404,运行nginx时我去掉了 –link php-fpm , 因为会报错 (Could not get container for php-fpm.
),但是结果好像没有影响。 刚入门,不懂深入的原理,望指教

一克拉的灵魂 says:

进去php容器后:要对 php.tar.xz 解压,才能获取到php.ini-production,然后拷贝到本地,然后在映射:php.ini.
root@4097a160025c:/usr/src# ls
php-5.6.33 php.tar.xz php.tar.xz.asc
root@4097a160025c:/usr/src# mv php-5.6.33/ php
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name 其中document_root可以直接用。但是在nginx配置 server端指定:root /usr/share/nginx/htmle.和run php-fpm的时候 也要映射本地和这个root地址。
2种方式都可以。

阿斯科马 says:

php-fpm容器和nginx容器的 挂载项目目录要一样的吧! 都改成:/usr/share/nginx/html,这样就可以解析PHP文件了!

h
hopper says:

在评论区找到解决办法,这个问题困扰我好几天了,感谢coder

d
datou says:

是这样吗 fastcgi_pass 127.0.0.1:9000;

s
summer says:

我的问题跟你的一样也是404,根据你的方案并没有解决这个问题,你可不可以帮我看看怎么回事?万分感谢!

阿军 says:

nginx配置文件location那块,一开始root设置成nginx根目录/usr/share/nginx/html。心想配置nginx容器的时候这个根目录映射地址和phpfpm映射的地址是一样的。就没想那么多,调了很久,一直都是No input file specified。后来location中的root设置成php的根目录/var/www/html后,可以了。
贴出我的配置如下:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
#root /usr/share/nginx/html;
root /var/www/html;
fastcgi_pass myphpfpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
其中myphpfpm是我容器的名称,也可以替换成ip地址。通过docker inspect myphpfpm | grep “IPAddress”查询。
具体为啥这样配置,我也不知道,/捂脸。

王大锤 says:

我的是只改第二个就可以了。

c
cynen says:

–link 的作用是在 nginx容器的hosts文件中添加一个映射 php-fpm –》 ip地址。 将php-fpm的ip做一个映射,所以在链接的时候,我们使用 php-fpm 其实就是主机名,替代了ip。

但是你直接使用ip:9000 所以,就不需要这个link 参数了。当然也就没有影响了

x
xuthus says: 回复

万分感谢 一步到位 中间两个步骤有点问题 就是关于加-V和php.ini的问题 这个自己稍微注意一下就可以了

d
datou says: 回复

请问 为啥 我没有 Nginx 配置目录呢
$ docker cp nginx:/etc/nginx/conf.d/default.conf default.conf
Error response from daemon: not a directory

一克拉的灵魂 says:

容器名称对吗?

歪麦 says: 作者

那就改用完整的目录呗

d
datou says: 回复

真不知道 为啥 我的就
403 Forbidden
nginx/1.13.9

歪麦 says: 作者

这是Nginx配置或代码错误

s
summer says: 回复

博主你好!为什么我安装的以后访问php文件的时候,是No input file specified.

歪麦 says: 作者

估计是路径配置的问题,从github下拉一份试试。

l
liyangcoder.com says: 回复

4 部署PHP-FPM
$ docker run –name php-fpm -p 9000:9000 -d -v php:fpm

多了一个-v

歪麦 says: 作者

多谢提醒,已处理

k
kaufu says: 回复

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d1ed3710069 php:fpm “docker-php-entrypoi…” 9 minutes ago Up 9 minutes 0.0.0.0:9000->9000/tcp php-fpm
3b1c61ecedbc mysql “docker-entrypoint.s…” 12 minutes ago Up 12 minutes 0.0.0.0:3306->3306/tcp mysql
3bc9d1140a33 nginx “nginx -g ‘daemon of…” 15 minutes ago Up 15 minutes 0.0.0.0:80->80/tcp nginx

为啥nginx、php-fpm、mysql三个容器启动后,要attach进去一直卡在那条命令上,
[root@kaufu www]# docker attach 7d1ed

用exec进入也是卡在那不动

用docker logs查看日志显示
[root@kaufu www]# docker logs 7d1ed
[10-Aug-2018 08:20:17] NOTICE: fpm is running, pid 1
[10-Aug-2018 08:20:17] NOTICE: ready to handle connections

求大神帮帮忙,进去一个centos容器是没问题的

歪麦 says: 作者

用docker ps看看,容器应该都启动了吧

h
hu says: 回复

按照您的流程走下来 访问 netstat -apn|grep 9000 ,没有任何输出,页面也是404,一直无法解决,求助

歪麦 says: 作者

9000只是容器中用,host不会用到的,404说明index.php文件不存在,重新从github拉一份试试。

says: 回复

我在docker swarm集群中编排nginx 和php
但是一直解析不到php的IP地址
一直提示nginx.conf 中 fastcgi_pass php-fpm:9000; php-fpm host not found
求教

新手 says: 回复

非常感谢楼主,按照教程弄完了,除了个小问题,也按照评论处理了。目前遇到一个问题,就是访问index.php后,是两个请求,一个是200,一个是404. 希望楼主能够更新一下教程。

新手报到 says: 回复

有index.html文件访问IP显示404,有index.php访问 ip/index.php 显示File not found 哪位大牛帮帮忙

阿川 says: 回复

请问composer在宿主机不能使用是怎么回事?

[ErrorException]
touch(): Unable to create file /tmp/composer/config.json because Permission denied

小小一兆 says: 回复

[root@Docker-231 ~]# docker run –name php-fpm –link mysql:mysql -v ~/www/html:/usr/share/nginx/html -v ~/www/www.conf:/usr/local/etc/php-fpm.d/www.conf -v ~/www/php.ini:/usr/local/etc/php-8.0.3/php.ini -d php:fpm
b2919d9d7ceb4c28e0ba329097fc0529d4007f387265e572c6dfa11e5bfd2ede
docker: Error response from daemon: Cannot link to a non running container: /mysql AS /php-fpm/mysql.

小小一兆 says:

这个错误困扰我好几天了,哪位大佬解答一下,谢谢了!在校学生做的毕设,实在是搞不明白,查了很多资料了

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

昵称 *