NGINX Plus升级失败后的恢复方法:“模块‘M’的版本为X,而非Y”

NGINX | 2017年3月14日

如果使用动态模块,在升级到新版NGINX或NGINX Plus时,可能会看到如下错误:

Setting up nginx-plus (1.11.10-1~xenial) ...
nginx: [emerg] module "/etc/nginx/modules/ngx_http_geoip_module.so" version 1011005 instead of 1011006 in /etc/nginx/nginx.conf:7

nginx: configuration file /etc/nginx/nginx.conf test failed

invoke-rc.d: initscript nginx, action "upgrade" failed.

最可能的原因是尚未升级指定的动态模块(.so文件):

  • 如果您运行的是NGINX Open Source,则必须针对要升级到的版本编译动态模块。
  • 如果运行的是NGINX Plus,则必须针对与要升级到的NGINX Plus版本相对应的NGINX Open Source版本编译动态模块。

为简洁起见,下文将仅提及NGINX Plus。

别慌!

请放心,此错误消息并不表示NGINX Plus服务器已停止运行。NGINX Plus采用无缝升级,因此升级失败时旧版本仍会继续运行。不过,此时升级尚未完成,系统处于不一致状态:

  • 内存中的NGINX Plus进程仍在运行旧版本
  • 磁盘上与NGINX Plus相关的所有文件均对应新版本
  • 错误消息中提到的动态模块是针对旧版本编译的

请勿手动重启nginx或重新启动系统。否则会导致服务中断,因为只要存在与新版NGINX Plus不同步的动态模块,新的NGINX Plus进程就无法启动。

请注意,该错误消息仅与升级过程中发现的第一个不兼容模块有关,因此务必查找配置中的所有“load_module”指令,并确保每个模块均针对相应的NGINX版本进行编译。每个NGINX Plus版本均提供所有“NGINX开发及认证的第三方动态模块”的正确版本,因此只需重新编译未经认证的模块。本文介绍如何安全地完成升级过程。

出了什么问题?

NGINX 1.11.5和NGINX Plus R11新增了针对NGINX Open Source编译动态模块并将其加载到NGINX Plus中的功能。要实现这种二进制兼容性,模块和NGINX Plus必须基于同一开源版本。如果未先安装针对相应NGINX Open Source版本构建的动态模块,升级NGINX Plus将因版本不匹配而失败。

如果动态模块由第三方供应商提供,则需要联系该供应商,获取与您计划升级到的NGINX Plus版本所对应的NGINX版本相匹配的新模块版本。如果动态模块是从源代码编译的(并且您可以访问源代码),请继续阅读。

恢复之路

步骤0:准备构建环境

强烈建议在单独的系统上编译动态模块,本文将该系统称为“构建环境”。这样可以最大限度地降低运行NGINX Plus及动态模块的系统(本文称为“生产环境”)所面临的风险和复杂性。构建环境必须与生产环境使用相同的操作系统及版本;此外,还必须安装以下组件:

  • UnZip实用工具
  • 编译器和make实用程序
  • Perl 兼容正则表达式库(开发文件)
  • Zlib压缩库(开发文件)

为确保构建环境已安装这些必备组件,请运行以下命令。

  • 对于Ubuntu/Debian:
buildenv$ sudo apt-get install unzip gcc make libpcre3-dev zlib1g-dev
  • 对于CentOS/RHEL/Oracle Linux:
buildenv$ sudo yum install unzip gcc make pcre-devel zlib-devel

第1步:获取NGINX Open Source

  1. 在生产环境中运行以下命令,确定与当前运行的NGINX Plus版本对应的NGINX Open Source版本。在此输出中,该版本以橙色突出显示:NGINX 1.11.10,对应NGINX Plus R12。
production$ nginx -vnginx version: nginx/1.11.10 (nginx-plus-r12)
  1. 在构建环境中,下载相应NGINX Open Source版本的源代码。
build-env$ wget -qO - http://nginx.org/download/nginx-1.11.10.tar.gz | tar zxfv -

第 2 步:获取动态模块源代码

将动态模块的源代码复制到所选的构建目录。此处,我们从该模块的GitHub存储库中复制一个NGINX“hello world”示例模块。

buildenv$ git clone https://github.com/perusio/nginx-hello-world-module.git
Cloning into 'nginx-hello-world-module'...

步骤 3:编译动态模块

  1. 要编译动态模块,请先运行NGINX的configure脚本并使用--with-compat参数,使动态模块与NGINX Plus保持二进制兼容。然后运行make modules,仅编译该模块。
buildenv$ cd nginx-1.11.10/buildenv$ ./configure --with-compat --add-dynamic-module=../nginx-hello-world-module
buildenv$ make modules
  1. 确认构建过程已将动态模块创建为 .so文件,并存放在objs子目录中。
buildenv$ ls objs/*.soobjs/ngx_http_hello_world.so
  1. 创建模块文件的副本,并在文件名中包含NGINX Open Source版本号。这样可以更轻松地在生产环境中管理动态模块的多个版本。
buildenv$ cp objs/ngx_http_hello_world.so ./ngx_http_hello_world_1.11.10.so

步骤4:将动态模块复制到生产环境

由于我们创建动态模块时在文件名中加入了NGINX Open Source版本信息,因此可以放心地将其复制到生产环境,而不会影响系统运行。

buildenv$ scp ./ngx_http_hello_world_1.11.10.so production:/etc/nginx/modules

第5步:切换动态模块

在生产环境中,换入新的 .so文件以替换当前文件。此时执行此操作是安全的,因为只有在nginx重启或重新加载配置时,动态模块才会加载到内存中。

production$ cd /etc/nginx/modulesproduction$ cp ngx_http_hello_world.so ngx_http_hello_world_ROLLBACK.so
production$ ln -fs ngx_http_hello_world_1.11.10.so ngx_http_hello_world.so
production$ ls -gG
-rw-r--r-- 1 243576 Jan 31 16:18 ngx_http_hello_world_1.11.10.so
-rw-r--r-- 1 243576 Oct 20 10:40 ngx_http_hello_world_ROLLBACK.so
lrwxrwxrwx 1     24 Jan 31 16:26 ngx_http_hello_world.so -> ngx_http_hello_world_1.11.10.so

步骤 6:完成 NGINX Plus 升级

  1. 运行以下命令,测试模块版本是否正确,并确认NGINX Plus已准备好完成升级过程。
production$ nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  1. 完成升级流程,使NGINX Plus使用新版本和动态模块。
production$ service nginx upgradeStarting new master nginx:                                 [  OK  ]
Graceful shutdown of old nginx:                            [  OK  ]

防止升级失败

下次升级NGINX Plus时,请在升级前按照这些说明操作,以确保开始升级时已提供更新后的动态模块,从而节省时间并避免错误。


分享

关于作者

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。