本篇概要:

  • 1. 安装 Docker、使用 PHP 官方镜像运行 PHP 程序;
  • 2. Docker 多容器运行 PHP + fpm + Apache;
  • 3. 使用 Docker-compose 编排 PHP + fpm + Apache;
  • 4. Docker 搭建 Nginx + PHP-fpm;
  • 5. MySQL 容器;
    • 5.1 创建 MySQL 容器;
    • 5.2 MySQL 配置文件方式启动、导入数据;
    • 5.3 微容器 alpine 之构建基础镜像、安装 MySQL 客户端;
    • 5.4 制作 MySQL 备份专用镜像;
      • 5.4.1 动态参数;
  • 6. ThinkPHP5 + Docker 运行;
    • 6.1 结合 Apache 运行;
    • 6.2 配置 Samba 共享;
    • 6.3 添加控制器、url 重写;
    • 6.4 连接数据库、添加 PHP 扩展;
    • 6.5 添加 Redis 扩展;
    • 6.6 上传文件、alpine 环境下的权限问题;
  • 7. Laravel + Docker 运行;
    • 7.1 Composer 镜像使用;

1. 安装 Docker、使用 PHP 官方镜像运行 PHP 程序;

安装 Docker

  • 官网:https://docs.docker.com/install/linux/docker-ce/centos/#upgrade-docker-ce
  • https://download.docker.com/linux/centos/7/x86_64/stable/Packages/
# rpm 包安装
cd /usr/local/src
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm
yum install docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm

Docker 用户组设置、加速器设置:

  • 参考:https://blog.csdn.net/hualaoshuan/article/details/104736199

使用 PHP 官方镜像运行 PHP 程序

  • 阿里云镜像搜索官方 PHP:https://cr.console.aliyun.com/cn-hangzhou/instances/images?search=php
  • 官方 PHP 镜像库:https://hub.docker.com/_/php
  • 查看版本信息:https://github.com/docker-library/docs/blob/master/php/README.md#supported-tags-and-respective-dockerfile-links
# 拉取最新版本 PHP 镜像
# 每个镜像都是一个操作系统,每个操作系统可以根据自己的需求定制和修改
docker pull php# 拉取特定版本的 PHP 镜像(版本参考上方“版本信息”连接)
# alpine 为精简版本
docker pull php:7.4.5-cli-alpine3.10# *删除镜像
docker rmi php:latest# 交互式模式启动容器,最后可加上起始命令
# php -m 显示容器内 PHP 安装的扩展
docker run -it --name myphp php:7.4.5-cli-alpine3.10 php -m# 由于是交互式方式,容器没有启动出来
docker ps -a
# 删除容器
docker rm myphp
# *删除所有容器
docker rm $(docker ps -a)# 把一个 PHP 程序放到容器里去运行
# 首先创建 PHP 程序
cd /data/php
echo "<?php echo 'test docker';" > test.php# 启动容器,命名为 runphp,把 /data/php 挂载到容器里
# 加入 --rm,表示程序运行好,容器自动删除,适用于容器运行临时任务
docker run -it --name runphp --rm -v /data/php:/php php:7.4.5-cli-alpine3.10 \
php /php/test.php
# 输出 test docker

2. Docker 多容器运行 PHP + fpm + Apache;

一些知识点

  • 为什么容器不能 docker run -d --name myphp php:xxx 后台运行?运行后 docker ps 后什么都没有,其实没有出错,通过 docker logs myphp 查询什么错误日志都没有
  • 在 alpine 容器或者镜像里面的设置,它的后台把 PHP 进程作为 id 为 1 的进程,一旦 PHP 进程结束,容器就会停止。和官方的 Redis 镜像一样,把 Redis 服务作为 id 为 1 的进程。一旦 Redis 停止,容器就消失了
# 交互式启动,不跟任何命令
docker run -it --name myphp php:7.4.5-cli-alpine3.10
# 会进入 shell 窗口,就是一个 PHP 进程,作为 id 为 1 的元老进程
# 此时可以做一些操作,比如 echo 一些字符串,phpinfo() 等

PHP + fpm + Apache 联合运行

## 2.1 拉取 fpm 镜像(尽可能的使用基于 alpine 的镜像)
docker pull php:7.4.5-fpm-alpine3.10
# 由于 fpm 是服务,可以后台运行
docker run -d --rm --name fpm php:7.4.5-fpm-alpine3.10## 2.2 单单 fpm 没有用,还需要配置服务器,比如 Apache
# 参考:https://hub.docker.com/_/httpd
docker pull httpd:2.4.43-alpine# 写个 html 文件,挂载到容器中
echo "<html>hello world</html>" > index.html
# 把容器的 80 端口映射到宿主机的 8080
docker run -d -p 8080:80 --rm --name myweb -v \
/data/php/:/usr/local/apache2/htdocs/ httpd:2.4.43-alpine
# 访问
curl localhost:8080
# 返回:<html>hello world</html>## 2.3 联合运行操作
# 2.3.1 首先需要修改配置文件
# 查看容器中是否有配置文件
docker exec -it myweb cat /usr/local/apache2/conf/httpd.conf
# 创建本地存放配置文件的目录
mkdir -p /data/php/conf/
cd /data/php/conf/
# 把容器里的配置文件拷贝到本地
docker cp myweb:/usr/local/apache2/conf/httpd.conf /data/php/conf/
# 修改配置文件
vim httpd.conf# 做以下修改
# 把下面四行的 # 去掉
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so# 删除以下内容
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
...
</Directory># 添加以下内容后,保存退出
<VirtualHost *:80>ServerAdmin admin@xx.cnDocumentRoot "/usr/local/apache2/htdocs"ServerName localhost<Directory "/usr/local/apache2/htdocs">Options NoneRequire all granted</Directory>ProxyRequests OffProxyPassMatch ^/(.*\.php)$ fcgi://172.17.0.4:9000/php/$1
</VirtualHost>
# 添加结束
# ProxyPassMatch 的 ip 为 172.17.0.4,下面会有说明
# /php:这是一个文件夹名,可以自己设定,在 fpm 容器是没有的
# 可以把主机的 php 文件夹映射到 fpm 容器的 php 文件夹# 2.3.2 设置网络相关
# 查看网络
docker network ls
# 检查一下 bridge 网络
docker network inspect bridge
# Containers 中 fpm 的 IPv4Address 为 172.17.0.4,填入上面 ProxyPassMatch 相关
# 主机的 IPAM.Config.Gateway 为 172.17.0.1(ifconfig 查看 docker0 也可以看到)
# 主机和容器都是可以互通的# 启动 fpm 的时候把 php 文件夹挂载到 fpm 容器中,因此 fpm 的启动要修改
docker stop fpm
docker run -d --rm --name fpm \
-v /data/php/:/php \
php:7.4.5-fpm-alpine3.10# 把新的 httpd 的配置文件映射到容器里
docker stop myweb
docker run -d -p 8080:80 --name myweb -v /data/php:/usr/local/apache2/htdocs/  \
-v /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf \
httpd:2.4.43-alpine# 访问,返回 test docker,成功
curl localhost:8080/test.php

3. 使用 Docker-compose 编排 PHP + fpm + Apache;

之前是手工启动和删除容器,很不方便,所以需要使用 docker compose,一款编排工具

  • 参考:https://docs.docker.com/compose/install/#install-compose
# Docker-compose 安装
# -L:有些网站有多次跳转,加入此参数随着网站跳转而跳转
# -o:把下载内容输出到指定路径的文件
curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose# 对下载的文件赋予可执行权限
sudo chmod +x /usr/local/bin/docker-compose# 查看文件版本
docker-compose -v

Compose file 参考(Version 3):https://docs.docker.com/compose/compose-file/

# 创建一个“空的”文件夹,再创建默认的 docker-compose.yml 文件
mkdir -p /data/php/compose
touch /data/php/compose/docker-compose.yml# 网络参考:https://docs.docker.com/compose/networking/
# 注意:以下 192.158.0.x 都是子网
# 在 docker-compose.yml 中写入以下内容
version: "3"
services:fpm:image: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php/:/phpnetworks:mywebnet:ipv4_address: 192.158.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8080:80volumes:- /data/php/:/usr/local/apache2/htdocs/  - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf networks:mywebnet:ipv4_address: 192.158.0.3networks:mywebnet:driver: bridgeipam:config: - subnet: 192.158.0.0/16# 写入结束# 修改 httpd 配置文件
vim /data/php/conf/httpd.conf
# 锁定 ProxyPassMatch ^/(.*\.php)$ fcgi://172.17.0.4:9000/php/$1,修改 IP 为
192.158.0.2# 启动 compose
cd /data/php/compose/
# 启动
# 也可以指定一个名称 -p php:docker-compose -p php -d
# 注意:如果之前创建了相同子网的网络,要先删掉之前的,否则冲突
# 如果指定了-p,那么停止或删除时也要 docker-compose -p php stop
docker-compose up -d
# 显示
Creating network "compose_mywebnet" with driver "bridge"
Creating fpm   ... done
Creating httpd ... done# 关闭容器(一个)
docker-compose stop fpm
# 关闭容器(所有)
docker-compose stop
# 同理,删除容器
docker-compose rm# 查看网络
docker network ls
# 返回
NETWORK ID          NAME                DRIVER              SCOPE
ab368b5af331        bridge              bridge              local
8e8d27f1d706        compose_mywebnet    bridge              local
...
# compose_mywebnet 就是 docker-compose 创建的网络
# 删掉所有没有使用的网络
docker network prune
# 删除指定网络
docker network rm compose_mywebnet

4. Docker 搭建 Nginx + PHP-fpm;

安装 Nginx 镜像,参考:https://hub.docker.com/_/nginx

# 下载(实际生产环境都可以使用 alpine 的操作系统)
docker pull nginx:1.17.10-alpine# 基本配置:
# 默认网页文件夹是 /usr/share/nginx/html
# 默认配置文件地址是 /etc/nginx/nginx.conf
# 如果没有现成的配置文件,那么可以先胡乱启动下容器,然后拷贝到本地文件夹中
# 启动
docker run --name nginx --rm -d nginx:1.17.10-alpine
# 拷贝
docker cp nginx:/etc/nginx/nginx.conf /data/php/conf

支持普通 HTML 访问

docker run --name nginx -d --rm -v /data/php:/usr/share/nginx/html \
-p 8080:80 nginx:1.17.10-alpine

Nginx + fpm 配置

# 修改 nginx 配置
vim /data/php/conf/nginx.conf
# 修改为以下内容
user  nginx;
worker_processes  1;error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;events {worker_connections  1024;
}http {include       /etc/nginx/mime.types;default_type  application/octet-stream;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /var/log/nginx/access.log  main;sendfile        on;#tcp_nopush     on;keepalive_timeout  65;#gzip  on;#  include /etc/nginx/conf.d/*.conf;server{listen 80;location / {root  /usr/share/nginx/html;index  index.html index.htm index.php;}location ~ \.php$ {root /php;fastcgi_pass 192.138.0.2:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;include fastcgi_params;}}}

启动

# 创建网络
docker network create --driver=bridge --subnet=192.138.0.0/16 nginx_network# fpm 启动
# 不需要映射端口,Nginx 容器可以通过内网地址(bridge 桥接模式)访问这个容器的 fpm 服务
# 调试的时候 -d 参数可以换成 -it 参数
docker run -d --rm --name fpm \
--network nginx_network --ip 192.138.0.2 \
-v /data/php:/php \
php:7.4.5-fpm-alpine3.10# 启动 Nginx(自动生成 ip)
docker run --name nginx -d --rm -v /data/php:/usr/share/nginx/html \
-v /data/php/conf/nginx.conf:/etc/nginx/nginx.conf \
--network nginx_network -p 8080:80 \
nginx:1.17.10-alpine

Docker-compose 启动

# 清除没用的网络
docker network prune# 之前使用过的子网 192.158.x.x 和 192.138.x.x,现在统一改为 192.138.x.x
# 修改 httpd 配置文件
vim /data/php/conf/httpd.conf
# 锁定 ProxyPassMatch ^/(.*\.php)$ fcgi://192.158.0.2:9000/php/$1,修改 IP 为
192.138.0.2# 修改 docker-compose 文件
vim /data/php/compose/docker-compose.yml
# 修改为以下内容
version: "3"
services:fpm:image: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php:/phpnetworks:mywebnet:ipv4_address: 192.138.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8081:80volumes:- /data/php/:/usr/local/apache2/htdocs/  - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf networks:mywebnet:ipv4_address: 192.138.0.3nginx:image: nginx:1.17.10-alpinecontainer_name: nginxports:- 8082:80volumes:- /data/php:/usr/share/nginx/html- /data/php/conf/nginx.conf:/etc/nginx/nginx.confnetworks:mywebnet:ipv4_address: 192.138.0.4networks:mywebnet:driver: bridgeipam:config: - subnet: 192.138.0.0/16# 修改结束
# 启动
docker-compose up -d
# Apache 和 Nginx 都能访问
curl localhost:8081/test.php
curl localhost:8082/test.php

此时结构如下

5. MySQL 容器;

5.1 创建 MySQL 容器;

参考:https://hub.docker.com/_/mysql/

# 拉取镜像
docker pull mysql:8.0.20# 简单运行
# -e 设置环境变量
# MYSQL_ROOT_PASSWORD 是 root 的密码
docker run --name mysql --rm \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=asdf -d mysql:8.0.20# 连接测试
# 使用容器里的客户端完成
docker exec -it mysql mysql -u root -pasdf

5.2 MySQL 配置文件方式启动、导入数据;

在实际开发的时候,肯定要使用配置文件对 MySQL 进行一些参数的优化,不使用配置文件肯定是不方便的

  • 查看文档:https://hub.docker.com/_/mysql/

定位到 “Using a custom MySQL configuration file”:配置文件

  • 注意点 1:在 /etc/mysql/conf.d 目录下也可以加入配置文件,后缀必须是 .cnf
  • 注意点 2:MySQL 5 和 8 版本的一个区别:在 8 版本中,没有了 /etc/mysql/mysql.conf.d/mysqld.cnf 配置文件(5 版本里有),此配置文件里的内容合并到了 /etc/mysql/my.cnf

定位到 “Where to Store Data”:数据存储目录

# 5.2.1 进入容器的命令行,查看容器里的配置文件相关目录
docker exec -it mysql bash
cd /etc/mysql/
ls# 5.2.2 挂载相关文件
# 根据官网,配置文件在
/etc/mysql/my.cnf
# 数据目录在
/var/lib/mysql
# 先创建一个文件夹 mysql,里面包含几个子文件夹 conf、 data
mkdir -p /data/php/mysql/conf
mkdir -p /data/php/mysql/data# 创建配置文件(文件名随便)
# 官方的 my.cnf 加载了conf.d 里面的文件(!includedir /etc/mysql/conf.d/)
# 只要创建个带有关键配置部分的配置文件,映射 conf.d 文件夹即可
# 在 conf 文件下,随便创建个文件比如 abc.cnf
touch /data/php/mysql/conf/abc.cnf# 写入以下内容(一些基础配置)
[mysqld]
# 服务 id 唯一(用于主从同步)
server-id = 1
port = 3306
# 必须是容器里有的目录
log-error   = /tmp/error.log
# 只能用IP地址
skip_name_resolve
# 数据库默认字符集
character-set-server = utf8mb4
# 数据库字符集对应一些排序等规则
collation-server = utf8mb4_general_ci
# 设置 client 连接 mysql 时的字符集,防止乱码
init_connect='SET NAMES utf8mb4'
# 最大连接数
max_connections=300
# default_authentication_plugin=mysql_native_password# 写入完毕# 5.2.3 启动挂载目录
# 先停止容器
docker stop mysql && docker rm mysql
docker run --name mysql --rm \
-v /data/php/mysql/conf:/etc/mysql/conf.d \
-v /data/php/mysql/data:/var/lib/mysql \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=asdf \
-d mysql:8.0.20# 端口设置
sudo iptables -I INPUT -p tcp --dport 3307 -j ACCEPT# 测试配置
show variables like 'max_connections'# 注意!MySQL 8 版本,客户端连接出现如下报错解决方式
# ERROR 1045 (28000): Plugin caching_sha2_password could not be loaded:
# Error loading shared library /usr/lib/mariadb/plugin/caching_sha2_password.so
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'asdf';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'asdf';

导入数据

# 数据准备
vim /data/php/mysql/test.sql
# 内容如下
SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (`user_id` int(11) NOT NULL AUTO_INCREMENT,`user_name` varchar(50) NOT NULL,`user_qq` varchar(50) NOT NULL,PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'hualaoshuan', 'asdf');
INSERT INTO `users` VALUES ('2', 'zhangsan', '123456');# 内容结束# 拷贝
docker cp /data/php/mysql/test.sql mysql:/tmp# 进入容器客户端
docker exec -it mysql mysql -uroot -pasdf
# 导入
mysql> create database test;
mysql> use test;
mysql> source /tmp/test.sql;

5.3 微容器 alpine 之构建基础镜像、安装 MySQL 客户端;

下载最基础的 alpine 镜像:https://hub.docker.com/_/alpine/

# 下载
docker pull alpine:3.11# 使用 Dockerfile 构建镜像
# 链接:https://hub.docker.com/_/alpine/,锁定关键词:How to use this image
# 以下为示例
FROM alpine:3.7
# apk add,类似于 apt-get 和 yum
# 从镜像库下载 mysql-client 客户端
# --no-cache:从远程直接下载,不使用本地镜像库
RUN apk add --no-cache mysql-client
# ENTRYPOINT:启动容器的时候执行的命令
# mysql:下载下来后的可执行程序,会主动连接本地的 MySQL Server
ENTRYPOINT ["mysql"]
# 示例结束# 演示
# 创建 Dockerfile 相关文件夹
mkdir -p /data/php/mydocker
vim Dockerfile
# 写入如下内容
FROM alpine:3.11
RUN apk add --no-cache mysql-client
ENTRYPOINT ["mysql"]
# 写入结束# 构建新镜像
cd /data/php/mydocker
docker build -t mytool:1.0 .# 测试运行
docker run -it --name tmp --rm mytool:1.0
# 执行会报错,因为容器启动时默认执行的命令是 mysql
# 如果没任何参数,代表连接它自己本地的 mysql,本地没有 mysql,所以报错# 正确启动( -it 交互式,直接进入客户端)
docker run -it --name tmp mytool:1.0 mysql -h 192.168.2.214 -uroot -pasdf# 注意点
# alpine 使用的是 apk 包管理器命令,如 apk add 、apk update 、apk del
# 默认镜像源可能比较慢,常用的有
# 中科大镜像源:http://mirrors.ustc.edu.cn/alpine/
# 阿里云镜像源:http://mirrors.aliyun.com/alpine/

修改数据源

# 查看源文件
docker start tmp
docker exec -it tmp cat /etc/apk/repositories# 修改方法 1:手动加入阿里镜像源
docker exec -it tmp sh -c \
"echo \"http://mirrors.aliyun.com/alpine/v3.11/main/\" > /etc/apk/repositories"
docker exec -it tmp sh -c \
"echo \"http://mirrors.aliyun.com/alpine/v3.11/community/\" >> /etc/apk/repositories"
# 设置好后,执行
apk update && apk upgrade# (推荐)修改方法 2:重新修改 Dockerfile
# 修改内容如下
FROM alpine:3.11
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.11/main > /etc/apk/repositories
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.11/community >> /etc/apk/repositories
RUN apk update && apk upgrade
RUN apk add mysql-client
ENTRYPOINT ["mysql"]# 重新构造镜像
docker build -t mytool:1.0 .# 测试运行
docker run -it --name mysqlclient --rm mytool:1.0 \
mysql -h 192.168.2.214 -uroot -P3307 -pasdf

5.4 制作 MySQL 备份专用镜像;

5.4.1 动态参数;

数据库备份命令

mysqldump -u用户名 -p密码 数据库名 > 导出的文件名# 举例
mysqldump -h192.168.2.214 -uroot -P3307 -pasdf test > test.sql
# 然后把 test.sql 专门生成在一个文件夹中
# 可以使用挂载的方式生成到本地物理机上

基于之前的 mytool:1.0 镜像

# 新 Dockerfile 编写
cd /data/php/mydocker
vim Dockerfile
# 修改为以下内容
FROM mytool:1.0
RUN mkdir /data
ENTRYPOINT mysqldump -h192.168.2.214 -uroot -P3307 -pasdf test > /data/test.sql
# 编写完毕
# 注释:这里的 ENTRYPOINT 可以覆盖上一次的
# ENTRYPOINT 后有“[]”  基于参数,相当于直接运行可执行文件
# 没有 “[]” 相当于在内部启动了一个 shell 进程:sh -c "xxxx",适用于命令比较复杂的情况# 编译镜像
docker build -t mytool:1.1 .# 挂载执行
mkdir -p /data/php/mysql/mysqlbak
docker run -it --name bakup --rm -v /data/php/mysql/mysqlbak:/data mytool:1.1# 优化 Dockerfile
FROM mytool:1.1
ENV mysql_user root
ENV mysql_pass asdf
ENV mysql_host 192.168.2.214
ENV mysql_port 3307
ENV mysql_db test
ENTRYPOINT mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_pass $mysql_db > /data/$mysql_db.sql
# 优化结束# 编译
docker build -t mytool:1.2 .# 运行,备份本机数据库(3306)数据
docker run -it --name bakup --rm \
-v /data/php/mysql/mysqlbak:/data \
-e mysql_pass=asdf \
-e mysql_host=192.168.2.214 \
-e mysql_port=3306 \
-e mysql_db=test \
-e mysql_user=root \
mytool:1.2

6. ThinkPHP5 + Docker 运行;

6.1 结合 Apache 运行;

准备工作

# 下载 thinkphp:http://www.thinkphp.cn/down.html
# 创建相关目录
# 放程序文件
mkdir -p /data/php/tp5/web/
# 放 docker-compose.yml(compose)
mkdir -p /data/php/tp5/compose/# 下载后解压解压
unzip thinkphp_5.0.24_with_extend.zip -d /data/php/tp5/web/

设置网站目录

实际操作

# 6.1.1 删除没用的网络
docker network prune# 6.1.2 修改要挂载的 Apache 配置文件
vim /data/php/conf/httpd.conf
# 修改 <VirtualHost *:80> 标签里的 ProxyPassMatch 为如下内容
ProxyPassMatch ^/(.*\.php)$ fcgi://192.138.0.2:9000/php/public/$
# 修改完毕后保存退出# 6.1.3 创建 dock-compose
cd /data/php/tp5/compose
vim docker-compose.yml
# 写入以下内容
version: "3"
services:fpm:image: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php/tp5/web:/phpnetworks:mywebnet:ipv4_address: 192.138.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8081:80volumes:- /data/php/tp5/web/public:/usr/local/apache2/htdocs/- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.confnetworks:mywebnet:ipv4_address: 192.138.0.3networks:mywebnet:driver: bridgeipam:config:- subnet: 192.138.0.0/16# 写入完毕,运行
docker-compose up -d# 访问
curl http://192.168.2.214:8081/index.php

6.2 配置 Samba 共享;

参考镜像: https://hub.docker.com/r/dperson/samba

# 下载镜像
docker pull dperson/samba# 开放相关端口
iptables -I INPUT -p tcp --dport 139 -j ACCEPT
iptables -I INPUT -p tcp --dport 445 -j ACCEPTiptables -I INPUT -p udp --dport 137 -j ACCEPT
iptables -I INPUT -p udp --dport 138 -j ACCEPT# 测试运行
docker run -it -p 139:139 -p 445:445 --name smb -d --rm  \-v /data/php/tp5/web:/mount \dperson/samba \-u "root;asdf" \-s "root;/mount/;yes;no;yes;all;all;all" \-w "WORKGROUP" ## 相关调试
# 进入容器
docker exec -it smb sh# 查看进程
ps -ef | grep samb# 进入挂载目录,里面的内容和主机的文件是同步的
cd /mount# samba 配置
cd /etc/samba# 重新配置
docker stop smb
# 完整运行(注意下面的 root 是开发机的当前用户)
docker run -it -p 139:139 -p 445:445  --name smb -d --rm  \-v /data/php/tp5/web:/mount \dperson/samba \-u "root;asdf" \-s "hua;/mount/;yes;no;yes;all;all;all" \-w "WORKGROUP" \-g "force user= root" \-g "guest account= root"

6.3 添加控制器、url 重写;

开启 Apache 重写

# 编辑配置文件
vim /data/php/conf/httpd.conf# 修改以下内容
# 以下配置前的 “#” 去掉
LoadModule rewrite_module modules/mod_rewrite.so
# <VirtualHost *:80> - <Directory> 标签内加入
AllowOverride all
#  ProxyPassMatch 修改为以下
ProxyPassMatch ^/(.*\.php) fcgi://192.138.0.2:9000/php/public/$1# 重新构建容器
docker-compose restart# 修改 /web/application/index/controller/Index.php
# 追加方法
public function test() {}
# 访问:http://192.168.2.214:8081/index/index/test

6.4 连接数据库、添加 PHP 扩展;

Docker-compose 编排 MySQL

# 暂停删除之前的 MySQL 容器
docker stop mysql# 修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# 修改为以下内容
version: "3"
services:fpm:image: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php/tp5/web:/phpnetworks:mywebnet:ipv4_address: 192.138.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8081:80volumes:- /data/php/tp5/web/public:/usr/local/apache2/htdocs/- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.confnetworks:mywebnet:ipv4_address: 192.138.0.3mysql:image: mysql:8.0.20container_name: mysqldports:- 3307:3306volumes:- /data/php/mysql/conf:/etc/mysql/conf.d- /data/php/mysql/data:/var/lib/mysqlenvironment:- MYSQL_ROOT_PASSWORD=asdfnetworks:mywebnet:ipv4_address: 192.138.0.4networks:mywebnet:driver: bridgeipam:config:- subnet: 192.138.0.0/16# 修改结束# 运行(追加创建 mysql 容器)
docker-compose up -d mysql

启动容器后情况如下

  • 可以用数据库客户端软件,连接映射端口的主机地址 192.168.2.214:3307

配置数据库连接

# 数据库连接配置
# 可以填主机地址 192.168.2.214:3307
# 但是一般填写的是 Docker 虚拟出来的 ip
# 查看 Docker 网络
docker network ls
docker network inspect compose_mywebnet# 修改 /web/application/database.php
# 修改以下内容
return [// 数据库类型'type'            => 'mysql',// 服务器地址(Docker 虚拟的 ip)'hostname'        => '192.138.0.4',// 数据库名'database'        => 'test',// 用户名'username'        => 'root',// 密码'password'        => 'asdf',// 端口'hostport'        => '3306'
]# 打开调试:修改 /web/application/config.php
return [// 应用调试模式'app_debug'              => true,
];# 定义模型,参考:https://www.kancloud.cn/manual/thinkphp5/135187
# 创建 /web/application/index/model/UserModel.php
# 写入以下内容
<?phpnamespace app\index\model;use think\Model;class UserModel extends Model
{protected $table = 'users';
}# 创建 /web/application/index/controller/UserIndex.php
# 写入以下内容
<?phpnamespace app\index\controller;use app\index\model\UserModel;class UserIndex
{public function index(){$users = UserModel::all();var_dump($users);return "this is userIndex";}
}# 返回:could not find driver
# 因为默认的 PHP–FPM 容器没有 PDO_MYSQL 扩展

添加 PHP 扩展

# 进入 PHP–FPM 容器
docker exec -it fpm sh
# 查看 PHP 扩展
php -m
# 没有 pdo_mysql 扩展,需要安装
# 文档:https://github.com/docker-library/docs/blob/master/php/README.md#php-core-extensions
# 以上是核心安装库
# 如果需要安装 swoole 等,查阅 PECL extensions,也可以手工安装
# pdo_mysql 是属于核心扩展,只需要执行 docker-php-ext-install(官方镜像的脚本)# 安装前需要修改下 alpine 的镜像源,否则下载速度太慢
# 查看镜像源版本
cat /etc/issue
# 查看镜像源设置文件
cat /etc/apk/repositories
# 返回
http://dl-cdn.alpinelinux.org/alpine/v3.10/main
http://dl-cdn.alpinelinux.org/alpine/v3.10/community
# 把官方镜像源替换成阿里云镜像源(注意对应的版本号要准确)
echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories && \
echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
# 更新配置
apk update && apk upgrade# 安装扩展
docker-php-ext-install pdo_mysql# 重启容器
cd /data/php/tp5/compose
docker-compose restart fpm# 再访问
curl http://192.168.2.214:8081/index/user_index/index

持久化

# 刚才的操作是在容器里临时完成的,一旦容器删除了,所有之前的操作就没有了
docker-compose stop fpm
docker-compose rm fpm
docker-compose up -d fpm
# 解决方案,两种方法:
# 1. 再次创建 Dockerfile, 构建一个新镜像
# 那要是下次还有内容修改呢?一直不断的构建会很麻烦# (推荐)2. 在 docker-compose 文件中进行构建
# 一旦有新内容,不会临时到外部进行构建的,而是直接在 docker-compose 下面执行
# 1) 在当前文件夹下创建一个子文件夹 叫做 build
# 2) 在 build 里面新建一个 Dockerfile 文件,注意文件名,比如叫做 phpfpm
mkdir -p /data/php/tp5/compose/build/
cd /data/php/tp5/compose/build/
# 创建 Dockerfile
vim phpfpm# 写入如下内容
FROM php:7.4.5-fpm-alpine3.10
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories && \echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
RUN apk update && apk upgrade
RUN docker-php-ext-install pdo_mysql
# 写入结束# 修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# 修改如下(添加了 services - fpm - build 内容)
version: "3"
services:fpm:build: context: ./builddockerfile: phpfpmimage: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php/tp5/web:/phpnetworks:mywebnet:ipv4_address: 192.138.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8081:80volumes:- /data/php/tp5/web/public:/usr/local/apache2/htdocs/- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.confnetworks:mywebnet:ipv4_address: 192.138.0.3mysql:image: mysql:8.0.20container_name: mysqldports:- 3307:3306volumes:- /data/php/mysql/conf:/etc/mysql/conf.d- /data/php/mysql/data:/var/lib/mysqlenvironment:- MYSQL_ROOT_PASSWORD=asdfnetworks:mywebnet:ipv4_address: 192.138.0.4networks:mywebnet:driver: bridgeipam:config:- subnet: 192.138.0.0/16# 修改结束# 重构
docker-compose build fpm
# 完成后显示
Successfully built 3343fec11dd6
Successfully tagged php:7.4.5-fpm-alpine3.10
# 新构筑了一个镜像并打上标签,原来的镜像废弃
# 停掉原来的 fpm 容器
docker-compose stop fpm
docker-compose rm fpm # 创建新容器
docker-compose up -d fpm

6.5 添加 Redis 扩展;

安装 Redis,参考:https://hub.docker.com/_/redis/

# 获取镜像
docker pull redis:6.0.1-alpine# 配置文件
# 实例,有各个版本的配置文件:https://redis.io/topics/config
mkdir -p /data/php/tp5/conf
vim redis.conf
## 写入以下内容
bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300# 容器方式直接 no
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo yessave 900 1
save 300 10
save 60 10000stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
# 容器里的工作目录
dir /dataslave-serve-stale-data yes
slave-read-only yesrepl-diskless-sync-delay 5
repl-disable-tcp-nodelay noslave-priority 100lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush noappendonly noappendfilename "appendonly.aof"appendfsync everysec
no-appendfsync-on-rewrite noauto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mbaof-load-truncated yes
aof-use-rdb-preamble nolua-time-limit 5000slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0notify-keyspace-events ""hash-max-ziplist-entries 512
hash-max-ziplist-value 64list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512zset-max-ziplist-entries 128
zset-max-ziplist-value 64hll-sparse-max-bytes 3000activerehashing yesclient-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60hz 10aof-rewrite-incremental-fsync yes## 写入完毕# 修改 docker-compose.yml
vim /data/php/tp5/compose/
# 添加 redis 部分配置,如下
version: "3"
services:fpm:build: context: ./builddockerfile: phpfpmimage: php:7.4.5-fpm-alpine3.10container_name: fpmvolumes:- /data/php/tp5/web:/phpnetworks:mywebnet:ipv4_address: 192.138.0.2httpd:image: httpd:2.4.43-alpinecontainer_name: httpdports:- 8081:80volumes:- /data/php/tp5/web/public:/usr/local/apache2/htdocs/- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.confnetworks:mywebnet:ipv4_address: 192.138.0.3mysql:image: mysql:8.0.20container_name: mysqldports:- 3307:3306volumes:- /data/php/mysql/conf:/etc/mysql/conf.d- /data/php/mysql/data:/var/lib/mysqlenvironment:- MYSQL_ROOT_PASSWORD=asdfnetworks:mywebnet:ipv4_address: 192.138.0.4redis:image: redis:6.0.1-alpinecontainer_name: redisports:- 6389:6379volumes:- /data/php/tp5/conf/redis.conf:/usr/local/etc/redis/redis.conf- /data/php/tp5/redisdata:/datanetworks:mywebnet:ipv4_address: 192.138.0.10networks:mywebnet:driver: bridgeipam:config:- subnet: 192.138.0.0/16# 修改完毕# 启动
docker-compose up -d
# 进入容器内 redis
docker exec -it redis redis-cli -p 6379

添加 PHP 的 Redis 扩展

# Redis 扩展可以使用 pecl 来安装
# 参考文档:https://hub.docker.com/_/php/,锁定 “PECL extensions”
# 在 build 目录中 创建 phpredis 文件
vim /data/php/tp5/compose/build/phpredis
# 写入以下内容
FROM php:7.4.5-fpm-alpine3.10
RUN apk add autoconf gcc g++ make
RUN pecl install redis-5.1.1 \&& docker-php-ext-enable redis# 写入完毕,修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# services - fpm - build - dockerfile 改成 phpredis# 重构
docker-compose build fpm# 完成后显示
Successfully built d7ccf1769bc0
Successfully tagged php:7.4.5-fpm-alpine3.10
# 新构筑了一个镜像并打上标签,原来的镜像废弃
# 停掉原来的 fpm 容器
docker-compose stop fpm
docker-compose rm fpm # 创建新容器
docker-compose up -d fpm

代码实现

# 参考:https://www.kancloud.cn/manual/thinkphp5/118131
# 修改 /web/application/config.php
'cache'                  => [// 驱动方式'type'   => 'redis',// 容器 ip'host'   => '192.138.0.10','port'   => '6379',// 缓存保存目录// 'path'   => CACHE_PATH,// 缓存前缀'prefix' => '',// 缓存有效期 0表示永久缓存'expire' => 0,
],# 修改 /web/application/index/controller/UserIndex.php
<?phpnamespace app\index\controller;use app\index\model\UserModel;
use think\Cache;class UserIndex
{public function index(){//$users = UserModel::all();Cache::set("user", "testuser");$users = Cache::get("user");print_r($users);return "this is userIndex";}
}

6.6 上传文件、alpine 环境下的权限问题;

模板设置:https://www.kancloud.cn/manual/thinkphp5/119298

  • 出现的问题
## 问题 1:mkdir(): Permission denied
# 之前是通过“挂载”的方式挂载到容器里,如果 /web/runtime 里没有缓存文件夹,就会出现上述错误
# 这个问题和物理机里的权限是没有关系的# 查看物理机用户
cat /etc/passwd
# 返回,得到用户组为 1000,是映射到容器里的
# 但是这个 1000 在 fpm 里是没有的
hualaoshuan:x:1000:1000:hualaoshuan:/home/hualaoshuan:/bin/bash# 进入容器
docker exec -it fpm sh
# 进入到挂载的目录
cd /php
ls -l
# 目录的用户:群组分别是 1000:1000
# 这个 1000 就是指物理机用户# 查看 php 进程,php-fpm 所有者是 www-data
ps -ef | grep php
# 返回
1 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
6 www-data  0:00 php-fpm: pool www# 查看所有用户
cat /etc/passwd
# 返回
.
www-data:x:82:82:Linux User,,,:/home/www-data:/sbin/nologin# 解决方案:把 www-data 的用户和群组改为物理机用户的群组
# www-data 是 php-fpm 启动的默认用户名
# 但是 alpine 没有 usermod 命令
# 参考:https://pkgs.alpinelinux.org/contents?file=usermod&path=&name=&branch=&repo=&arch=
# alpine < 3.4,在数据源中加入
echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
apk --no-cache add shadow
# alpine > 3.4
apk add shadow# 修改用户 www-data 的用户以及群组 ID 为 1000
usermod -u 1000 www-data
groupmod -g 1000 www-data# 退出容器,重启容器
docker-compose restart fpm
  • 创建:/web/application/index/controller/Upload.php
<?php
// 访问:http://192.168.2.214:8081/index/upload/
namespace app\index\controller;use think\Controller;class Upload extends Controller
{public function index(){return $this->fetch("up");}public function up(){// https://www.kancloud.cn/manual/thinkphp5/155159}
}
  • 创建:/web/application/index/view/upload/up.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="/index/user_index/up">上传文件:<hr/><input type="file" name="myfile"/><hr/><input type="submit" value="上传"/></form>
</body>
</html>

7. Laravel + Docker 运行;

7.1 Composer 镜像使用;

  • Laravel 文档:https://docs.golaravel.com/docs/5.8/installation
  • Composer 镜像:https://hub.docker.com/_/composer/
# 拉取镜像
docker pull composer

Docker 搭建 PHP 运行环境相关推荐

  1. 使用 Docker 搭建 Tomcat 运行环境

    转自: http://m.oschina.net/blog/616526, 版权归原作者所有. 1 Docker与虚拟机     2 搭建过程 2.1 准备宿主系统 准备一个 CentOS 7操作系统 ...

  2. Docker搭建PHP运行环境

    目录 Docker 安装 PHP Docker 安装 Nginx ​编辑运行nginx容器 nginx安装成功 Nginx + PHP 部署PHP项目 启动 PHP: 启动 nginx: 查看正在运行 ...

  3. 本地docker搭建jupyter运行环境

    1.容器操作 1.拉取镜像 docker pull ubuntu 2.创建容器 创建容器时要先考虑好自己要开设几个端口,要提前指定好映射关系!!! docker run -dit --name Loc ...

  4. 使用 Docker 搭建 Laravel 本地环境

    (原文地址:https://blog.tanteng.me/2017/...) Laravel 官方提供 Homestead 和 Valet 作为本地开发环境,Homestead 是一个官方预封装的 ...

  5. Docker最全教程之使用Docker搭建Java开发环境(十八)

    前言 Java是一门面向对象的优秀编程语言,市场占有率极高,但是在容器化实践过程中,发现官方支持并不友好,同时与其他编程语言的基础镜像相比(具体见各语言镜像比较),确实是非常臃肿. 本篇仅作探索,希望 ...

  6. Docker最全教程之使用Docker搭建Java开发环境

    前言 Java是一门面向对象的优秀编程语言,市场占有率极高,但是在容器化实践过程中,发现官方支持并不友好,同时与其他编程语言的基础镜像相比(具体见各语言镜像比较),确实是非常臃肿. Java [Jav ...

  7. Docker学习总结(23)——Docker搭建大规模测试环境的实践

    内容来源:2017年4月8日,第四范式资深测试开发工程师孙高飞在"饿了么技术沙龙[第四弹]北京研发中心测试专场"进行<docker搭建大规模测试环境的实践>演讲分享.I ...

  8. OSGI企业应用开发(二)Eclipse中搭建Felix运行环境

    上篇文章介绍了什么是OSGI以及使用OSGI构建应用的优点,接着介绍了两款常用的OSGI实现,分别为Apache Felix和Equinox,接下来开始介绍如何在Eclipse中使用Apache Fe ...

  9. ubuntu下php服务器搭建_Ubuntu服务器下搭建php运行环境的方法

    本文实例讲述了Ubuntu服务器下搭建php运行环境的方法.分享给大家供大家参考,具体如下: 安装 Apache2: sudo apt-get install apache2 安装PHP模块: sud ...

最新文章

  1. mysql删除数据表show_简单的连接、删除数据库和show命令
  2. IQueryable和IEnumerable的区别
  3. CentOS 6.9/7通过yum安装指定版本的MySQL
  4. Java日志性能那些事
  5. 每日干货丨C语言数组知识点总结
  6. 存储引擎:engine
  7. 据说:一个线程性能相当于30%核心
  8. Java基础总结(上)
  9. 读书笔记——晶体管电路设计
  10. SPSS正在使用的工作文件或变量集中的所有变量不适合此对话框。
  11. jdk安装 系统找不到文件C:\ProgramData\Oracle\Java\javapath\java.exe
  12. 商汤科技Java面试题(含答案)
  13. php session fixation,Session Fixation 攻防实战
  14. 百度搜索稳定性问题分析的故事
  15. 2PC、XA、DTP与两阶段提交
  16. XGBoost feature importance特征重要性-实战印第安人糖尿病数据集
  17. android 仿支付宝动画,自定义view之仿支付宝动画
  18. 私信基本功能数据库设计
  19. 激光打印机的粉盒装粉
  20. TensorFlow是什么?

热门文章

  1. 2.5 大公司都在用的图片型封面
  2. 案例解析 GBase8s 在工业互联网平台中的应用
  3. 多智能体系统协同一致性问题(一)
  4. 多智能体系统——具有非线性不确定干扰的多智能体系统的固定时间事件触发一致性控制(附论文链接+源码Matlab)
  5. 中国电动汽车换电站行业发展前景与未来需求趋势预测报告(2022-2027)
  6. vue-Promise处理异步和同步
  7. windows7与linux共存,windows7和linux可以并存吗?
  8. sublime使用live-server
  9. 私域直播系统优势,具备这些功能点才叫系统
  10. Qt实现 获取程序所在的各种路径