Implemented Bionic/libc compatibility.
This commit is contained in:
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -34,7 +34,8 @@ env:
|
||||
DEFAULT_NGINX_VERSIONS: "1.22.1 1.24.0 1.26.3 1.28.0 1.30.0"
|
||||
DEFAULT_TARGET_ARCHES: "linux-x86_64 linux-arm64 linux-armv7"
|
||||
MODULE_NAME: ngx_http_monitoring_module
|
||||
RELEASE_BUILD_IMAGE: ubuntu:22.04
|
||||
RELEASE_BUILD_IMAGE: ubuntu:18.04
|
||||
RELEASE_LIBC_BASELINE: ubuntu-bionic-glibc-2.27
|
||||
NGINX_CONFIGURE_ARGS: >-
|
||||
--with-compat
|
||||
--with-http_ssl_module
|
||||
@@ -226,6 +227,7 @@ jobs:
|
||||
-e NEXT_VERSION \
|
||||
-e NGINX_CONFIGURE_ARGS \
|
||||
-e RELEASE_BUILD_IMAGE \
|
||||
-e RELEASE_LIBC_BASELINE \
|
||||
-e TARGET_ARCH="$target_arch" \
|
||||
-v "$GITHUB_WORKSPACE:/work" \
|
||||
-w /work \
|
||||
@@ -306,6 +308,7 @@ jobs:
|
||||
printf 'target=%s\n' "$TARGET_ARCH"
|
||||
printf 'docker_platform=%s\n' "$DOCKER_PLATFORM"
|
||||
printf 'build_image=%s\n' "$RELEASE_BUILD_IMAGE"
|
||||
printf 'libc_baseline=%s\n' "$RELEASE_LIBC_BASELINE"
|
||||
printf 'build_machine=%s\n' "$(uname -m)"
|
||||
printf 'runner=ubuntu-22.04\n'
|
||||
printf 'git_ref=%s\n' "$GITHUB_REF"
|
||||
@@ -318,6 +321,7 @@ jobs:
|
||||
printf '# %s for Nginx %s\n\n' "$MODULE_NAME" "$nginx_version"
|
||||
printf 'Release: `%s`\n\n' "$NEXT_TAG"
|
||||
printf 'Target: `%s` (`%s`)\n\n' "$TARGET_ARCH" "$DOCKER_PLATFORM"
|
||||
printf 'Libc baseline: `%s`\n\n' "$RELEASE_LIBC_BASELINE"
|
||||
printf 'This package contains a prebuilt Linux dynamic module:\n\n'
|
||||
printf '```text\n'
|
||||
printf 'modules/%s.so\n' "$MODULE_NAME"
|
||||
@@ -326,8 +330,8 @@ jobs:
|
||||
printf '```nginx\n'
|
||||
printf 'load_module modules/%s.so;\n' "$MODULE_NAME"
|
||||
printf '```\n\n'
|
||||
printf 'This binary is built with `--with-compat` against Nginx %s on Ubuntu 22.04 for %s. ' "$nginx_version" "$TARGET_ARCH"
|
||||
printf 'For safest production use, run the same Nginx version, CPU architecture, and a compatible Linux/glibc environment. '
|
||||
printf 'This binary is built with `--with-compat` against Nginx %s on Ubuntu Bionic 18.04 for %s. ' "$nginx_version" "$TARGET_ARCH"
|
||||
printf 'For safest production use, run the same Nginx version, CPU architecture, and a Linux/glibc environment compatible with `%s`. ' "$RELEASE_LIBC_BASELINE"
|
||||
printf 'If your Nginx package has a materially different module ABI, rebuild from source with this repository.\n'
|
||||
} > "$package_dir/INSTALL.md"
|
||||
|
||||
@@ -354,6 +358,7 @@ jobs:
|
||||
{
|
||||
printf '# ngx_http_monitoring_module %s\n\n' "$NEXT_TAG"
|
||||
printf 'Previous tag: `%s`\n\n' "$LATEST_TAG"
|
||||
printf 'Libc baseline: `%s`\n\n' "$RELEASE_LIBC_BASELINE"
|
||||
printf 'Prebuilt Linux dynamic module packages are attached for targets: `%s`.\n\n' "$NORMALIZED_TARGET_ARCHES"
|
||||
printf 'Each tarball is built against the Nginx version and target architecture in its filename and includes:\n\n'
|
||||
printf -- '- `modules/%s.so`\n' "$MODULE_NAME"
|
||||
@@ -417,6 +422,9 @@ jobs:
|
||||
file: dockerized/Dockerfile
|
||||
platforms: ${{ steps.targets.outputs.docker_platforms }}
|
||||
push: true
|
||||
build-args: |
|
||||
BASE_IMAGE=ubuntu:18.04
|
||||
OPENSSL_RUNTIME_PACKAGE=libssl1.1
|
||||
tags: |
|
||||
${{ steps.image.outputs.repo }}:${{ steps.version.outputs.next_tag }}
|
||||
${{ steps.image.outputs.repo }}:latest
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -13,7 +13,7 @@ permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TEST_BUILD_IMAGE: ubuntu:22.04
|
||||
TEST_BUILD_IMAGE: ubuntu:18.04
|
||||
NGINX_CONFIGURE_ARGS: >-
|
||||
--with-compat
|
||||
--with-http_ssl_module
|
||||
|
||||
@@ -36,6 +36,8 @@ The compiled module is written to:
|
||||
build/ngx_http_monitoring_module.so
|
||||
```
|
||||
|
||||
The source avoids glibc-only mount parsing APIs such as `getmntent()` and parses `/proc/mounts` directly, which keeps the collectors portable across Linux libc implementations that expose the required `/proc`, `statvfs()`, and `getifaddrs()` interfaces.
|
||||
|
||||
## Docker Image
|
||||
|
||||
A Dockerized Nginx image is available in [dockerized](</dockerized>):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ARG DEBIAN_VERSION=bookworm
|
||||
ARG BASE_IMAGE=debian:bookworm-slim
|
||||
ARG NGINX_VERSION=1.28.0
|
||||
|
||||
FROM debian:${DEBIAN_VERSION}-slim AS builder
|
||||
FROM ${BASE_IMAGE} AS builder
|
||||
|
||||
ARG NGINX_VERSION
|
||||
ARG NGINX_CONFIGURE_ARGS="--with-compat --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_v2_module --with-http_gzip_static_module"
|
||||
@@ -48,9 +48,10 @@ RUN ./configure \
|
||||
&& cp objs/ngx_http_monitoring_module.so /usr/local/nginx/modules/
|
||||
|
||||
|
||||
FROM debian:${DEBIAN_VERSION}-slim AS runtime
|
||||
FROM ${BASE_IMAGE} AS runtime
|
||||
|
||||
ARG NGINX_VERSION
|
||||
ARG OPENSSL_RUNTIME_PACKAGE=libssl3
|
||||
|
||||
LABEL org.opencontainers.image.title="ngx_http_monitoring_module nginx image" \
|
||||
org.opencontainers.image.description="Nginx built with ngx_http_monitoring_module and embedded monitoring dashboard" \
|
||||
@@ -60,7 +61,7 @@ RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
libpcre2-8-0 \
|
||||
libssl3 \
|
||||
${OPENSSL_RUNTIME_PACKAGE} \
|
||||
zlib1g \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& groupadd --system --gid 101 nginx \
|
||||
|
||||
@@ -22,6 +22,12 @@ To choose a different Nginx version:
|
||||
NGINX_VERSION=1.28.0 sh dockerized/build.sh
|
||||
```
|
||||
|
||||
To build the image on an Ubuntu Bionic 18.04 libc baseline:
|
||||
|
||||
```sh
|
||||
BASE_IMAGE=ubuntu:18.04 OPENSSL_RUNTIME_PACKAGE=libssl1.1 sh dockerized/build.sh
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```sh
|
||||
|
||||
@@ -3,11 +3,15 @@ set -eu
|
||||
|
||||
IMAGE="${IMAGE:-ngx-http-monitoring-module:local}"
|
||||
NGINX_VERSION="${NGINX_VERSION:-1.28.0}"
|
||||
BASE_IMAGE="${BASE_IMAGE:-debian:bookworm-slim}"
|
||||
OPENSSL_RUNTIME_PACKAGE="${OPENSSL_RUNTIME_PACKAGE:-libssl3}"
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
docker build \
|
||||
--build-arg "NGINX_VERSION=$NGINX_VERSION" \
|
||||
--build-arg "BASE_IMAGE=$BASE_IMAGE" \
|
||||
--build-arg "OPENSSL_RUNTIME_PACKAGE=$OPENSSL_RUNTIME_PACKAGE" \
|
||||
-f dockerized/Dockerfile \
|
||||
-t "$IMAGE" \
|
||||
.
|
||||
|
||||
@@ -4,7 +4,9 @@ services:
|
||||
context: ..
|
||||
dockerfile: dockerized/Dockerfile
|
||||
args:
|
||||
BASE_IMAGE: "debian:bookworm-slim"
|
||||
NGINX_VERSION: "1.28.0"
|
||||
OPENSSL_RUNTIME_PACKAGE: "libssl3"
|
||||
image: ngx-http-monitoring-module:local
|
||||
container_name: ngx-http-monitoring-module
|
||||
ports:
|
||||
|
||||
@@ -58,3 +58,5 @@ Upstream metrics are passively observed from Nginx upstream state recorded on pr
|
||||
## Compatibility
|
||||
|
||||
The module is designed as an Nginx dynamic HTTP module and should be built with `--with-compat` against the target Nginx source tree. Stub-status counters are compiled in when the target Nginx build includes `--with-http_stub_status_module`; otherwise request counters still work but low-level active/reading/writing/waiting counters remain zero.
|
||||
|
||||
Collectors avoid glibc-only helpers such as `getmntent()` and parse `/proc/mounts` directly. This keeps filesystem collection compatible with libc implementations that do not ship `<mntent.h>`, while still requiring Linux `/proc`, `statvfs()`, and `getifaddrs()`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Release Builds
|
||||
|
||||
The GitHub Actions workflow in `.github/workflows/release.yml` builds ready-to-use Linux dynamic module packages for x86_64 and ARM targets.
|
||||
The GitHub Actions workflow in `.github/workflows/release.yml` builds ready-to-use Linux dynamic module packages for x86_64 and ARM targets. Release binaries are built in Ubuntu Bionic 18.04 containers, giving the module artifacts a `ubuntu-bionic-glibc-2.27` libc baseline.
|
||||
|
||||
## Manual Release Only
|
||||
|
||||
@@ -71,6 +71,13 @@ ghcr.io/<owner>/<repo>:latest
|
||||
|
||||
The image is built with Docker Buildx for the same normalized target platforms requested by `target_arches`.
|
||||
|
||||
The release image build passes:
|
||||
|
||||
```text
|
||||
BASE_IMAGE=ubuntu:18.04
|
||||
OPENSSL_RUNTIME_PACKAGE=libssl1.1
|
||||
```
|
||||
|
||||
## Compatibility Warning
|
||||
|
||||
Nginx dynamic modules are ABI-sensitive. The release packages are built with `--with-compat` on Ubuntu 22.04 against the Nginx version and CPU architecture in the filename. Use the matching Nginx version, CPU architecture, and a compatible Linux/glibc runtime. Rebuild locally when using a vendor Nginx package with materially different module ABI or hardening options.
|
||||
Nginx dynamic modules are ABI-sensitive. The release packages are built with `--with-compat` on Ubuntu Bionic 18.04 against the Nginx version and CPU architecture in the filename. Use the matching Nginx version, CPU architecture, and a Linux/glibc runtime compatible with `ubuntu-bionic-glibc-2.27`. Rebuild locally when using a vendor Nginx package with materially different module ABI or hardening options.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <mntent.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -41,6 +40,9 @@ static ngx_atomic_uint_t ngx_http_monitoring_sum_disk(
|
||||
static ngx_atomic_uint_t ngx_http_monitoring_delta(ngx_atomic_uint_t now,
|
||||
ngx_atomic_uint_t prev);
|
||||
static ngx_uint_t ngx_http_monitoring_skip_fs(const char *type);
|
||||
static char *ngx_http_monitoring_next_mount_field(char **cursor);
|
||||
static void ngx_http_monitoring_copy_mount_field(u_char *dst, size_t size,
|
||||
char *src);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
@@ -599,25 +601,45 @@ static void
|
||||
ngx_http_monitoring_collect_filesystems(ngx_http_monitoring_shctx_t *sh)
|
||||
{
|
||||
FILE *fp;
|
||||
struct mntent *mnt;
|
||||
char line[4096], *cursor, *source, *mount, *type;
|
||||
u_char mount_path[4096], fs_type[NGX_HTTP_MONITORING_NAME_LEN];
|
||||
struct statvfs st;
|
||||
ngx_uint_t count;
|
||||
uint64_t total, free_bytes, avail, used;
|
||||
|
||||
fp = setmntent("/proc/mounts", "r");
|
||||
fp = fopen("/proc/mounts", "r");
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while ((mnt = getmntent(fp)) != NULL
|
||||
&& count < NGX_HTTP_MONITORING_FILESYSTEMS_MAX)
|
||||
while (count < NGX_HTTP_MONITORING_FILESYSTEMS_MAX
|
||||
&& fgets(line, sizeof(line), fp) != NULL)
|
||||
{
|
||||
if (ngx_http_monitoring_skip_fs(mnt->mnt_type)) {
|
||||
cursor = line;
|
||||
source = ngx_http_monitoring_next_mount_field(&cursor);
|
||||
mount = ngx_http_monitoring_next_mount_field(&cursor);
|
||||
type = ngx_http_monitoring_next_mount_field(&cursor);
|
||||
|
||||
if (source == NULL || mount == NULL || type == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (statvfs(mnt->mnt_dir, &st) != 0 || st.f_blocks == 0) {
|
||||
(void) source;
|
||||
|
||||
ngx_http_monitoring_copy_mount_field(mount_path, sizeof(mount_path),
|
||||
mount);
|
||||
ngx_http_monitoring_copy_mount_field(fs_type, sizeof(fs_type), type);
|
||||
|
||||
if (mount_path[0] == '\0' || fs_type[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_http_monitoring_skip_fs((char *) fs_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (statvfs((char *) mount_path, &st) != 0 || st.f_blocks == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -626,9 +648,9 @@ ngx_http_monitoring_collect_filesystems(ngx_http_monitoring_shctx_t *sh)
|
||||
avail = (uint64_t) st.f_bavail * st.f_frsize;
|
||||
used = total - free_bytes;
|
||||
|
||||
ngx_cpystrn(sh->filesystems[count].path, (u_char *) mnt->mnt_dir,
|
||||
ngx_cpystrn(sh->filesystems[count].path, mount_path,
|
||||
NGX_HTTP_MONITORING_KEY_LEN);
|
||||
ngx_cpystrn(sh->filesystems[count].type, (u_char *) mnt->mnt_type,
|
||||
ngx_cpystrn(sh->filesystems[count].type, fs_type,
|
||||
NGX_HTTP_MONITORING_NAME_LEN);
|
||||
sh->filesystems[count].total = (ngx_atomic_uint_t) total;
|
||||
sh->filesystems[count].used = (ngx_atomic_uint_t) used;
|
||||
@@ -640,7 +662,7 @@ ngx_http_monitoring_collect_filesystems(ngx_http_monitoring_shctx_t *sh)
|
||||
count++;
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
fclose(fp);
|
||||
sh->fs_count = count;
|
||||
}
|
||||
|
||||
@@ -822,6 +844,72 @@ ngx_http_monitoring_delta(ngx_atomic_uint_t now, ngx_atomic_uint_t prev)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_monitoring_next_mount_field(char **cursor)
|
||||
{
|
||||
char *p, *start;
|
||||
|
||||
p = *cursor;
|
||||
|
||||
while (*p == ' ' || *p == '\t') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\0' || *p == '\n') {
|
||||
*cursor = p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start = p;
|
||||
|
||||
while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p != '\0') {
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_monitoring_copy_mount_field(u_char *dst, size_t size, char *src)
|
||||
{
|
||||
u_char *p, *last;
|
||||
ngx_uint_t value;
|
||||
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = dst;
|
||||
last = dst + size - 1;
|
||||
|
||||
while (*src != '\0' && p < last) {
|
||||
if (src[0] == '\\'
|
||||
&& src[1] >= '0' && src[1] <= '7'
|
||||
&& src[2] >= '0' && src[2] <= '7'
|
||||
&& src[3] >= '0' && src[3] <= '7')
|
||||
{
|
||||
value = (ngx_uint_t) ((src[1] - '0') * 64
|
||||
+ (src[2] - '0') * 8
|
||||
+ (src[3] - '0'));
|
||||
*p++ = (u_char) value;
|
||||
src += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
*p++ = (u_char) *src++;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_http_monitoring_skip_fs(const char *type)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user