实践说明:基于RHEL7(CentOS7.9)部署docker环境(23.0.1、24.0.2),所构建的php5.6.40镜像应用于RHEL7-9(如AlmaLinux9.1),但因为docker的特性,适用场景是不限于此的。
文档形成时期:2017-2023年
因系统或软件版本不同,构建部署可能略有差异,但本文未做细分,对稍有经验者应不存在明显障碍。
因软件世界之复杂和个人能力之限,难免疏漏和错误,欢迎指正。
文章目录
PHP5.6模组选择说明
php-5.6.40发布时间是2019.01.10,各模组安装可以参考这个时间。
官方php:5.6.40-fpm镜像的临时容器
通过临时容器获得默认配置和模组信息(可选):
创建临时容器的目的主要是获得默认配置、模组等信息。
docker run -itd --name phpfpm-5.6.40-tmp php:5.6.40-fpm
进入容器查看默认配置
docker exec -it phpfpm-5.6.40-tmp /bin/bash
临时容器系统版本
[root@localhost ~]# docker exec phpfpm-5.6.40-tmp /bin/bash -c "cat /etc/issue"
Debian GNU/Linux 9 \n \l
临时容器默认源
deb http://deb.debian.org/debian stretch main
deb http://security.debian.org/debian-security stretch/updates main
deb http://deb.debian.org/debian stretch-updates main
可准备国内源,建议用http而不是https
国内源sources_debian9.list放/root/sh/Dockerfiles/Independent中:
deb https://mirrors.aliyun.com/debian-archive/debian stretch main contrib non-free
#deb https://mirrors.aliyun.com/debian-archive/debian stretch-proposed-updates main non-free contrib
deb https://mirrors.aliyun.com/debian-archive/debian stretch-backports main non-free contrib
deb https://mirrors.aliyun.com/debian-archive/debian-security stretch/updates main contrib non-free
deb-src https://mirrors.aliyun.com/debian-archive/debian stretch main contrib non-free
#deb-src https://mirrors.aliyun.com/debian-archive/debian stretch-proposed-updates main contrib non-free
deb-src https://mirrors.aliyun.com/debian-archive/debian stretch-backports main contrib non-free
deb-src https://mirrors.aliyun.com/debian-archive/debian-security stretch/updates main contrib non-free
因为debian9默认不支持https,缺少apt-transport-https ca-certificates,采用https出现 0% [Working] ,卡那儿不动了,
解决方法:
- 先用官方源安装缺少的包,再改用国内源;
- 国内源同时支持http的,暂改用http,即:
deb http://mirrors.aliyun.com/debian-archive/debian stretch main contrib non-free
#deb http://mirrors.aliyun.com/debian-archive/debian stretch-proposed-updates main non-free contrib
deb http://mirrors.aliyun.com/debian-archive/debian stretch-backports main non-free contrib
deb http://mirrors.aliyun.com/debian-archive/debian-security stretch/updates main contrib non-free
deb-src http://mirrors.aliyun.com/debian-archive/debian stretch main contrib non-free
#deb-src http://mirrors.aliyun.com/debian-archive/debian stretch-proposed-updates main contrib non-free
deb-src http://mirrors.aliyun.com/debian-archive/debian stretch-backports main contrib non-free
deb-src http://mirrors.aliyun.com/debian-archive/debian-security stretch/updates main contrib non-free
临时容器默认模组
[root@localhost Independent]# docker exec phpfpm-5.6.40-tmp /bin/bash -c "php -m"
[PHP Modules]
Core
ctype
curl
date
dom
ereg
fileinfo
filter
ftp
hash
iconv
json
libxml
mbstring
mhash
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
[Zend Modules]
创建自定义网络
创建自定义网络并指定网段、网关,只有自定义了网络,才可以使用此网络为容器分配固定IP。
docker network create -d bridge --subnet 10.1.5.0/24 --gateway 10.1.5.1 custom_bridge_net
php5.6.40_Dockerfile
基于官方php:5.6.40-fpm镜像默认模组、wordpress老版本对php环境的要求,php5.6.40部署常见模组,以及曾经的生产环境常用模组,最终整理了比较完整模组安装的Dockerfile文件。
/root/sh/Dockerfiles/Independent/php5.6.40_Dockerfile 的内容:
FROM php:5.6.40-fpm
MAINTAINER Fisher "user@domain.com"
# 设置时区
ENV TZ=Asia/Shanghai
ADD sources_debian9.list /etc/apt/sources.list
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& mkdir /opt/web && mkdir -p /usr/local/php56/var/log && touch /usr/local/php56/var/log/php-fpm.log && touch /usr/local/php56/var/log/php_errors.log \
&& groupadd www -g 1000 && useradd -s /sbin/nologin -M www -u 1000 -g 1000 && mkdir /home/www && chown www:www /home/www \
&& chown www:www /usr/local/php56/var/log/php-fpm.log /usr/local/php56/var/log/php_errors.log \
&& DEBIAN_FRONTEND=noninteractive apt-get update -q \
&& apt-get install -y --no-install-recommends \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng-dev \
libmemcached-dev \
zlib1g-dev \
libbz2-dev \
libgmp-dev \
libedit-dev \
libxml2-dev \
libxslt-dev \
openssl \
libssl-dev \
libpq-dev \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
bcmath \
mysql \
mysqli \
pdo_mysql \
bz2 \
calendar \
exif \
gettext \
intl \
pcntl \
pgsql \
pdo_pgsql \
shmop \
sockets \
wddx \
xsl \
zip \
opcache \
mcrypt \
&& docker-php-ext-enable \
bcmath \
mysql \
mysqli \
pdo_mysql \
bz2 \
calendar \
exif \
gettext \
intl \
pcntl \
pgsql \
pdo_pgsql \
shmop \
sockets \
wddx \
xsl \
zip \
opcache \
mcrypt \
&& apt-get install -y --no-install-recommends libldap2-dev \
&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu && docker-php-ext-install -j$(nproc) ldap && docker-php-ext-enable ldap \
&& apt-get install -y --no-install-recommends libtidy-dev libxslt1-dev && docker-php-ext-install -j$(nproc) soap xmlrpc tidy && docker-php-ext-enable soap xmlrpc tidy \
&& docker-php-ext-install -j$(nproc) sysvsem sysvshm && docker-php-ext-enable sysvsem sysvshm \
&& docker-php-source delete \
&& apt-get clean; rm -rf /var/lib/apt/lists/* > /dev/null 2>&1
后记:web用户的uid和gid在docker内和宿主机上采用的一样的,方便权限的使用,但采用1000并不是一个好主意,可以考虑变更下。
php模组部署说明
在docker官方提到了php模组的几个来源:
- PHP Core Extensions。即自带的;
- 默认扩展。一些扩展是默认编译的。这取决于您使用的 PHP 版本。在容器中运行php -m以获取特定版本的列表。
- PECL 扩展。一些扩展没有随 PHP 源代码一起提供,而是通过PECL提供。要安装 PECL 扩展,请使用pecl install下载并编译它,然后使用docker-php-ext-enable启用它。
强烈建议在调用中使用明确的版本号以确保正确(PECL 在选择要安装的扩展版本时不检查 PHP 版本兼容性,但在尝试安装它时检查)。
例如,memcached-2.2.0没有 PHP 版本限制 ( https://pecl.php.net/package/memcached/2.2.0 ),但memcached-3.1.4需要 PHP 7.0.0 或更新版本 ( https://pecl.php.net/package/memcached /3.1.4)。在 PHP 5.6 上执行pecl install memcached(无特定版本)时,PECL 将尝试安装最新版本并失败。 - 其他扩展。一些扩展不是通过 Core 或 PECL 提供的;这些也可以安装,即把编译过程写进去,或后期手动安装模块(通过docker-php-ext-install安装也算比较简易),尽管这个过程自动化程度较低。
php5的时代,docker对php环境支持的成熟度还欠佳,构建过程中安装某些模组也比较坎坷,好在最终构建成功。
构建镜像
docker buildx build -t tmtcha/php:5.6.40-fpm-v1.01 -f /root/sh/Dockerfiles/Independent/php5.6.40_Dockerfile .
构建时间:350.7s,约6分钟
错误处理经验
遇错:rm: cannot remove ‘/var/lib/apt/lists/*’: No such file or directory
参考:https://github.com/iMacken/DevDock/issues/8
只有在apt出问题时才会使用这个方法,如果想要一个干净的环境 rm -rf /var/lib/apt/lists/ 这个方式可能解决这个问题。
运行容器
如果容器运行失败,可查看日志
docker logs 容器ID或名称
以构建的镜像再次运行一个临时的容器,为查看和拷贝配置等文件。
删除之前的临时容器(如果有):
docker stop phpfpm-5.6.40-tmp; docker rm phpfpm-5.6.40-tmp
docker run -itd --name phpfpm-5.6.40-tmp tmtcha/php:5.6.40-fpm-v1.01
可以看到,默认加载配置是这样的(后期手动扩展模块后,版本是v1.02):
[root@localhost ~]# docker exec -it phpfpm-5.6.40-v1.02 /bin/bash -c "php --ini"
Configuration File (php.ini) Path: /usr/local/etc/php
Loaded Configuration File: /usr/local/etc/php/php.ini
Scan for additional .ini files in: /usr/local/etc/php/conf.d
Additional .ini files parsed: /usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini,
/usr/local/etc/php/conf.d/docker-php-ext-bz2.ini,
/usr/local/etc/php/conf.d/docker-php-ext-calendar.ini,
/usr/local/etc/php/conf.d/docker-php-ext-exif.ini,
/usr/local/etc/php/conf.d/docker-php-ext-gd.ini,
/usr/local/etc/php/conf.d/docker-php-ext-gettext.ini,
/usr/local/etc/php/conf.d/docker-php-ext-igbinary.ini,
/usr/local/etc/php/conf.d/docker-php-ext-intl.ini,
/usr/local/etc/php/conf.d/docker-php-ext-ldap.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mcrypt.ini,
/usr/local/etc/php/conf.d/docker-php-ext-memcache.ini,
/usr/local/etc/php/conf.d/docker-php-ext-memcached.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mongo.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mysql.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini,
/usr/local/etc/php/conf.d/docker-php-ext-opcache.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pcntl.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pdo_pgsql.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pgsql.ini,
/usr/local/etc/php/conf.d/docker-php-ext-redis.ini,
/usr/local/etc/php/conf.d/docker-php-ext-shmop.ini,
/usr/local/etc/php/conf.d/docker-php-ext-soap.ini,
/usr/local/etc/php/conf.d/docker-php-ext-sockets.ini,
/usr/local/etc/php/conf.d/docker-php-ext-sysvsem.ini,
/usr/local/etc/php/conf.d/docker-php-ext-sysvshm.ini,
/usr/local/etc/php/conf.d/docker-php-ext-tidy.ini,
/usr/local/etc/php/conf.d/docker-php-ext-wddx.ini,
/usr/local/etc/php/conf.d/docker-php-ext-xmlrpc.ini,
/usr/local/etc/php/conf.d/docker-php-ext-xsl.ini,
/usr/local/etc/php/conf.d/docker-php-ext-zip.ini
配置均在/usr/local/etc/中,默认没有php.ini主配置,但仍然加载了构建过程中启用模组的子配置,
停止临时docker容器
docker stop phpfpm-5.6.40-tmp
拷贝配置到宿主机自定义的一个持久化目录中:
宿主机中执行:
mkdir -p /opt/docker_lnmp/{php56_cfg,php56_log}
docker cp phpfpm-5.6.40-tmp:/usr/local/etc /opt/docker_lnmp/php56_cfg
docker cp -a phpfpm-5.6.40-tmp:/usr/local/php56/var/log /opt/docker_lnmp/php56_log
注:会拷贝到目标路径下的子目录,需要再手动拷贝出来,并纠正权限,比如log文件应该是php-fpm运行用户所有,有可读写权限,因为用的www账户,容器内和宿主机的uid/gid一样,所以在宿主机执行chown www:www -R /opt/docker_lnmp/php56_log 这条命令也是对的。
php配置常见调整
cd /opt/docker_lnmp/php56_cfg
cp -a php/php.ini-production php/php.ini
vi php/php.ini
php日志路径变更为 error_log = /usr/local/php56/var/log/php_errors.log
修改内存限制,上传文件大小等必要配置,
upload_max_filesize = 32M
post_max_size = 32M
php-fpm配置常见调整
注,下面一些配置在php-fpm.conf中,一些在子配置www.conf,zz-docker.conf,docker.conf
user = www-data
group = www-data
改为
user = www
group = www
侦听端口变更为9000
listen = 127.0.0.1:9000
zz-docker.conf中有侦听配置,实践中发现优先于www.conf的配置生效。
listen = 9000
php-fpm日志路径变更为 error_log = /usr/local/php56/var/log/php-fpm.log
实践中发现docker.conf有日志路径输出配置:
error_log = /proc/self/fd/2
access.log = /proc/self/fd/2
这优先于php-fpm.conf中的配置生效,docker.conf中默认配置应该是为了便于通过docker观察日志输出,进入容器查看日志或手动挂载日志和docker的使用设计原则不符吧,应该尽可能通过docker去管理和查看服务。不过前面dockerfile和后面容器创建中关于日志自定义配置可以权当一个备用方案。
child processes视业务场景修改
内存限制
php_admin_value[memory_limit] = 128M
停止临时docker容器,或可删除(要手动安装模块时,先不要删)
docker stop phpfpm-5.6.40-tmp; # docker rm phpfpm-5.6.40-tmp
手动安装模块和更新镜像
(该部分内容是后期补充的)
先下载好需要手动安装的模块,再拷贝到临时容器中,进入容器安装。
docker start phpfpm-5.6.40-tmp
docker cp /root/software/php56_ext phpfpm-5.6.40-tmp:/root/
docker exec -it phpfpm-5.6.40-tmp /bin/bash
cd /usr/src/
tar xf php.tar.xz
cd /root/php56_ext
mv php-5.6.40 php # 要重命名为php,不然docker-php-ext-install按默认路径找不到扩展,下面的扩展版本号在安装时也要去掉,原因相同。
tar zxf igbinary-2.0.8.tgz
tar zxf memcache-2.2.7.tgz
tar zxf memcached-2.2.0.tgz
tar zxf mongo-1.6.16.tgz
tar zxf mongodb-1.5.3.tgz
tar zxf redis-4.2.0.tgz
mv igbinary-2.0.8 /usr/src/php/ext/igbinary
mv memcache-2.2.7 /usr/src/php/ext/memcache
mv memcached-2.2.0 /usr/src/php/ext/memcached
mv mongo-1.6.16 /usr/src/php/ext/mongo
mv mongodb-1.5.3 /usr/src/php/ext/mongodb
mv redis-4.2.0 /usr/src/php/ext/redis
cd /usr/src/php/ext/
cd /usr/src/php/ext/igbinary; docker-php-ext-install igbinary # 实践发现docker-php-ext-install默认会启用所安装的模块
cd /usr/src/php/ext/memcache; docker-php-ext-install memcache
cd /usr/src/php/ext/memcached; docker-php-ext-install memcached
cd /usr/src/php/ext/mongo; docker-php-ext-install mongo
cd /usr/src/php/ext/mongodb; docker-php-ext-install mongodb
cd /usr/src/php/ext/redis; docker-php-ext-install redis
通过php -m和php --ini可以发现模块成功扩展后,清理工地
cd /root; docker-php-source delete; rm -rf php56_ext; apt-get clean
exit
回到宿主机了,
导出配置:
docker cp phpfpm-5.6.40-tmp:/usr/local/etc /opt/docker_lnmp/php56_cfg
配置修改仍参考前面的经验,或者把新增模块的子配置拷贝出来补充到以往的配置目录中也行。
导出容器为快照(可选):
docker export phpfpm-5.6.40-tmp > /opt/data_bak/backup_ever/phpfpm-5.6.40-tmp.tar
通过快照可迁移到别的服务器。可以使用 docker import 从容器快照文件中再导入为镜像。
创建新的镜像(推荐):
docker commit -m="Install extensions igbinary-2.0.8, redis-4.2.0, memcache-2.2.7, memcached-2.2.0, mongo-1.6.16, mongodb-1.5.3" -a="tmtcha" phpfpm-5.6.40-tmp tmtcha/php:5.6.40-fpm-v1.02
容器快照和镜像有所不同,操作的命令也不一样,其本质上区别没有仔细去研究和测验,也许就像操作系统快照和镜像一样,总是有所区别的,总之别搞混了吧。
正式生产的容器和镜像
启动容器
docker run -dit
-p 9000:9000
–network custom_bridge_net --ip 10.1.5.129
-v /opt/web:/opt/web
-v /opt/docker_lnmp/php56_cfg:/usr/local/etc
-v /opt/docker_lnmp/php56_log:/usr/local/php56/var/log
–name=phpfpm-5.6.40-v1.01 tmtcha/php:5.6.40-fpm-v1.01
创建容器后重启容器:docker restart phpfpm-5.6.40-v1.01
tmtcha/php:5.6.40-fpm-v1.02同上
测验
容器内查看和调试
docker exec -it phpfpm-5.6.40-v1.01 /bin/bash
安装必要软件包
apt update
apt install net-tools vim procps inetutils-ping telnet
对该环境搭配宿主机的nginx+mysql,
报错:Connection failed: SQLSTATE[HY000] [2054] Server sent charset unknown to the client. Please, report to the developers
处理:mysql8中的[mysqld]中utf8mb4改为utf8,或不改,而添加collation-server = utf8mb4_unicode_ci
报错:Connection failed: SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client Connection failed
解决:mysql8中采用default_authentication_plugin=mysql_native_password,而不是8.0.33日志中推荐的
最终模组结果
模组结果(包括手动扩展模块后,版本是v1.02):
[root@localhost ~]# docker exec -it phpfpm-5.6.40-v1.02 /bin/bash -c "php -m"
[PHP Modules]
bcmath
bz2
calendar
Core
ctype
curl
date
dom
ereg
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
igbinary
intl
json
ldap
libxml
mbstring
mcrypt
memcache
memcached
mhash
mongo
mongodb
mysql
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_pgsql
pdo_sqlite
pgsql
Phar
posix
readline
redis
Reflection
session
shmop
SimpleXML
soap
sockets
SPL
sqlite3
standard
sysvsem
sysvshm
tidy
tokenizer
wddx
xml
xmlreader
xmlrpc
xmlwriter
xsl
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
Discuzx3.4测验
工具–》更新缓存报错:(1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘system>0’ at line 1
连接mysql5.6没有报错,推测和mysql8版本无关。因相关网站几乎不再有维护,暂时搁置该问题。
本文主题是php5的docker镜像构建,关于mysql的更多问题省略。
Wordpress4测验
正常
镜像导出和配置备份
mkdir /opt/data_bak/backup_ever/docker_images
docker save tmtcha/php:5.6.40-fpm-v1.01 > /opt/data_bak/backup_ever/docker_images/tmtcha-php-5.6.40-fpm-v1.01.tar
cd /opt/docker_lnmp
tar czpf /opt/data_bak/backup_ever/docker_images/php56_cfg.tar.gz php56_cfg
在新的服务器上应用此镜像时,导入镜像,php配置放于预定路径,启动容器,即可生产使用。
镜像和配置下载
地址:https://download.csdn.net/download/ynz1220/88726803
(资源如果不能打开是可能正在审核中,可过一会儿或次日访问)
镜像信息
名称:tmtcha/php:5.6.40-fpm-v1.01
大小:504MB
说明:因pecl问题少了好一些模块
名称:tmtcha/php:5.6.40-fpm-v1.02
大小:511MB
说明:手动安装了因pecl问题缺少的模块
镜像导入和解压配置示例
docker load < /opt/data_bak/backup_ever/docker_images/tmtcha-php-5.6.40-fpm-v1.02.rar
tar czpf /opt/data_bak/backup_ever/docker_images/php56_cfg_v1.02.tar.gz -C /opt/docker_lnmp/