返回

解决 Docker PHP Redis 类找不到问题 (完整指南)

php

Docker 中 PHP 无法找到 Redis 类

在使用 Docker 容器化 PHP 应用时,开发者可能遇到明明 Redis 扩展已安装,PHP 代码运行时却报 “Class "Redis" not found” 的错误。这通常是因为扩展虽然安装成功,但未正确加载,或者加载时出现了其他问题。理解原因、逐一排查,最终找到解决方法,能够顺利让 PHP 应用与 Redis 协同工作。

问题剖析

问题的核心在于 phpredis 扩展虽然在 Docker 构建阶段被安装,但在运行时却未能被 PHP 正确识别和加载。extension_loaded('redis') 函数返回 true 只是表示 redis 扩展的动态链接库 (.so) 文件确实存在,并不代表它已被成功加载到 PHP 进程中。导致这一问题的常见原因包括:

  1. PHP 扩展配置缺失: 虽然 .so 文件存在,但 php.ini 配置中可能未显式启用该扩展。
  2. 扩展加载路径问题: PHP 进程可能在错误路径寻找扩展,未能定位到 redis.so 文件。
  3. 动态库依赖缺失: 某些动态链接库需要依赖其它库,若这些依赖缺失,则扩展加载失败。
  4. PHP-FPM 用户权限: PHP-FPM 可能运行于权限受限的用户,没有权限读取 .so 文件。
  5. 不正确的PHP版本: phpredis 可能不支持你当前使用的 PHP 版本,或存在兼容性问题。

解决方案

以下是一些常见的解决方法:

1. 确认 PHP 扩展已启用

php.ini 文件是 PHP 运行时的核心配置文件,确保 redis.so 扩展在其中被明确启用是关键一步。

操作步骤:

  1. 进入 Docker 容器内部:

    docker exec -it <你的容器ID或名称> sh
    
  2. 查找 php.ini 文件的位置。 可以通过 php --ini 命令查看:

    php --ini
    

    命令输出通常包含配置文件的加载路径,如 /usr/local/etc/php/php.ini

  3. 编辑 php.ini 文件(例如,使用 vinano 编辑器)并在 Dynamic Extensions 区域添加 extension=redis.so 一行。

     vi /usr/local/etc/php/php.ini # 请使用上一步中你找到的文件路径
    

    或者你可以尝试这种简便的命令,直接写入配置:

       echo "extension=redis.so" >> /usr/local/etc/php/php.ini # 请使用上一步中你找到的文件路径
    
  4. 保存更改并退出编辑器。

  5. 重启 php-fpm 服务,使其加载新配置。你可以尝试使用类似以下命令:

    php-fpm restart
     #或者使用另一种 restart方式
     kill -USR2 `cat /var/run/php/php-fpm.pid`
    

此方法能够确保 php-fpm 读取配置信息并加载了对应的扩展。

2. 明确指定扩展加载路径

某些情况下,PHP 可能未能准确找到 redis.so 文件。可以使用 extension_dir 参数,指定 php 扩展所在的目录,确保 PHP 能够准确定位扩展文件。

操作步骤:

  1. 同样地进入容器内部

     docker exec -it <你的容器ID或名称> sh
    
  2. 查看redis 扩展安装路径, 你可以通过 php -i 命令 找到 extension_dir 这个配置信息, 并找到对应redis 的.so路径。

        php -i | grep extension_dir # 通常是类似 /usr/local/lib/php/extensions/no-debug-non-zts-xxxxxxxx/ 
    

    或者你可以尝试定位这个文件,例如:

        find / -name "redis.so"
    

    你会得到类似 /usr/local/lib/php/extensions/no-debug-non-zts-20160303/redis.so这样的结果,这个例子中 /usr/local/lib/php/extensions/no-debug-non-zts-20160303extension_dir,也就是接下来需要添加的参数的值。

  3. 修改 /usr/local/etc/php/php.ini,在 Dynamic Extensions 区域,修改 extension=redis.soextension=/usr/local/lib/php/extensions/no-debug-non-zts-xxxxxxxx/redis.so (注意 xxxxxx需要根据上一步的结果修改成实际值)或是在 extension_dir 配置项中加入这个路径.

  4. 重启 php-fpm 服务。

    php-fpm restart
     #或者
     kill -USR2 `cat /var/run/php/php-fpm.pid`

通过以上方法能够确保 php-fpm 正确加载了对应目录的redis扩展。

3. 检查动态库依赖

redis.so 扩展有时会依赖其他动态链接库。检查扩展依赖是否有缺失能够帮助开发者定位问题。可以使用 ldd 命令来检查依赖情况。

操作步骤:

  1. 进入 Docker 容器:

        docker exec -it <你的容器ID或名称> sh
    
  2. 使用 ldd 命令检查 redis.so 文件的依赖。

    ldd /usr/local/lib/php/extensions/no-debug-non-zts-xxxxxxxx/redis.so  #注意 `xxxxxx`需要根据实际路径修改
 ```
3.   分析输出,如果存在 `not found` 标识的依赖项,表示对应的库文件缺失。
4. 根据提示缺失的依赖,在Dockerfile中添加安装步骤,例如使用apk 或 apt 安装对应的库,并在php扩展之前执行。比如安装`libssl.so` , 在 `Dockerfile`添加
 ```Dockerfile
   RUN apk --update add openssl # 以alpine linux 为例
 ```
 然后重建 Docker 镜像。

解决缺失依赖,扩展就能正常加载。

### 4.  确认PHP版本兼容性

`phpredis` 扩展不同版本可能对 PHP 版本存在兼容性问题。确保使用的 `phpredis` 版本与你的 PHP 版本相匹配,是确保 Redis 类可用的关键步骤。可以在 `phpredis` 官方 GitHub 仓库或其他文档中查找兼容性信息。同时应该检查在 Dockerfile 中安装的 redis扩展版本和需要的php版本匹配。
**操作步骤** 
1. 检查`phpredis`的版本,在Dockerfile中找到这一行,类似`ENV PHPREDIS_VERSION 5.2.2`, 可以修改版本后重新构建镜像。或者尝试使用稳定版本。
2. 检查PHP版本,通过Dockerfile查找使用的php镜像。 
 ```
   FROM php:7.1.32-fpm-alpine3.10
  ```
 如果你的 php 是比较老的版本,可以考虑升级 php 或 使用兼容的 phpredis 版本。 也可以尝试php.net提供的版本
```dockerfile
     RUN pecl install redis && docker-php-ext-enable redis

解决php版本兼容问题能够确保扩展正确加载,正常工作。

安全提示

在构建 Docker 镜像过程中,注意使用官方镜像,或者信誉良好的镜像来源。使用最新的 phpredis 稳定版本,能够避免已知的安全漏洞。同时,限制 Docker 容器的运行权限,防止容器逃逸以及安全隐患。

以上提供的方法覆盖了多数 "Redis 类找不到" 问题的常见原因。逐一排查、逐步验证是解决问题的有效手段,保证 Redis 与 PHP 应用能顺利集成。