本片文章搭建的环境是 nginx1.19 + php7.4 + php8.2 + mysql5.7 + mysql8.0 + redis
,多版本 php 和多版本 mysql。
这里就直接使用 docker-compose 搭建环境,也可以找到镜像创建容器再关联映射端口部署。
资源包下载地址。
参考文章:docker-compose使用nginx+php+mysql+redis部署fastadmin
。
.
.env # 配置参数
├── docker-compose.yml # docker-compose文件
├── mysql57
│ ├── conf
│ │ └── my.cnf
│ └── log
│ ├── mysqld.log
│ ├── tallylog
│ └── yum.log
├── mysql80
│ ├── conf
│ │ └── my.cnf
│ ├── data # mysql8.0数据目录(我这里没有挂载)
│ └── log
├── nginx
│ ├── conf
│ │ ├── default.conf
│ │ ├── php.conf
│ └── logs
│ ├── access.log
│ └── error.log
├── php74
│ ├── Dockerfile # php7.4 Dockerfile文件
│ └── conf
│ ├── ini
│ │ ├── conf.d
│ │ │ ├── docker-php-ext-mysqli.ini
│ │ │ ├── docker-php-ext-pdo_mysql.ini
│ │ │ └── docker-php-ext-sodium.ini
│ │ ├── php.ini-development
│ │ └── php.ini-production
│ └── php-fpm.d
│ ├── docker.conf
│ ├── www.conf
│ ├── www.conf.default
│ └── zz-docker.conf
├── php824
│ ├── Dockerfile # php8.2.4 Dockerfile文件
│ ├── conf
│ │ ├── php-fpm.conf
│ │ └── php.ini
│ ├── data
│ │ └── composer
│ └── logs
│ ├── fpm.slow.log
│ └── php.error.log
└── redis
├── redis.cnf
└── redis.conf
我只简单配置了 工作目录
和 docker环境目录
,可以根据需要把 docker-compose.yml
中容器参数放到这边。
#
# 项目目录/工作目录
#
PROJECT_DIR=/Users/yunsanmu/work/project
#
# 当前docker开发环境目录
#
DEV_ENV_DIR=/Users/yunsanmu/dev-env
为了方便操作,一般都会把容器的配置文件、日志文件等挂载映射。端口映射根据自己需要
version: "2.1"
services:
nginx:
image: nginx:1.19.1-alpine
container_name: nginx
ports:
- "80:80"
volumes:
- ${PROJECT_DIR}:/usr/share/nginx/html
- ${DEV_ENV_DIR}/nginx/conf:/etc/nginx/conf.d
- ${DEV_ENV_DIR}/nginx/logs:/var/log/nginx
networks:
- lnmp-network
php74:
container_name: php74
build: ./php74 # 这个目录放上我们刚才做好的定制化php的Dockerfile
ports:
- "9001:9000"
volumes:
- ${PROJECT_DIR}:/www:rw
- ${DEV_ENV_DIR}/php74/conf/ini:/usr/local/etc/php
- ${DEV_ENV_DIR}/php74/conf/php-fpm.d:/usr/local/etc/php-fpm.d
restart: always
links:
- mysql57
networks:
- lnmp-network
php824:
container_name: php824
build: ./php824
ports:
- "9002:9000"
volumes:
- ${PROJECT_DIR}:/www/:rw
- ${DEV_ENV_DIR}/php824/conf/php.ini:/usr/local/etc/php/php.ini:ro
- ${DEV_ENV_DIR}/php824/conf/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf:rw
- ${DEV_ENV_DIR}/php824/logs:/var/log/php
- ${DEV_ENV_DIR}/php824/data/composer:/tmp/composer
restart: always
networks:
- lnmp-network
mysql57:
image: mysql/mysql-server:5.7.28
container_name: mysql57
ports:
- "3307:3306"
volumes:
- ${DEV_ENV_DIR}/mysql57/conf/my.cnf:/etc/my.cnf:ro
# - ${DEV_ENV_DIR}/mysql57/data:/var/lib/mysql/:rw # 这里我就不挂载了,有需要到容器里看
- ${DEV_ENV_DIR}/mysql57/log:/var/log/:rw
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always
networks:
- lnmp-network
mysql80:
image: mysql:8.0
container_name: mysql80
ports:
- "3308:3306"
volumes:
- ${DEV_ENV_DIR}/mysql80/conf/my.cnf:/etc/my.cnf:ro
# - ${DEV_ENV_DIR}/mysql80/data:/var/lib/mysql/:rw
- ${DEV_ENV_DIR}/mysql80/log:/var/log/:rw
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
- lnmp-network
redis:
image: redis:5.0.3-alpine
container_name: redis
ports:
- "6379:6379"
volumes:
- ${DEV_ENV_DIR}/redis/redis.cnf:/etc/redis.conf:ro
restart: always
entrypoint: [ "redis-server", "/etc/redis.conf" ]
networks:
- lnmp-network
networks:
lnmp-network:
driver: bridge
ipam:
driver: default
由于我的电脑是 mac 的 m1 芯片
所以我这里使用的都是支持linux/arm64/v8
的镜像。
MySQL5.7的最新镜像就是不支持 linux/arm64/v8 平台,创建容器会报如下警告:
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
我这里使用 mysql/mysql-server:5.7.28
替代。
dockerfile
是自定义镜像的一套规则,由多条指令构成,在docker-compose.yml
中通过 build
参数引入。 上面的 docker-compose.yml
比较简单,我只对两个版本的PHP写了 dockerfile
,其他的都只在 compose
中使用image
,没有过多配置。
php7.4 的 dockerfile:
# 该装的都装上
# 版本7.4
FROM php:7.4-fpm
# composer
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/bin/composer && chmod +x /usr/bin/composer
# 各种依赖库和扩展
RUN apt-get update \
&& apt-get install -y \
vim \
git \
wget \
build-essential \
libmagickcore-dev \
libmagickwand-dev \
imagemagick \
libfreetype6-dev \
libmcrypt-dev \
libpng-dev \
libzip-dev \
libwebp-dev \
autoconf \
pkg-config \
gcc \
make \
zlib1g \
zlib1g-dev \
&& docker-php-ext-configure gd --with-webp=/usr/include/webp --with-jpeg=/usr/include --with-freetype=/usr/include/freetype2/ \
&& docker-php-ext-install -j$(nproc) gd iconv pdo pdo_mysql pdo_odbc mysqli bcmath calendar exif gettext sockets dba pcntl shmop sysvmsg sysvsem sysvshm zip \
&& pecl install redis-5.3.7 \
&& pecl install imagick \
&& pecl install mcrypt \
&& docker-php-ext-enable redis imagick mcrypt \
# 这句很重要,如果和你的nginx用户不同会导致你的服务起不来
RUN groupadd www && useradd -g www www
# 如果你需要别的扩展,还可以再加
php8.2.4 的 dockerfile:
# 该装的都装上
# 版本8.2.4
FROM php:8.2.4-fpm
# composer
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/bin/composer && chmod +x /usr/bin/composer
# 各种依赖库和扩展
RUN apt-get update \
&& apt-get install -y \
vim \
git \
wget \
build-essential \
libmagickcore-dev \
libmagickwand-dev \
imagemagick \
libfreetype6-dev \
libmcrypt-dev \
libpng-dev \
libzip-dev \
libwebp-dev \
autoconf \
pkg-config \
gcc \
make \
zlib1g \
zlib1g-dev \
&& docker-php-ext-configure gd --with-webp=/usr/include/webp --with-jpeg=/usr/include --with-freetype=/usr/include/freetype2/ \
&& docker-php-ext-install -j$(nproc) gd iconv pdo pdo_mysql mysqli bcmath calendar exif gettext sockets dba pcntl shmop sysvmsg sysvsem sysvshm zip \
&& pecl install redis-5.3.7 \
&& pecl install imagick \
&& pecl install mcrypt \
&& docker-php-ext-enable redis \
&& docker-php-ext-enable imagick \
&& docker-php-ext-enable mcrypt
# 这句很重要,如果和你的nginx用户不同会导致你的服务起不来
RUN groupadd www && useradd -g www www
# 如果你需要别的扩展,还可以再加
进入 docker-compose.yml
所在的目录,创建镜像那一步就直接跳过了,执行 docker-compose up -d
启动如下:
yunsanmu@yunsanmudeMacBook-Pro ~ % cd dev-env
yunsanmu@yunsanmudeMacBook-Pro dev-env % docker-compose up -d
Starting nginx ... done
Starting redis ... done
Starting php824 ... done
Starting mysql80 ... done
Starting mysql57 ... done
Starting php74 ... done
yunsanmu@yunsanmudeMacBook-Pro dev-env %
docker-compose up -d # 创建并启动某个容器
docker-compose down # 停止并删除所有容器、网络、镜像等
docker-compose stop # 停止所有容器
docker-compose start # 启动所有容器
docker-compose restart # 重启所有容器
docker-compose rm # 删除容器(删除前必须关闭容器,执行stop)
启动完成后需要做一些操作,mysql默认root账号是没有远程连接权限,先通过命令行在mysql5.7和mysql8.0赋予root用户远程权限,生产环境添加专门的远程账号。
通过docker 客户端进入mysql57和mysql80容器内,都执行一遍下面的命令:
sh-4.2# mysql -uroot -p
Enter password:
mysql> use mysql;
Database changed
mysql> update user set host = '%' where user = 'root';
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
mysql> exit
下面的测试显示的都是成功的流程,如果遇到相同问题参考下面的解决方法,其他问题自行百度。
进入nginx配置文件目录添加两个配置文件:php74.conf
、php82.conf
,并且在项目目录下创建两个文件夹:php74
、php82
,分别测试不同版本PHP。
├── nginx
│ ├── conf
│ │ ├── default.conf
│ │ ├── php74.conf
│ │ ├── php82.conf
├── project
│ ├── php74
│ │ ├── index.php
│ ├── php82
│ │ ├── index.php
php74.conf :
server {
listen 80;
server_name www.php74.com;
location / {
root /usr/share/nginx/html/php74;
index index.html index.htm index.php;
if (!-e $request_filename) {
# rewrite ^.*$ /index.php last;
rewrite ^/(.*)$ /index.php/$1 last;
}
}
location ~ \.php$ {
fastcgi_pass php74:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /www/php74/$fastcgi_script_name;
include fastcgi_params;
}
}
php82.conf :
server {
listen 80;
server_name www.php82.com;
location / {
root /usr/share/nginx/html/php82;
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 break;
# rewrite . /index.php last;
}
}
location ~ \.php$ {
fastcgi_pass php824:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /www/php82/$fastcgi_script_name;
include fastcgi_params;
}
}
修改 hosts,添加以下内容:
127.0.0.1 www.php74.com
127.0.0.1 www.php82.com
mysql5.7、mysql8.0和redis连接测试,编辑两个域名下的index.php文件,添加相同测试代码,测试连接:
php74/index.php:
// redis 测试
$redis = new \Redis();
$redis->connect('redis',6379);
echo "redis is running: ".$redis->ping();
echo '
';
// mysql5.7 测试
try {
# 连接的host要注意,与./nginx/default.conf中的php连接一样,不是ip,是docker-compose中配置的容器名,container_name
$dsn = "mysql:host=mysql57;dbname=mysql;";
$username = "root";
$password = "root";
$db = new PDO($dsn, $username, $password);
$sql = "SELECT * FROM user";
$stmt = $db->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($result);
} catch (PDOException $e) {
echo $e->getMessage() . "
";
exit;
}
echo '
';
// mysql8.0 测试
try {
# 连接的host要注意,与./nginx/default.conf中的php连接一样,不是ip,是docker-compose中配置的容器名,container_name
$dsn = "mysql:host=mysql80;dbname=mysql;";
$username = "root";
$password = "root";
$db = new PDO($dsn, $username, $password);
$sql = "SELECT * FROM user";
$stmt = $db->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($result);
} catch (PDOException $e) {
echo $e->getMessage() . "
";
exit;
}
报错:
[error] 26#26: *1 rewrite or internal redirection cycle while processing "/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/", client: 172.28.0.1, server: www.php82.com, request: "GET / HTTP/1.1", host: "www.php82.com"
2
修改nginx配置文件的反向代理:
错误配置
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
}
正确配置,替换{}内容:
rewrite ^/(.*)$ /index.php/$1 break;
或
rewrite . /index.php last;
报错:
Host '172.28.0.6' is not allowed to connect to this MySQL server
解决方法: 进入容器执行以下命令。
mysql> use mysql;
mysql> update user set host = '%' where user = 'root';
mysql> flush privileges;
mysql> exit
执行第二个命令时可能会出现 Duplicate entry ‘%-root‘ for key ‘PRIMARY‘
错误,参考:MySql出现ERROR 1062 (23000): Duplicate entry ‘%-root‘ for key ‘PRIMARY‘。
错误:
Error!: could not find driver
原因:
当我们使用 navicat
连接 mysql
时是在容器外进行操作,是用 ip+映射端口
连接;当在 php
代码中使用 pdo
连接 mysql
是在 php
容器内部连接mysql
容器,所以是 容器名+3306端口
连接。
解决办法:
$conn = new PDO('mysql:host=容器名;dbname=数据库;port=端口','用户','密码');