Docker之MNMP配置PHP|Docker之MNMP配置PHP Web开发环境

Docker 安装,参考Docker之开始
  • 再谈docker搭建nginx+php+mysql开发环境
相关文件
?www tree -L 2 . ├── default.conf ├── html │├── connect_mysql.php │└── index.php ├── mysql ├── php.ini └── www.conf

这里的目录与文件,会在下文中都有介绍,先不用手动创建
mysql
【Docker之MNMP配置PHP|Docker之MNMP配置PHP Web开发环境】从Docker Hub 中拉取镜像
docker pull mysql:5.7

最新版本的mysql 8.0 会有一些新特性,与最新的php-fpm 配合需要一些特殊处理,这里采用 mysql:5.7 先做上手。
实例容器,启动数据库
docker run -p 3306:3306 --name mysql -v ~/www/mysql/:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d --privileged=true mysql

说明:
  • -p 3306:3306:将容器的3306端口映射到主机的3306端口
  • -v ~/www/mysql/:/var/lib/mysql:将主机当前用户目录下的mysql文件夹挂载到容器的/var/lib/mysql 下,在mysql容器中产生的数据就会保存在本机mysql目录下
  • -e MYSQL_ROOT_PASSWORD=123456:初始化root用户的密码
  • -d 后台运行容器
  • --name 给容器指定别名
  • --privileged=true 可能会碰到权限问题,需要加参数;否则的话 访问 mysql 会提示无访问权限
php-fpm
拉取镜像
docker pull php:7.2-fpm

实例容器,启动PHP
docker run --name php-fpm -p 9000:9000 -d php:7.2-fpm

复制配置文件至本地
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-fpm:/usr/src/php/php.ini-production,在实例出的容器中,不一定是路径src/php,拉取的php:fpm版本镜像不同,php.ini路径不同。
可以这样查看php.ini路径
# 先进入容器 $ docker exec -it php-fpm bash $ cd /usr/src/ && ls # 有以下两个文件 php.tar.xzphp.tar.xz.asc # 这里我们需要解压php.tar.xz文件,因为php.ini-production就在其中 //先解压xz xz -d php.tar.xz //再解压tar # tar -xvfphp.tar

解压完毕后, php.ini-production便出现了,我当时的路径是/usr/src/php-7.1.9/php.ini-production。
即,前文中的 $ docker cp php-fpm:/usr/src/php/php.ini-production php.ini 改为 $ docker cp php-fpm:/usr/src/php-7.1.9/php.ini-production php.ini

==在本地服务器修改 php.ini 的内容,设置 cgi.fix_pathinfo=1(要先删除前面的; 注释符)。==
前面关于php-fpm的一系列操作主要是为了获得配置文件,并没有挂载本地目录到容器中,所以接下来需要删除容器,重新实例一个容器出来
$ docker stop php-fpm $ docker rm php-fpm $ docker run --name php-fpm -p 9000:9000 --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:7.2-fpm

上述操作,从博客中直接复制过来,实操过程基本一致。php.ini的获取,我使用的是php-7.2.12所以路径也有细微不同。按照上述操作获取即可。
Nginx
拉取镜像
docker pull nginx

实例容器
docker run --name nginx -p 80:80 -d nginx

通过浏览器:localhost 就会看到Nginx默认的欢迎界面:Welcome to Nginx
映射HTML路径 默认情况下,Docker nginx服务器的HTML路径(网站根目录)在容器/usr/share/nginx/html目录下,现在需要把这个目录映射到本地服务器的~/www/html目录。在上面命令的基础上加上-v参数,具体如下:
## 先删除之前的容器 $ docker rm nginx $ docker run --name nginx -p 80:80 -d -v ~/www/html:/usr/share/nginx/html nginx

-v的参数格式为::
在~/www/html下创建一个index.html文件,内容随意
比如 hello world
在浏览器上访问 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

这样就可以直接在本地修改配置文件了。
修改Nginx配置 就是前面我们从容器中复制出来的 default.conf
server { listen80; server_name_; root/usr/share/nginx/html; indexindex.html index.htm; #charset koi8-r; #access_log/var/log/nginx/host.access.logmain; location / { #root/usr/share/nginx/html; #indexindex.html index.htm; try_files $uri $uri/ =404; }error_page404/404.html; location = /40x.html { root/user/share/nginx/html; }# redirect server error pages to the static page /50x.html # error_page500 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_passhttp://127.0.0.1; #}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { root/var/www/html/; fastcgi_passphp-fpm:9000; fastcgi_indexindex.php; includefastcgi_params; #fastcgi_paramSCRIPT_FILENAME/scripts$fastcgi_script_name; fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name; }# deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { denyall; } }

关于配置文件,有个需要注意的地方
location ~ \.php$ { root/var/www/html/; fastcgi_passphp-fpm:9000; fastcgi_indexindex.php; #fastcgi_paramSCRIPT_FILENAME/scripts$fastcgi_script_name; includefastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }includefastcgi_params; 要放在 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 的前面

fastcgi_pass:其中配置的 php-fpm:9000,就是之前实例PHP的容器名
删除刚才的nginx容器,重新生成一个
$ docker stop nginx $ docker rm 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

测试 PHP与Nginx的连接
~/www/html 下创建 index.php

浏览器访问 localhost
会以长表格形式展现当前 PHP的版本信息。
测试PHP与MySQL的连接
PHP中与MySQL建立连接 还需要我们安装 PHP的扩展:mysqli
# 进入 php-fpm 容器中 docker exec -it php-fpm bash # 执行php mysqli 的扩展安装 docker-php-ext-install mysqli # 退出容器 exit

重启容器
docker restart php-fpm

~/www/html 中创建 connect_mysql.php
"; echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL. "
"; echo "Debugging error: " . mysqli_connect_error() . PHP_EOL. "
"; echo "string"; // exit; }echo "Success: A proper connection to MySQL was made! The my_db database is great." . PHP_EOL. "
"; echo "Host information: " . mysqli_get_host_info($link) . PHP_EOL; mysqli_close($link); ?>

在浏览器中输入:http://localhost/connect_mysql.php,展示如下:
Success: A proper connection to MySQL was made! The my_db database is great. Host information: 10.10.10.1:3306 via TCP/IP

则说明php与MySQL连接已建立
配置Dockerfile
上述中,在容器 php-fpm 中手动安装的扩展,在容器被删除后,就会被删除了,所以再次实例 php-fpm 时,还要再次手动安装扩展。是不是很麻烦,很不自动化?
so Dockerfile 就出场了,通过Dockerfile来定制镜像,只需要安装一次扩展以后实例化容器,就自动拥有这些扩展了。
先看目录层级
www ├── default.conf ├── Dockerfile ├── html │├── index.php │└── connect_mysql.php ├── mysql ├── php.ini └── www.conf

Dockerfile文件如下:
FROM php:7.2-fpm ADD www.conf/usr/local/etc/php-fpm.d/www.conf ADD php.ini/usr/src/php/php.ini RUN docker-php-ext-install mysqli pdo_mysql \ && docker-php-ext-enable mysqli EXPOSE 9000

依旧先删除之前的php-fpm容器:
$ docker stop php-fpm $ docker rm php-fpm # 构建 运行 # 进入项目的目录,比如我的www文件夹就是建在/home/username下的 $ cd ~/www $ docker build -t php-fpm:v1 ./ $ docker run --name php-fpm -p 9000:9000 --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:7.2-fpm 即可

当然具体需要哪些扩展还是根据自己的需求来编写Dockerfile
docker-compose
上述中,每次都要输入那么多的shell命令,每个容器都要一个个的启动,还要加那么多的参数,是不是感觉很烦?
so docker-compose 就出场了
先看目录层级
. ├── app │├── connect_mysql.php │└── index.php ├── docker-compose.yml └── services ├── mysql │└── data ├── nginx │├── config ││└── default.conf │└── logs └── php ├── Dockerfile └── config ├── php.ini └── www.conf

docker-compose.yml 文件如下:
version: '3' services: nginx: image: nginx:latest # 端口映射 ports: - "80:80" # 依赖关系 先跑php depends_on: - "php" # 数据卷 volumes: # 映射主机config目录到容器/etc/nginx/conf.d目录 - "$PWD/services/nginx/config:/etc/nginx/conf.d" - "$PWD/app:/usr/share/nginx/html" networks: - app_net # 容器名称 container_name: "compose-nginx" php: build: ./services/php # image指定build Dockerfile生成镜像的名称 image: php:7.2-fpm-pdo ports: - "9000:9000" volumes: - "$PWD/app:/var/www/html" networks: - app_net container_name: "compose-php" mysql: image: mysql:5.7 ports: - "3306:3306" volumes: - "$PWD/services/mysql/data:/var/lib/mysql" # 环境变量 environment: MYSQL_ROOT_PASSWORD: "123456" # 允许运行特权命令 privileged: true networks: app_net: # 固定子网ip,网段必须在子网络10.10.*.* ipv4_address: 10.10.10.1 container_name: "compose-mysql" networks: # 配置docker network app_net: driver: bridge ipam: config: # 子网络 - subnet: 10.10.0.0/16

按照如上目录层级,做好文件配置,其中相关文件配置内容,同名参考前面步骤就OK,直接复制过来就行。
实际上到了这一步,基本就完成了一个docker-compose 项目。
启动项目
docker-compose up -d

实际上,在这里启动的时候,如果本地镜像不存在,就会去Docker Hub 中去拉取;如果是定制镜像且在本地未曾构建过,就会自动去构建新的镜像;如果是定制镜像,但本地已经存在构建过的同名镜像,就会跳过构建这一步,直接启动同名镜像去实例化容器。
停止项目服务并删除所有容器
docekr-compose down

测试Sequel Pro 连接 MySQL
host:127.0.0.1 username:root password:123456 port:3306

登录即可
关于端口 port:MySQL容器的导出端口,即启动时配置的宿主机端口与容器端口的映射,默认是3306
  • 例如:
    ports: - 3306:3306

    则Sequel Pro 中通过 127.0.0.1:3306连接。
    ports: - 3316:3306

    则Sequel Pro 中通过 127.0.0.1:3316连接,而docker-compose容器互联则要通过 3306端口来访问MySQL Server
关于一些坑
  • php最新版(实操时:7.2.12-fpm),与最新版 MySQL (8.0),由于默认的加密机制不同,导致无法连接成功,不利于新手上手实操。故本文中直接采用 mysql:5.7
  • 启动 mysql 需要 添加 privileged=true 参数,否则连接数据库时,无访问权限
参考文献
  • 再谈docker搭建nginx+php+mysql开发环境 | Sail
  • 更好的PHP开发环境-Docker篇
  • Mac上通过docker配置PHP开发环境
  • docker-compose搭建nginx+php+mysql
  • Docker — 从入门到实践
  • Docker官方文档

    推荐阅读