Bookmarks

You haven't yet saved any bookmarks. To bookmark a post, just click .

  • Docker 搭建 Nginx+MySQL+ PHP (LNMP)基础环境

  • 前言

    本文是 Docker 系列文章的第一篇,既是分享,也为备份。

    本系列文章内容将尽量简单清晰,突出实用性,目标是使每位读者只须少量 Linux 基础知识便能利用 Docker 的便利性解决自己的问题。

    本系列文章将包括以下内容:

    • Docker 搭建 nginx + MySQL + PHP (LNMP)基础环境

    • Docker 搭建主流博客平台 Wordpress 和 Ghost

    • Docker 搭建私有云 Nextcloud

    • Docker 搭建 Python 运行环境

    • Docker 跨服务器迁移

    若无特别说明,初次成文均使用 Ubuntu 18.04 LTS,但为了保证教程的适用性,在全部文章发布完成后本人将同时在 Ubuntu 16.04 LTS 以及 CentOS 7.5 等系统上进行测试,并对差异性的内容将单独列示。

    整体说明

    对多数使用 VPS 的朋友而言,除了某种不可描述的用途之外,最大的价值便是搭建个人网站或者其他实用服务,但对多数 Linux 系统知识有限的朋友来说,自己搭建网站运行环境并非易事。LNMP 一键安装包便是在这样的环境下诞生的,一行代码,Nginx + MySQL + PHP 环境就能搭建起来,非常方便实用。

    在 Docker 开始流行之后,很多朋友便希望能够在 Docker 中使用 LNMP,搜索 Docker LNMP 等关键字也有很多结果,但在参考了许多做法后,并没有找到兼俱简单实用的解决方案。

    实际上要实现 LNMP 的功能并不复杂,不需要任何复杂配置,只需要单独安装各个容器,并解决不同容器之间的通信即可。在通过参考官方文档以及多次测试后,在这里分享一下本人的解决办法,供各位参考。

    在 LNMP 环境搭建过程中,主要基于以下几个方面考虑:

    • 尽量使用官方镜像
    • 尽量少需要手工配置
    • 保证各容器之间相互独立
    • 能够方便的进行版本变更
    • 能够方便的实现功能扩展

    同时,本解决方案基于渐进式思维,以实现应用正常运行为第一目标,之后进行容器卷配置实现数据的持久化存储和配置文件的可配置,再之后测试增加其他容器或者其他方式实现功能扩展。

    整个配置过程解释清晰,无黑箱,不涉及任何复杂操作,简单易行。

    强烈建议安装 Portainer 进行可视化的操作和查看

    必要前置知识:Docker 容器通信

    本部分的内容可以选择跳过,它存在是为了让你能够更好的理解下文内容。由于相关知识内容过多,本部分不会过多阐述,有兴趣的可以自行搜索进一步了解

    在使用 Docker 之前多数朋友应该接触过一键安装包,可使用 Docker 之后,事情似乎开始变得棘手,直接安装 Ngnix + MySQL + PHP-FPM 你得到的仅仅是三个没有关联的容器。那如何让这几个容器进行有效通信来让他们协调起来实现让应用运行起来的目的,这就需要了解容器通信相关的知识。

    关于 docker0 和 bridge

    Docker 容器网络模式包括桥接模式(bridge)、主机模式(host)、中继模式(overlay)等,但大多数时候我们只使用默认的桥接模式(bridge),本文也只涉及默认的桥接模式(bridge)。

    注意,这里的 bridge 容易有歧义,bridge 一般是指一种网络模式即桥接,但 Docker 默认的桥接网络也直接命名为 bridge,除了默认的 bridge 桥接网络,我们也可以新建其他名称的桥接网络,为了避免歧义,当我们直接使用 bridge 时,均指特定的桥接网络 bridge。

    Docker 会在宿主机上创建一个名称为 docker0 的桥接网络,这个网络将会是容器的默认网络,通过在宿主机上运行 ifconfig docker0 你将看到这个网络的具体信息:

    docker-lnmp-docker0.png

    如上图所示,在测试服务器上,docker0 网络的网关为172.17.0.1,子网掩码为255.255.0.0。

    docker0 的存在便是容器与宿主机之间通信的关键,容器默认加入的网络 bridge 便是 docker0,我们可以通过 Docker 的相关命令来查看一下这个 bridge 网络:

    docker network inspect bridge
    

    docker-lnmp-bridge.png

    从图中可以看到 docker0 和 bridge 实际是同一网络,在这一网络中的容器与宿主机在同一子网下,可以直接通过 IP 互相通信。

    检测容器联通性

    我们对容器与宿主机以及容器之间的联通性进行测试,下面是方法:

    • 进入容器内终端:
    docker exec -it nginx /bin/bash
    
    • 安装 ping
    apt-get update
    apt-get install iputils-ping
    
    • 使用 ping

    docker-lnmp-ping.png

    使用自定义网络

    Docker 支持用户手动创建网络,以及手动将容器加入某个网络,同一容器可以加入多个网络,获得多个 IP 地址。

    我们创建一个网络,并将现有容器加入:

    docker network create test
    docker network connect test portainer
    docker network connect test nginx
    

    我们成功的创建了网络 test,并将现有容器 portainer 和 nginx 加入了其中,我们可以通过 docker inspect CONTAINER 命令来查看容器信息,可以看到两个容器分别获得了 172.18.0.2 和 172.18.0.3 的IP,他们之间可以通过这一子网进行通信了。

    所以,综上所述,通过加入相同子网(默认的bridge或者自定义子网)可以实现容器间的通信,通过加入bridge子网则可以实现容器与宿主机的通信。

    更多相关命令可以通过 docker 命令的 help 自行查询

    使用容器名通信

    在前面内容中,我们一直提到的是使用 IP 通信,但容器的 IP 地址并非一成不变的,容器关闭的情况下,容器 IP 可能会被其他新建容器占用,所以直接使用容器名通信似乎是更好的选择。

    但要实现容器名通信存在一定的限制条件: 两个容器在除bridge外的相同子网内或者两个容器通过--link命令进行了链接

    不过 Docker 官方文档已经明确提出 --link将在未来版本中移除,鼓励使用自定义网络来实现用户间的通信,并指出例如共享环境变量这样可以通过--link实现而无法通过自定义网络实现的功能则推荐使用volumes的方式解决。

    docker-lnmp-link.png

    --link 实现名称访问的原理是通过修改容器内的 hosts 文件,比如容器A --link 容器B,这时 Docker 就会修改容器 A 的 hosts 文件,将容器 B 及对应的 IP 添加进去。但使用 --link 会造成容器之间的绑定,前面的例子中,若删除容器B,容器A将无法运行,即使重新创建一个相同名称的容器B,容器A仍然无法运行,这显然是我们不想看到的。

    还要提到一点是,通过 docker-compose 创建的 stack,会同时创建一个自定义网络, stack中的所有容器均会加入该网络,但他们默认将不会加入 bridge 网络,所以无法与主机直接通信,但我们仍然可以通过命令手动将其中某个或全部容器加入 bridge 网络,但大部分时候并不会有这个需求。

    总结

    • 容器间通信:如果在同一子网,可以通过 IP 互相通信,如果不在同一子网,则可以通过加入相同子网实现 IP 互相通信,如果需要通过容器名通信,需要加入除 bridge 外的相同子网;

    • 容器与宿主机通信:将容器加入bridge网络后即可与宿主机通信,宿主机 IP 即为 bridge网络网关地址。


    初步实现

    本部分的目标很明确,就是不考虑其他因素,实现“让应用跑起来”的目标。

    我们要使用的容器包括以下几个:

    容器名 所用镜像 说明
    nginx nginx:latest 官方最新版本镜像
    mysql mysql:5.7 也可以使用 mariadb:10.2
    phpfpm php:7.2-fpm 可以使用已安装 mysql扩展的bitnami/php-fpm

    本文中使用的路径如下:

    • 网站主目录: ~/wwwroot
    • mysql root密码: root
    • nginx 配置文件目录: ~/docker/nginx
    • mysql 配置文件目录: ~/docker/mysql
    • php 配置文件目录: ~/docker/php

    由于直接使用root用户,所以~即为/root

    1. 获得 nginx 默认配置文件

    以下内容请分步执行

    docker run --name nginx -d nginx          #运行一个nginx容器
    mkdir ~/docker                            #创建容器配置文件夹
    docker cp nginx:/etc/nginx ~/docker       #复制nginx默认配置
    
    docker cp nginx:/usr/share/nginx/html ~   #顺便复制默认网站内容
    mv ~/html ~/wwwroot                       #更改文件夹名为wwwroot
    
    docker stop nginx                         #停止nginx容器
    docker rm nginx                           #删除nginx容器
    

    2. 分别运行各个容器

    • 运行 MySQL 容器
    docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d -p 3306:3306  mysql:5.7
    
    • 运行 nginx 容器
    docker run -d --name nginx \
    -v ~/docker/nginx:/etc/nginx \
    -v ~/wwwroot:/usr/share/nginx/html \
    -p 80:80 \
    -p 443:443 \
    nginx
    

    绑定了 nginx 配置文件和网站主目录,方便后续测试

    • 运行 PHP-FPM 容器
    docker run --name phpfpm -d -P \
    -v ~/wwwroot:/usr/share/nginx/html \
    php:7.2-fpm
    

    需要注意的是 PHP-FPM 容器的网站目录必须与 nginx 内的一致,否则会有不必要的麻烦
    另外这里使用了 PHP 官方的包,采用了7.2.12版本,各版本的 Tags 可以在官方Docker Hub页面中查询。

    3. 配置容器通信

    通过 docker ps 命令可以看到各容器都已经正常运行,在浏览器中输入服务器IP也能看到熟悉的 nginx 默认页面,下面的关键在于实现三个容器间的通信,解决如下问题:

    • 如何使用容器中的 PHP-FPM 来处理 PHP 页面
    • 如何连接到容器中的 MySQL 数据库

    为了方便下文内容,我们对各容器的IP情况进行一个汇总:

    容器名称 加入网络 IP地址
    mysql bridge 172.17.0.3
    nginx bridge 172.17.0.4
    phpfpm bridge 172.17.0.5

    直接查看 Portainer 界面更直观:

    docker-lnmp-containerlist.png

    通过参考前置知识中的内容,我们知道此时的宿主机 IP 为 172.17.0.1,各容器都可以通过这个 IP 与主机进行通信。

    配置 Nginx 连接 PHP-FPM

    为了测试 PHP 文件能否正常处理,我们在网站主目录中创建一个 test.php 文件:

    echo "<?php echo '<p>Hello World</p>'; ?>" > ~/wwwroot/test.php
    

    之后在浏览器中输入服务器IP/test.php,由于此时我们还未配置 nginx 如何处理 PHP 文件,不出意外的话浏览器将会直接下载该文件。

    我们进入 nginx 配置文件夹对配置进行修改

    cd ~/docker/nginx/conf.d
    

    如果担心修改出问题,可以先复制一份default.conf

    cp default.conf default.conf.bak
    

    之后使用 vim 修改 default.conf:

    docker-lnmp-nginx1.png

    修改的关键就是上面红色的内容,最关键的是这里的 fastcgi_pass 地址是什么,127.0.0.1肯定不正确,因为对nginx容器来说,127.0.0.1指的是容器内部的虚拟系统,通过参考前面的知识,我们知道这时有两种方法可以连接到 php-fpm:

    • 连接 PHP-FPM 容器的 9000 端口
    • 连接宿主机中 PHP-FPM 9000 端口所映射的端口

    这里我们采用第一种方式,即 172.17.0.5:9000,因为前面在创建 PHP-FPM 容器的时候并未映射固定端口,但如果你愿意给phpfpm映射一个固定端口的话,使用第二种方式也有优点,那就是宿主机的 IP 是不会变化的,没有需要修改配置文件的风险。

    所以 nginx 配置文件内容如下:

    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
        #error_page  404              /404.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;
        }
    
        # pass the PHP scripts to FastCGI server
        
        location ~ \.php$ {
            root           /usr/share/nginx/html;
            fastcgi_pass   172.17.0.5:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
    
    

    wq保存之后,重启一下 nginx 容器:

    docker restart nginx
    

    这时再用浏览器打开服务器IP/test.php,熟悉的 Hello World 就能正常显示了。

    docker-lnmp-success1.png

    配置及测试 MySQL 数据库连接

    此时如果你通过外部工具连接宿主机的 MySQL 数据库,实际上已经可以正常连接了,但在宿主机中的容器要连接这个 MySQL 则需要进行一点修改。

    本部分我们在测试 MySQL 数据库的连接的同时,搭建一个 phpMyAdmin ,毕竟phpMyAdmin 只是一个 PHP程序。

    • 下载 phpMyAdmin 到网站主目录
    wget https://files.phpmyadmin.net/phpMyAdmin/4.8.3/phpMyAdmin-4.8.3-all-languages.zip
    
    • 解压缩 phpMyAdmin 压缩包
    unzip phpMyAdmin/4.8.3/phpMyAdmin-4.8.3-all-languages.zip
    
    • 修改 phpMyAdmin 目录名称
    mv phpMyAdmin-4.8.3-all-languages phpmyadmin
    

    为了让 nginx 支持不同子目录的多个 PHP 程序,我们需要修改 nginx 配置文件:

    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
        #error_page  404              /404.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;
        }
    
        # pass the PHP scripts to FastCGI server
    
        location ~ \.php$ {
            root           /usr/share/nginx/html;
            fastcgi_pass   172.17.0.5:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
        location /phpmyadmin {
            root   /usr/share/nginx/html/phpmyadmin;
            index  index.html index.htm;
        }
    
        location ~ /phpmyadmin/(?<after_ali>(.*)\.(php|php5)?$){
            root           /usr/share/nginx/html/phpmyadmin;
            fastcgi_pass   172.17.0.5:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
    

    这里参考了linuxguy的nginx多动态目录配置文件。

    之后在浏览器打开 服务器IP/phpmyadmin/index.php,却发现报错:

    docker-lnmp-phpmyadmin-error.png

    查看 PHP 官方 Docker Hub 页面可知,为了减少体积并未包含大部分扩展。

    在这里举这个例子的目的也是在此,PHP 官方提供的 PHP-FPM 镜像缺少主要扩展,在应用过程中我们可能不得不使用 Dockerfile 添加所需扩展后手动编译,或者使用其他已编译好的包含扩展的镜像,我个人推荐自己添加需要的扩展后上传至 Docker Hub。

    因此我们不得不手动安装,我们参考官方页面提供的 Dockerfile 示例添加部分扩展,方法如下:

    在任意目录下创建一个 Dockerfile 文件并修改内容如下:

    FROM php:7.2-fpm
    RUN apt-get update && apt-get install -y \
    		libfreetype6-dev \
    		libjpeg62-turbo-dev \
    		libpng-dev \
    	&& docker-php-ext-install -j$(nproc) iconv \
    	&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    	&& docker-php-ext-install -j$(nproc) gd \
       && docker-php-ext-install mysqli pdo pdo_mysql
    

    之后我们构建一下我们的镜像:

    docker build -t myphpfpm-7.2 .
    

    我们给我们的镜像添加 Tag 为myphpfpm-7.2, 之后我们需要删除原来的 PHP-FPM 容器,之后再运行我们所构建的新的镜像:

    可以将自己制作的镜像上传 Docker Hub 方便日后直接使用,具体方式可自行搜索。

    docker stop phpfpm
    docker rm phpfpm
    
    docker run --name phpfpm -d -P \
    -v /root/wwwroot:/usr/share/nginx/html \
    myphpfpm-7.2
    

    之后重新从浏览器打开 phpmyadmin 地址服务器IP/phpmyadmin/index.php

    docker-lnmp-phpmyadmin-success1.png

    已经能够正常使用了,但我们输入用户名root和密码root之后,却报错了:

    docker-lnmp-phpmyadmin-error2.png

    我们需要将 phpmyadmin 默认的 Server host 由 localhost 修改为我们宿主机在容器中的IP,即 172.17.0.1

    前往 phpmyadmin 配置文件夹

    cd ~/wwwroot/phpmyadmin
    

    复制config.sample.inc.php并命名为 config.inc.php

    cp config.sample.inc.php config.inc.php
    

    修改内容如下:

    docker-lnmp-phpmyadmin-config1.png
    ==>
    docker-lnmp-phpmyadmin-config2.png

    聪明的读者一定知道,这里修改成MySQL容器 IP 172.17.0.3 也是可以的。

    之后使用MySQL账号密码就能顺利登录了:

    docker-lnmp-phpmyadmin-success2.png

    至此为止,我们已经完成了 Nginx+MySQL+PHP 的环境搭建,并掌握了这种模式下的使用方法,下面我们将实现数据的持久化存储和配置文件的可配置。


    进阶实现

    在上一部分中,我们已经完成了 Nginx+MySQL+PHP 环境的搭建,并能够正常运行 PHP 网站,但有很多细节我们没有考虑,比如:

    • 如何修改 PHP 配置
    • 如何修改 MySQL 配置
    • 如何配置 Nginx 网站的 SSL 证书
    • 如何避免因容器 IP 变化而需要修改配置

    等等。

    本部分内容将解决这些问题。

    持久化存储数据

    列举需要的文件

    上一部分我们已经在宿主机与容器间共享了部分文件夹,如网站目录、Nginx 配置目录等,因为这些是显而易见且会影响我们对容器的基本使用的,但实际上各容器需要共享的文件不止这些,下表是一个不完全统计,各位可以根据自己的需要修改。

    容器 需与宿主机共享内容 容器内文件路经 宿主机文件路经 绑定方式
    nginx 网站主目录 /usr/share/nginx/html ~/wwwroot 文件
    nginx 配置文件 /etc/nginx ~/docker/nginx 文件
    nginx 证书文件 /etc/letsencrypt /etc/letsencrypt 文件
    mysql 数据库文件 volume:mysql /var/lib/mysql volume
    mysql 配置文件 /etc/mysql ~/docker/mysql 文件
    phpfpm 配置文件 /usr/local/etc/php ~/docker/php 文件

    nginx 证书文件夹可自行指定,使用了 /etc/letsencrypt 文件夹是因为该文件夹是 Letsencrypt 自动申请的证书默认目录。

    重新运行容器

    我们需要由容器复制默认配置文件,再删除原有容器,之后加入新的文件绑定后重新运行容器:

    • 复制容器默认配置文件
    docker cp mysql:/etc/mysql ~/docker #复制 mysql 配置文件
    docker cp phpfpm:/usr/local/etc/php ~/docker #复制phpfpm配置文件
    
    • 删除所有容器
    docker stop nginx
    docker rm nginx
    docker stop mysql
    docker rm mysql
    docker stop phpfpm
    docker rm phpfpm
    
    • 重新运行 Nginx 容器
    docker run -d --name nginx \
    -v ~/docker/nginx:/etc/nginx \
    -v ~/wwwroot:/usr/share/nginx/html \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -p 80:80 \
    -p 443:443 \
    nginx
    

    关于挂载文件的方式,可以使用 -v,也可以使用 --mount,其差异性可以参考官方文档或者这里

    • 重新运行 MySQL 容器
    docker run -d --name mysql \
    -e MYSQL_ROOT_PASSWORD=root \
    -v ~/docker/mysql:/etc/mysql \
    -v mysql:/var/lib/mysql \
    -p 3306:3306 \
    mysql:5.7
    
    • 重新运行 PHP-FPM 容器

    记得使用我们前面使用 Dockerfile build的镜像

    docker run --name phpfpm -d -P \
    -v ~/wwwroot:/usr/share/nginx/html \
    -v ~/docker/php:/usr/local/etc/php \
    myphpfpm-7.2
    

    使用容器名通信

    在重新运行容器的过程中你会发现,Docker 会根据容器出现的先后顺序依次分配 IP,如果这一次你没有按照 nginx、mysql、phpfpm 的顺序依次运行容器,那么现在你的容器分配的 IP 已经发生了变化,之前的配置文件可能已经失效了,我们可以通过自定义网络的方式来解决这个问题。

    • 创建自定义网络 lnmp
    docker network create lnmp
    
    • 将各容器加入该自定义网络
    docker network connect lnmp nginx
    docker network connect lnmp mysql
    docker network connect lnmp phpfpm
    
    

    容器网络的创建与加入都可以通过 Portainer 可视化操作

    • 修改配置文件

    比如我们之前使用的 nginx 配置文件中,所使用的 172.17.0.5:9000,现在可以改写为phpfpm:9000,phpMyAdmin 配置文件中的 host 现在也可以修改为 mysql 了,可自行测试。

    到目前为止,我们基本已经完成了 Nginx+MySQL+PHP 环境的搭建,能够满足大部分需求,读者可以根据自己的需求,自由调整各容器,因为他们之间并无绑定关系,互相独立。

    如果使用自定义网络,则需要注意删除后再新建的容器,需要手动加入 lnmp 网络

    增加扩展

    由于整个环境的搭建并未对容器间进行绑定,因此要增加扩展非常容易,只需要运行容器,并配置容器通信即可,若需要使用容器名通过则将新增加的容器直接加入 lnmp 网络即可。下面以几个实际例子来看。

    使用 phpMyAdmin

    虽然前面我们已经通过手动安装 phpMyAdmin 实现了该功能,但这远没有直接运行一个容器来得方便,我们通过查看 phpMyAdmin 的官方 Docker Hub 页面,可以了解到通过参数可以实现不同的运行模式:

    docker-lnmp-phpmyadmin.png

    我们选择第三种,任意服务器模式:

    docker run --name myadmin -d -e PMA_ARBITRARY=1 -p 8080:80 phpmyadmin/phpmyadmin
    

    之后打开服务器端口:8080,就会出现一个可以输入服务器地址的 phpMyAdmin 界面:

    docker-lnmp-phpmyadmin2.png

    这个界面作为一个连接测试也是很好的,通过前面的知识我们应该知道,这里即可以输入
    172.17.0.4,也可以输入172.17.0.1,如果把 myadmin 容器加入 lnmp 子网,还可以直接在服务器栏输入 mysql,都可以正常连接,可自行测试。

    172.17.0.4 这一地址可以自行通过 Portainer 查看,或者使用 docker inspect命令查看:
    docker inspect mysql
    或者 docker inspect mysql | grep 'IPAddress'

    其他扩展

    待补充。


    脱水版本

    如果你只是想快速在服务器上搭建起一个 Nginx+MySQL+PHP 的运行环境来运行自己的PHP代码,不想了解细节内容,直接看这里就好。

    使用的容器名、镜像以及使用的文件绑定和volume等见下表,可参考自己配置修改下面内容:

    容器名 所用镜像 说明
    nginx nginx:latest 官方最新版本镜像
    mysql mysql:5.7 也可以使用 mariadb:10.2
    phpfpm php:7.2-fpm 可以使用已安装 mysql扩展的bitnami/php-fpm
    容器 需与宿主机共享内容 容器内文件路经 宿主机文件路经 绑定方式
    nginx 网站主目录 /usr/share/nginx/html ~/wwwroot 文件
    nginx 配置文件 /etc/nginx ~/docker/nginx 文件
    nginx 证书文件 /etc/letsencrypt /etc/letsencrypt 文件
    mysql 数据库文件 volume:mysql /var/lib/mysql volume
    mysql 配置文件 /etc/mysql ~/docker/mysql 文件
    phpfpm 配置文件 /usr/local/etc/php ~/docker/php 文件

    获取容器默认配置

    docker run --name nginx -d nginx          #运行一个nginx容器
    mkdir ~/docker                            #创建容器配置文件夹
    docker cp nginx:/etc/nginx ~/docker       #复制nginx默认配置
    
    docker cp nginx:/usr/share/nginx/html ~   #顺便复制默认网站内容
    mv ~/html ~/wwwroot                       #更改文件夹名为wwwroot
    
    docker stop nginx                         #停止nginx容器
    docker rm nginx                           #删除nginx容器
    
    docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d -p 3306:3306  mysql:5.7   #运行 mysql 容器
    docker cp mysql:/etc/mysql ~/docker #复制 mysql 配置文件
    
    docker stop mysql  #停止 mysql 容器
    docker rm mysql #删除 mysql 容器
    
    docker run --name phpfpm -d -P php:7.2-fpm    #运行 phpfpm 容器
    docker cp phpfpm:/usr/local/etc/php ~/docker  #复制 phpfpm 配置文件
    
    docker stop phpfpm  #停止 phpfpm 容器
    docker rm phpfpm #删除 phpfpm 容器
    

    重新运行各容器

    考虑到这是脱水版,本人已将编译完成的包括 mysqli 模块的 PHP-FPM 上传至 Docker Hub,可以直接 pull 使用,需要自己编译或者出现自己需要的模块未安装的情况请参考上面内容或者直接查看 PHP 官方 Docker Hub 页面

    • 重新运行 Nginx 容器
    docker run -d --name nginx \
    -v ~/docker/nginx:/etc/nginx \
    -v ~/wwwroot:/usr/share/nginx/html \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -p 80:80 \
    -p 443:443 \
    nginx
    
    • 重新运行 MySQL 容器
    docker run -d --name mysql \
    -e MYSQL_ROOT_PASSWORD=root \
    -v ~/docker/mysql:/etc/mysql \
    -v mysql:/var/lib/mysql \
    -p 3306:3306 \
    mysql:5.7
    
    • 重新运行 PHP-FPM 容器
    docker run --name phpfpm -d -P \
    -v ~/wwwroot:/usr/share/nginx/html \
    -v ~/docker/php:/usr/local/etc/php \
    xbeta/php-fpm:7.2
    

    创建自定义网络并加入

    • 创建自定义网络 lnmp
    docker network create lnmp
    
    • 将各容器加入该自定义网络
    docker network connect lnmp nginx
    docker network connect lnmp mysql
    docker network connect lnmp phpfpm
    
    

    复制 PHP 程序文件至网页目录

    自行根据需求复制。

    修改 Nginx 配置文件

    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
        #error_page  404              /404.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;
        }
    
        # pass the PHP scripts to FastCGI server
        
        location ~ \.php$ {
            root           /usr/share/nginx/html;
            fastcgi_pass   phpfpm:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
    
    

    若需要运行多个网站,请参考本文“配置及测试 MySQL 数据库连接”部分

    配置完成后重启 nginx 容器

    docker restart nginx
    

    之后打开浏览器即可访问网站,要连接 mysql 数据库时,数据库地址请直接填写 mysql 即可。


    部分参考内容

    1. Docker 官方文档
    2. Docker Hub MySQL 官方页面
    3. Docker Hub PHP 官方页面
    4. Docker Hub phpMyAdmin 官方页面
    5. Docker 从入门到实践
    6. Docker搭建可一键部署的多域名LNMP环境
    7. 如何将docker 镜像上传到Docker Hub仓库
    8. Connect to mysql in a docker container from the host
    9. nginx多动态目录配置的问题