Docker 搭建 PHP 运行环境
本篇概要: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
本篇概要:
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 用户组设置、加速器设置:
使用 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.cn
DocumentRoot "/usr/local/apache2/htdocs"
ServerName localhost
<Directory "/usr/local/apache2/htdocs">
Options None
Require all granted
</Directory>
ProxyRequests Off
ProxyPassMatch ^/(.*\.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,一款编排工具
# 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.10
container_name: fpm
volumes:
- /data/php/:/php
networks:
mywebnet:
ipv4_address: 192.158.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8080:80
volumes:
- /data/php/:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.158.0.3
networks:
mywebnet:
driver: bridge
ipam:
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.10
container_name: fpm
volumes:
- /data/php:/php
networks:
mywebnet:
ipv4_address: 192.138.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8081:80
volumes:
- /data/php/:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.138.0.3
nginx:
image: nginx:1.17.10-alpine
container_name: nginx
ports:
- 8082:80
volumes:
- /data/php:/usr/share/nginx/html
- /data/php/conf/nginx.conf:/etc/nginx/nginx.conf
networks:
mywebnet:
ipv4_address: 192.138.0.4
networks:
mywebnet:
driver: bridge
ipam:
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 进行一些参数的优化,不使用配置文件肯定是不方便的
定位到 “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.10
container_name: fpm
volumes:
- /data/php/tp5/web:/php
networks:
mywebnet:
ipv4_address: 192.138.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8081:80
volumes:
- /data/php/tp5/web/public:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.138.0.3
networks:
mywebnet:
driver: bridge
ipam:
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 ACCEPT
iptables -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.10
container_name: fpm
volumes:
- /data/php/tp5/web:/php
networks:
mywebnet:
ipv4_address: 192.138.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8081:80
volumes:
- /data/php/tp5/web/public:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.138.0.3
mysql:
image: mysql:8.0.20
container_name: mysqld
ports:
- 3307:3306
volumes:
- /data/php/mysql/conf:/etc/mysql/conf.d
- /data/php/mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=asdf
networks:
mywebnet:
ipv4_address: 192.138.0.4
networks:
mywebnet:
driver: bridge
ipam:
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
# 写入以下内容
<?php
namespace app\index\model;
use think\Model;
class UserModel extends Model
{
protected $table = 'users';
}
# 创建 /web/application/index/controller/UserIndex.php
# 写入以下内容
<?php
namespace 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: ./build
dockerfile: phpfpm
image: php:7.4.5-fpm-alpine3.10
container_name: fpm
volumes:
- /data/php/tp5/web:/php
networks:
mywebnet:
ipv4_address: 192.138.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8081:80
volumes:
- /data/php/tp5/web/public:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.138.0.3
mysql:
image: mysql:8.0.20
container_name: mysqld
ports:
- 3307:3306
volumes:
- /data/php/mysql/conf:/etc/mysql/conf.d
- /data/php/mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=asdf
networks:
mywebnet:
ipv4_address: 192.138.0.4
networks:
mywebnet:
driver: bridge
ipam:
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 yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
# 容器里的工作目录
dir /data
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
## 写入完毕
# 修改 docker-compose.yml
vim /data/php/tp5/compose/
# 添加 redis 部分配置,如下
version: "3"
services:
fpm:
build:
context: ./build
dockerfile: phpfpm
image: php:7.4.5-fpm-alpine3.10
container_name: fpm
volumes:
- /data/php/tp5/web:/php
networks:
mywebnet:
ipv4_address: 192.138.0.2
httpd:
image: httpd:2.4.43-alpine
container_name: httpd
ports:
- 8081:80
volumes:
- /data/php/tp5/web/public:/usr/local/apache2/htdocs/
- /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
networks:
mywebnet:
ipv4_address: 192.138.0.3
mysql:
image: mysql:8.0.20
container_name: mysqld
ports:
- 3307:3306
volumes:
- /data/php/mysql/conf:/etc/mysql/conf.d
- /data/php/mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=asdf
networks:
mywebnet:
ipv4_address: 192.138.0.4
redis:
image: redis:6.0.1-alpine
container_name: redis
ports:
- 6389:6379
volumes:
- /data/php/tp5/conf/redis.conf:/usr/local/etc/redis/redis.conf
- /data/php/tp5/redisdata:/data
networks:
mywebnet:
ipv4_address: 192.138.0.10
networks:
mywebnet:
driver: bridge
ipam:
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
<?php
namespace 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
更多推荐
所有评论(0)