Skip to content

Feat/add otel support #7642

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,32 @@ ARG PACKAGE_REPO=pkgs.nginx.com
FROM ghcr.io/nginx/dependencies/nginx-ubi-ppc64le:nginx-1.27.4@sha256:fff4dde599b89cb22e5cea5d8cfba8c47bcedaa8e6fa549f5fe74a89c733aa2f AS ubi-ppc64le
FROM ghcr.io/nginx/alpine-fips:0.2.4-alpine3.19@sha256:2a7f8451110b588b733e4cb8727a48153057b1debac5c78ef8a539ff63712fa1 AS alpine-fips-3.19
FROM ghcr.io/nginx/alpine-fips:0.2.4-alpine3.21@sha256:5221dec2e33436f2586c743c7aa3ef4626c0ec54184dc3364d101036d4f4a060 AS alpine-fips-3.21
FROM redhat/ubi9-minimal:9.5@sha256:a50731d3397a4ee28583f1699842183d4d24fadcc565c4688487af9ee4e13a44 AS ubi-minimal
FROM golang:1.24-alpine@sha256:ef18ee7117463ac1055f5a370ed18b8750f01589f13ea0b48642f5792b234044 AS golang-builder
FROM redhat/ubi9-minimal:9.5@sha256:e1c4703364c5cb58f5462575dc90345bcd934ddc45e6c32f9c162f2b5617681c AS ubi-minimal
FROM golang:1.24-alpine@sha256:7772cb5322baa875edd74705556d08f0eeca7b9c4b5367754ce3f2f00041ccee AS golang-builder


############################################# Base image for Alpine #############################################
FROM nginx:1.27.4-alpine@sha256:4ff102c5d78d254a6f0da062b3cf39eaf07f01eec0927fd21e219d0af8bc0591 AS alpine

RUN apk add --no-cache libcap libstdc++
RUN printf "%s%s%s\n" "http://nginx.org/packages/mainline/alpine/v" `egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release` "/main" >> /etc/apk/repositories \
&& apk add --no-cache libcap libstdc++ nginx-module-otel \
&& sed -i -e '/nginx.org/d' /etc/apk/repositories


############################################# Base image for Debian #############################################
FROM nginx:1.27.4@sha256:09369da6b10306312cd908661320086bf87fbae1b6b0c49a1f50ba531fef2eab AS debian
FROM nginx:1.27.4@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19 AS debian

RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y libcap2-bin
&& apt-get install --no-install-recommends --no-install-suggests -y \
libcap2-bin curl gnupg2 ca-certificates lsb-release debian-archive-keyring \
&& curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" > /etc/apt/sources.list.d/nginx.list \
&& printf "%s" "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" > /etc/apt/preferences.d/99nginx \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y nginx-module-otel \
&& apt-get purge --auto-remove -y gnupg2 lsb-release curl \
&& rm -rf /var/lib/apt/lists/* /etc/apt/preferences.d/99nginx /etc/apt/sources.list.d/nginx.list


############################################# NGINX files #############################################
Expand Down Expand Up @@ -109,7 +120,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/apk/cert.pem,mode=0644 \
--mount=type=bind,from=nginx-files,src=tracking.info,target=/tmp/nginx/reporting/tracking.info \
export $(cat /tmp/user_agent) \
&& printf "%s\n" "https://${PACKAGE_REPO}/plus/${NGINX_PLUS_VERSION}/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& apk add --no-cache nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check libcap libcurl \
&& apk add --no-cache nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check libcap libcurl \
&& mkdir -p /etc/nginx/reporting/ && cp -av /tmp/nginx/reporting/tracking.info /etc/nginx/reporting/tracking.info \
&& ldconfig /usr/local/lib/ \
&& sed -i -e '/nginx.com/d' /etc/apk/repositories
Expand Down Expand Up @@ -151,7 +162,7 @@ RUN --mount=type=bind,from=alpine-fips-3.19,target=/tmp/fips/ \
&& printf "%s\n" "https://${PACKAGE_REPO}/app-protect/${NGINX_PLUS_VERSION}/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& printf "%s\n" "https://pkgs.nginx.com/app-protect-security-updates/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& printf "%s\n" "https://${PACKAGE_REPO}/nginx-agent/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& if [ "${NGINX_AGENT}" = "true" ]; then apk add --no-cache nginx-agent; fi \
&& mkdir -p /usr/ssl \
&& cp -av /tmp/fips/usr/lib/ossl-modules/fips.so /usr/lib/ossl-modules/fips.so \
Expand Down Expand Up @@ -187,7 +198,7 @@ RUN --mount=type=bind,from=alpine-fips-3.19,target=/tmp/fips/ \
printf "%s\n" "https://${PACKAGE_REPO}/plus/${NGINX_PLUS_VERSION}/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& printf "%s\n" "https://${PACKAGE_REPO}/app-protect-x-plus/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& printf "%s\n" "https://${PACKAGE_REPO}/nginx-agent/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& if [ "${NGINX_AGENT}" = "true" ]; then apk add --no-cache nginx-agent; fi \
&& mkdir -p /usr/ssl \
&& cp -av /tmp/fips/usr/lib/ossl-modules/fips.so /usr/lib/ossl-modules/fips.so \
Expand Down Expand Up @@ -226,7 +237,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode
&& gpg --dearmor -o /usr/share/keyrings/app-protect-archive-keyring.gpg /tmp/app-protect-security-updates.key \
&& cp /tmp/nginx-plus.sources /etc/apt/sources.list.d/nginx-plus.sources \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& apt-get install --no-install-recommends --no-install-suggests -y nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& apt-get purge --auto-remove -y gpg \
&& mkdir -p /etc/nginx/reporting/ \
&& cp -av /tmp/nginx/reporting/tracking.info /etc/nginx/reporting/tracking.info \
Expand Down Expand Up @@ -346,7 +357,7 @@ RUN --mount=type=bind,from=nginx-files,src=nginx_signing.key,target=/tmp/nginx_s
printf "%s\n" "[nginx]" "name=nginx repo" \
"baseurl=https://nginx.org/packages/mainline/centos/9/\$basearch/" \
"gpgcheck=1" "enabled=1" "module_hotfixes=true" > /etc/yum.repos.d/nginx.repo \
&& microdnf --nodocs install -y nginx nginx-module-njs nginx-module-image-filter nginx-module-xslt \
&& microdnf --nodocs install -y nginx nginx-module-njs nginx-module-otel nginx-module-image-filter nginx-module-xslt \
&& rm /etc/yum.repos.d/nginx.repo; \
fi \
&& ubi-clean.sh
Expand All @@ -368,7 +379,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode
--mount=type=bind,from=nginx-files,src=tracking.info,target=/tmp/nginx/reporting/tracking.info \
mkdir -p /etc/nginx/reporting/ && cp -av /tmp/nginx/reporting/tracking.info /etc/nginx/reporting/tracking.info \
&& ubi-setup.sh \
&& microdnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& microdnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& ubi-clean.sh


Expand Down Expand Up @@ -473,7 +484,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode
&& groupadd --system --gid 101 nginx \
&& useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \
&& rpm --import /tmp/nginx_signing.key \
&& dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& if [ "${NGINX_AGENT}" = "true" ]; then dnf --nodocs install -y nginx-agent; fi \
&& sed -i 's/\(def in_container():\)/\1\n return False/g' /usr/lib64/python*/*-packages/rhsm/config.py \
&& subscription-manager register --org=${RHEL_ORGANIZATION} --activationkey=${RHEL_ACTIVATION_KEY} || true \
Expand Down Expand Up @@ -520,7 +531,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode
&& groupadd --system --gid 101 nginx \
&& useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \
&& rpm --import /tmp/nginx_signing.key \
&& dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \
&& dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-otel nginx-plus-module-fips-check \
&& if [ "${NGINX_AGENT}" = "true" ]; then dnf --nodocs install -y nginx-agent; fi \
## end of duplicated code
&& sed -i 's/\(def in_container():\)/\1\n return False/g' /usr/lib64/python*/*-packages/rhsm/config.py \
Expand Down
7 changes: 7 additions & 0 deletions internal/configs/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ type ConfigParams struct {
MainLogFormat []string
MainLogFormatEscaping string
MainMainSnippets []string
MainOtelLoadModule bool
MainOtelTraceInHTTP bool
MainOtelExporterEndpoint string
MainOtelExporterTrustedCA string
MainOtelExporterHeaderName string
MainOtelExporterHeaderValue string
MainOtelServiceName string
MainServerNamesHashBucketSize string
MainServerNamesHashMaxSize string
MainStreamLogFormat []string
Expand Down
84 changes: 84 additions & 0 deletions internal/configs/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,11 @@ func ParseConfigMap(ctx context.Context, cfgm *v1.ConfigMap, nginxPlus bool, has
}
}

_, otelErr := parseConfigMapOpenTelemetry(l, cfgm, cfgParams, eventLog)
if otelErr != nil {
configOk = false
}

if hasAppProtect {
if appProtectFailureModeAction, exists := cfgm.Data["app-protect-failure-mode-action"]; exists {
if appProtectFailureModeAction == "pass" || appProtectFailureModeAction == "drop" {
Expand Down Expand Up @@ -740,6 +745,79 @@ func parseConfigMapZoneSync(l *slog.Logger, cfgm *v1.ConfigMap, cfgParams *Confi
return &cfgParams.ZoneSync, nil
}

//nolint:gocyclo
func parseConfigMapOpenTelemetry(l *slog.Logger, cfgm *v1.ConfigMap, cfgParams *ConfigParams, eventLog record.EventRecorder) (*ConfigParams, error) {
if otelExporterEndpoint, exists := cfgm.Data["otel-exporter-endpoint"]; exists {
otelExporterEndpoint = strings.TrimSpace(otelExporterEndpoint)
if otelExporterEndpoint != "" {
cfgParams.MainOtelExporterEndpoint = otelExporterEndpoint
}
}

if otelExporterHeaderName, exists := cfgm.Data["otel-exporter-header-name"]; exists {
otelExporterHeaderName = strings.TrimSpace(otelExporterHeaderName)
if otelExporterHeaderName != "" {
cfgParams.MainOtelExporterHeaderName = otelExporterHeaderName
}
}

if otelExporterHeaderValue, exists := cfgm.Data["otel-exporter-header-value"]; exists {
otelExporterHeaderValue = strings.TrimSpace(otelExporterHeaderValue)
if otelExporterHeaderValue != "" {
cfgParams.MainOtelExporterHeaderValue = otelExporterHeaderValue
}
}

if otelServiceName, exists := cfgm.Data["otel-service-name"]; exists {
otelServiceName = strings.TrimSpace(otelServiceName)
if otelServiceName != "" {
cfgParams.MainOtelServiceName = otelServiceName
}
}

otelValid := true

if otelTraceInHTTP, exists, err := GetMapKeyAsBool(cfgm.Data, "otel-trace-in-http", cfgm); exists {
if err != nil {
nl.Error(l, err)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, err.Error())
otelValid = false
}
cfgParams.MainOtelTraceInHTTP = otelTraceInHTTP
}

if (cfgParams.MainOtelExporterHeaderName != "" && cfgParams.MainOtelExporterHeaderValue == "") ||
(cfgParams.MainOtelExporterHeaderName == "" && cfgParams.MainOtelExporterHeaderValue != "") {
errorText := "Both 'otel-exporter-header-name' and 'otel-exporter-header-value' must be set or neither"
nl.Error(l, errorText)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
otelValid = false
}

if cfgParams.MainOtelExporterEndpoint != "" {
cfgParams.MainOtelLoadModule = true
}

if cfgParams.MainOtelExporterEndpoint == "" &&
(cfgParams.MainOtelExporterTrustedCA != "" ||
cfgParams.MainOtelExporterHeaderName != "" ||
cfgParams.MainOtelExporterHeaderValue != "" ||
cfgParams.MainOtelServiceName != "" ||
cfgParams.MainOtelTraceInHTTP) {
errorText := "ConfigMap key 'otel-exporter-endpoint' is required when other otel fields are set"
nl.Error(l, errorText)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
otelValid = false
cfgParams.MainOtelTraceInHTTP = false
}

if !otelValid {
return nil, errors.New("invalid OpenTelemetry configuration")
}

return cfgParams, nil
}

// ParseMGMTConfigMap parses the mgmt block ConfigMap into MGMTConfigParams.
//
//nolint:gocyclo
Expand Down Expand Up @@ -913,6 +991,12 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config
NginxStatus: staticCfgParams.NginxStatus,
NginxStatusAllowCIDRs: staticCfgParams.NginxStatusAllowCIDRs,
NginxStatusPort: staticCfgParams.NginxStatusPort,
MainOtelLoadModule: config.MainOtelLoadModule,
MainOtelGlobalTraceEnabled: config.MainOtelTraceInHTTP,
MainOtelExporterEndpoint: config.MainOtelExporterEndpoint,
MainOtelExporterHeaderName: config.MainOtelExporterHeaderName,
MainOtelExporterHeaderValue: config.MainOtelExporterHeaderValue,
MainOtelServiceName: config.MainOtelServiceName,
ProxyProtocol: config.ProxyProtocol,
ResolverAddresses: config.ResolverAddresses,
ResolverIPV6: config.ResolverIPV6,
Expand Down
Loading
Loading