Installable Packages for Dynamic Modules Enable Seamless Upgrades

Original: https://www.nginx.com/blog/creating-installable-packages-dynamic-modules/

NGINX 1.11.5 and NGINX Plus R11 introduced support for compiling dynamic modules independently of NGINX itself. This allows users of NGINX and NGINX Plus to use the official builds from the NGINX, Inc. repositories and load in the dynamic modules they need. There are several sources of dynamic modules:

This blog focuses on the use of third‑party dynamic modules with NGINX and NGINX Plus. We discuss best practices for building, deploying, and upgrading dynamic modules in a production environment. For more basic module‑compilation instructions suitable for development and test environments, see Compiling Third‑Party Dynamic Modules for NGINX and NGINX Plus.

The Problem with .so Files

When you compile a dynamic module, the raw output is a shared object (.so file). At startup and reload, NGINX and NGINX Plus load each of the shared objects specified by a load_module directive. Shared objects are typically loaded from /etc/nginx/modules.

Dynamic modules are binary‑compatible with the official builds of NGINX and NGINX Plus. However, this binary compatibility has limitations. Dynamic modules must be compiled against the same version of NGINX they are loaded into. For NGINX Plus, dynamic modules must be compiled against the open source version that NGINX Plus is built on. This means that upgrading NGINX or NGINX Plus without first installing a new version of the dynamic module built against the matching version results in a failed upgrade.

Manually managing the dependency between NGINX and its dynamic modules is error‑prone. Dynamic module .so files do not indicate which version of NGINX they were built against, which makes the process of manually copying them around somewhat precarious. In a development environment this is generally acceptable, but for production environments dependencies need to be protected and upgrades automated.

The goal is for all dynamic modules to be automatically upgraded when you upgrade NGINX or NGINX Plus, regardless of whether the module was provided by NGINX, a Certified Module vendor, or a third‑party provider.

Packaging Dynamic Modules with Dependencies

If you use the official repositories for NGINX or NGINX Plus then you are already familiar with using a package manager to install and upgrade NGINX – yum for Red Hat/CentOS, apt for Ubuntu/Debian. The official NGINX and NGINX Plus repositories also contain installable packages for a number of dynamic modules. The metadata of a dynamic module package indicates the NGINX version the module was compiled against, automatically triggering an upgrade of the module during NGINX or NGINX Plus upgrade.

Using installable packages for third‑party dynamic modules is the key to honoring the dependency with NGINX, avoiding upgrade failures, and facilitating seamless upgrades.

NGINX, Inc. uses automated tooling to create the dynamic module packages for our official repositories. This tooling, called pkg‑oss, can also be used to create installable packages for third‑party modules.

You can use the pkg‑oss tooling to create an installable package for any dynamic module. It also includes a script, build_module.sh, that automates the process, as an example of how to create an installable package with the correct dependency on NGINX or NGINX Plus. Simply specify the version of NGINX or NGINX Plus and the location of the dynamic module sources. The module sources may be on the local disk, point at a GitHub repo, or be a general download link. The following example builds the RTMP module for NGINX Plus R11 on Ubuntu/Debian.

$ wget http://hg.nginx.org/pkg-oss/raw-file/default/build_module.sh
$ chmod a+x build_module.sh
$ ./build_module.sh -r 11 https://github.com/arut/nginx-rtmp-module.git
...
build_module.sh: INFO: Module packages created
~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb
~/debuild/nginx-plus-module-rtmp-dbg_1.11.5_amd64.deb

The filename indicates the module was built against the base NGINX version for NGINX Plus R11 (1.11.5), and we can confirm that by examining the package metadata.

$ dpkg-deb -f ~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb Depends
libc6 (>= 2.14), nginx-plus (>> 1.11.4), nginx-plus (<< 1.11.6)

When using the build_module.sh script, take note of the following points.

Setting Up a Private Repository for Seamless Upgrades

Many organizations use private repositories for distributing software. After copying the .deb or .rpm files produced by the NGINX pkg‑oss tooling to such a repository, you can install, remove, and upgrade dynamic modules with the same package manager you use to install NGINX and NGINX Plus. If you do not have a private repository, then it is a simple exercise to create one locally on the server.

To illustrate this process we show how to create a private repository for Ubuntu/Debian and Red Hat/CentOS so that our dynamic module can be installed with apt(8) or yum(8) respectively. Note that these steps require root access. Also, we’ve omitted the command prompt in this section to facilitate copying and pasting.

  1. Prepare dependencies and create the local repository for the package manager.

    • On Ubuntu/Debian systems:

      mkdir /opt/deb
      echo "deb file:/opt deb/" > /etc/apt/sources.list.d/local.list
    • On Red Hat/CentOS systems:

      yum install createrepo
      mkdir /opt/rpm
      cat << EOF > /etc/yum.repos.d/localrepo.repo 
      [localrepo]
      name=Dynamic modules for NGINX
      baseurl=file:///opt/rpm
      gpgcheck=0
      enabled=1
      EOF
  2. Copy the installable package for the dynamic module to the local repository.

    • On Ubuntu/Debian systems:

      cp ~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb /opt/deb
    • On Red Hat/CentOS systems:

      cp ~/rpmbuild/RPMS/x86_64/nginx-plus-module-rtmp-1.11.5-1.el7.centos.ngx.x86_64.rpm /opt/rpm
  3. Update the package manager to be aware of the dynamic module package.

    • On Ubuntu/Debian systems:

      cd /opt && dpkg-scanpackages deb | gzip > deb/Packages.gz
      apt-get update
    • On Red Hat/CentOS systems:

      createrepo -v /opt/rpm
      yum clean all
      yum update
  4. Repeat Steps 2 and 3 for each module.

Installing a Module from a Private Repository

When a dynamic module is stored in a private repository, you can use the local package manager to install it.

Note that the name of the package is the same as the filename produced by the build script, without the version and platform information.

When installation is complete, a banner explains how to configure NGINX to load the newly installed dynamic module.

----------------------------------------------------------------------

The rtmp dynamic module for nginx has been installed.
To enable this module, add the following to /etc/nginx/nginx.conf
and reload nginx:

    load_module modules/ngx_rtmp_module.so;

----------------------------------------------------------------------

Seamless Upgrade

With the dynamic module installed in this way, you are protected from version mismatch during upgrades of NGINX or NGINX Plus. If an upgrade of NGINX or NGINX Plus is attempted before installed dynamic modules are upgraded, the local package manager reports the problem.

To ensure a seamless upgrade, first build a new version of the dynamic module against the version of NGINX or NGINX Plus you intend to upgrade to. The following example shows the steps required to upgrade NGINX Plus from R11 to R12 with the RTMP dynamic module installed.

  1. Build the dynamic module for NGINX Plus R12.

    $ ./build_module.sh -r 12 https://github.com/arut/nginx-rtmp-module.git
    ...
    build_module.sh: INFO: Module packages created
    ~/debuild/nginx-plus-module-rtmp_1.11.10_amd64.deb
    ~/debuild/nginx-plus-module-rtmp-dbg_1.11.10_amd64.deb
  2. Repeat Steps 2 and 3 from Setting Up a Private Repository for Seamless Upgrades to update the private repository with the new dynamic module.

  3. Upgrade NGINX Plus.

    • On Ubuntu/Debian systems:

      $ apt-get install nginx-plus
      Reading package lists... Done
      Building dependency tree       
      Reading state information... Done
      The following packages will be upgraded:
        nginx-plus nginx-plus-module-rtmp
      2 to upgrade, 0 to newly install, 0 to remove
      Need to get 2,571 kB/2,731 kB of archives.
      After this operation, 411 kB of additional disk space will be used.
      Do you want to continue? [Y/n]
    • On Red Hat/CentOS systems:

      $ yum install nginx-plus
      ...
      Resolving Dependencies
      --> Running transaction check
      ---> Package nginx-plus.x86_64 0:1.11.5-1.el7.ngx will be updated
      --> Processing Dependency:
       ---> Package nginx-plus-module-rtmp.x86_64 0:1.11.5-1.el7.centos.ngx will be updated
      --> Finished Dependency Resolution
      
      Dependencies Resolved
      
      =========================================================================
       Package                Arch   Version                  Repository  Size
      =========================================================================
      Updating:
       nginx-plus             x86_64 1.11.10-3.el7.ngx        nginx-plus 2.4 M
      Updating for dependencies:
       nginx-plus-module-rtmp x86_64 1.11.10-1.el7.centos.ngx localrepo  176 k
      
      Transaction Summary
      =========================================================================
      Upgrade  1 Package (+1 Dependent package)
      
      Total download size: 2.6 M
      Is this ok [y/d/N]:

Summary

Dynamic modules for NGINX and NGINX Plus enable you to compile only the specific extensions you require while taking advantage of the prebuilt and tested packages from NGINX, Inc. The pkg‑oss tooling and the build_module.sh script provide a straightforward solution to creating, installing, and upgrading third‑party modules for production deployments of NGINX and NGINX Plus.

Retrieved by Nick Shadrin from nginx.com website.