diff --git a/Makefile b/Makefile index e8a5902449..1391c54abd 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ HELM_SCHEMA_VERSION = 0.18.1 PREFIX ?= nginx-gateway-fabric## The name of the NGF image. For example, nginx-gateway-fabric NGINX_PREFIX ?= $(PREFIX)/nginx## The name of the nginx image. For example: nginx-gateway-fabric/nginx NGINX_PLUS_PREFIX ?= $(PREFIX)/nginx-plus## The name of the nginx plus image. For example: nginx-gateway-fabric/nginx-plus +BUILD_OS ?= ## The OS of the nginx image. Possible values: ubi and empty string, which defaults to alpine. NGINX_SERVICE_TYPE ?= NodePort## The type of the nginx service. Possible values: NodePort, LoadBalancer, ClusterIP PULL_POLICY ?= Never## The pull policy of the images. Possible values: Always, IfNotPresent, Never TAG ?= $(VERSION:v%=%)## The tag of the image. For example, 1.1.0 @@ -85,21 +86,21 @@ build-prod-ngf-image: build-ngf-image ## Build the NGF docker image for producti .PHONY: build-ngf-image build-ngf-image: check-for-docker build ## Build the NGF docker image - docker build --platform linux/$(GOARCH) --build-arg BUILD_AGENT=$(BUILD_AGENT) --target $(strip $(TARGET)) -f $(SELF_DIR)build/Dockerfile -t $(strip $(PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) + docker build --platform linux/$(GOARCH) --build-arg BUILD_AGENT=$(BUILD_AGENT) --target $(strip $(TARGET)) -f $(SELF_DIR)build/$(if $(BUILD_OS),$(BUILD_OS)/)Dockerfile -t $(strip $(PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) .PHONY: build-prod-nginx-image build-prod-nginx-image: build-nginx-image ## Build the custom nginx image for production .PHONY: build-nginx-image build-nginx-image: check-for-docker ## Build the custom nginx image - docker build --platform linux/$(GOARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) -f $(SELF_DIR)build/Dockerfile.nginx -t $(strip $(NGINX_PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) + docker build --platform linux/$(GOARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) -f $(SELF_DIR)build/$(if $(BUILD_OS),$(BUILD_OS)/)Dockerfile.nginx -t $(strip $(NGINX_PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) .PHONY: build-prod-nginx-plus-image build-prod-nginx-plus-image: build-nginx-plus-image ## Build the custom nginx plus image for production .PHONY: build-nginx-plus-image build-nginx-plus-image: check-for-docker ## Build the custom nginx plus image - docker build --platform linux/$(GOARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) $(strip $(NGINX_DOCKER_BUILD_PLUS_ARGS)) -f $(SELF_DIR)build/Dockerfile.nginxplus -t $(strip $(NGINX_PLUS_PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) + docker build --platform linux/$(GOARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) $(strip $(NGINX_DOCKER_BUILD_PLUS_ARGS)) -f $(SELF_DIR)build/$(if $(BUILD_OS),$(BUILD_OS)/)Dockerfile.nginxplus -t $(strip $(NGINX_PLUS_PREFIX)):$(strip $(TAG)) $(strip $(SELF_DIR)) .PHONY: check-for-docker check-for-docker: ## Check if Docker is installed diff --git a/build/entrypoint.sh b/build/entrypoint.sh index 9e9552b338..3c05aebcd9 100755 --- a/build/entrypoint.sh +++ b/build/entrypoint.sh @@ -40,12 +40,12 @@ fi nginx_pid=$! SECONDS=0 - -while ! ps -ef | grep "nginx: master process" | grep -v grep; do - if ((SECONDS > 5)); then +while [[ ! -f /var/run/nginx.pid ]] && [[ ! -f /var/run/nginx/nginx.pid ]]; do + if ((SECONDS > 30)); then echo "couldn't find nginx master process" exit 1 fi + sleep 1 done # start nginx-agent, pass args diff --git a/build/ubi/Dockerfile b/build/ubi/Dockerfile new file mode 100644 index 0000000000..81cc76e417 --- /dev/null +++ b/build/ubi/Dockerfile @@ -0,0 +1,30 @@ +# syntax=docker/dockerfile:1.18 +FROM golang:1.25 AS builder + +WORKDIR /go/src/github.com/nginx/nginx-gateway-fabric + +COPY go.mod go.sum /go/src/github.com/nginx/nginx-gateway-fabric/ +RUN go mod download + +COPY . /go/src/github.com/nginx/nginx-gateway-fabric +RUN make build + +FROM golang:1.25 AS ca-certs-provider + +FROM redhat/ubi9-minimal:9.6 AS ngf-ubi-minimal +# CA certs are needed for telemetry report so that NGF can verify the server's certificate. +COPY --from=ca-certs-provider --link /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +USER 101:1001 +ARG BUILD_AGENT +ENV BUILD_AGENT=${BUILD_AGENT} +ENTRYPOINT [ "/usr/bin/gateway" ] + +FROM ngf-ubi-minimal AS container +COPY --from=builder /go/src/github.com/nginxinc/nginx-gateway-fabric/build/out/gateway /usr/bin/gateway + +FROM ngf-ubi-minimal AS local +COPY ./build/out/gateway /usr/bin/gateway + +FROM ngf-ubi-minimal AS goreleaser +ARG TARGETARCH +COPY dist/gateway_linux_$TARGETARCH*/gateway /usr/bin/gateway diff --git a/build/ubi/Dockerfile.nginx b/build/ubi/Dockerfile.nginx new file mode 100644 index 0000000000..71adbb37e7 --- /dev/null +++ b/build/ubi/Dockerfile.nginx @@ -0,0 +1,70 @@ +# syntax=docker/dockerfile:1.18 +FROM scratch AS nginx-files + +# Repository and key files for UBI-based builds +ADD --link --chown=101:1001 https://nginx.org/keys/nginx_signing.key nginx_signing.key +ADD --link --chown=101:1001 build/ubi/repos/nginx.repo nginx.repo +ADD --link --chown=101:1001 build/ubi/repos/agent.repo agent.repo + +FROM ghcr.io/nginx/dependencies/nginx-ubi:ubi9@sha256:01a32246761b9bbe47a6a29bcd8ca6e9b6e331b3bdfa372d8987b622276f7025 AS ubi9-packages + +FROM redhat/ubi9-minimal:9.6 AS ubi-nginx + +# renovate: datasource=github-tags depName=nginx/agent +ARG NGINX_AGENT_VERSION=v3.3.1 +ARG NJS_DIR +ARG NGINX_CONF_DIR +ARG BUILD_AGENT + +LABEL name="F5 NGINX Gateway Fabric NGINX OSS" \ + maintainer="kubernetes@nginx.com" \ + vendor="F5 NGINX" \ + summary="NGINX Gateway Fabric" \ + description="NGINX Gateway Fabric provides an implementation for the Gateway API using NGINX as the data plane." \ + org.nginx.ngf.image.build.agent="${BUILD_AGENT}" \ + io.k8s.description="NGINX Gateway Fabric provides an implementation for the Gateway API using NGINX as the data plane." \ + io.openshift.tags="nginx,gateway,kubernetes,openshift" + +COPY --link --chown=101:1001 LICENSE /licenses/ + +# Install NGINX with packages +RUN --mount=type=bind,from=nginx-files,src=nginx_signing.key,target=/tmp/nginx_signing.key \ + --mount=type=bind,from=nginx-files,src=nginx.repo,target=/etc/yum.repos.d/nginx.repo \ + --mount=type=bind,from=nginx-files,src=agent.repo,target=/etc/yum.repos.d/agent.repo \ + --mount=type=bind,from=ubi9-packages,src=/,target=/ubi-bin/ \ + # Import NGINX signing key + rpm --import /tmp/nginx_signing.key \ + # Install c-ares from the dependencies image (contains required libs) + && rpm -Uvh /ubi-bin/c-ares-*.rpm \ + # Create nginx user with consistent UID/GID + && groupadd -g 1001 nginx \ + && useradd -r -u 101 -g nginx -s /sbin/nologin -d /var/cache/nginx nginx \ + # Install NGINX and modules including OTEL + && microdnf --nodocs install -y nginx nginx-module-njs nginx-module-otel \ + # Install nginx-agent + && microdnf --nodocs install -y nginx-agent-${NGINX_AGENT_VERSION#v}* \ + # Clean up (only remove what we can) + && microdnf clean all \ + && rm -rf /var/cache/yum + +# Configure directories and logging +RUN mkdir -p /usr/lib/nginx/modules /var/run/nginx /usr/lib64/nginx/modules \ + # Forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ + && mv /usr/lib64/nginx/modules/ngx_* /usr/lib/nginx/modules/ + +# Set proper permissions for nginx user +RUN chown -R 101:1001 /etc/nginx /var/cache/nginx + +# Copy configuration files and scripts +COPY build/entrypoint.sh /agent/entrypoint.sh +COPY ${NJS_DIR}/ /usr/lib/nginx/modules/njs/ +COPY ${NGINX_CONF_DIR}/nginx.conf /etc/nginx/nginx.conf +COPY ${NGINX_CONF_DIR}/grpc-error-locations.conf /etc/nginx/grpc-error-locations.conf +COPY ${NGINX_CONF_DIR}/grpc-error-pages.conf /etc/nginx/grpc-error-pages.conf + +# Switch to non-root user +USER 101:1001 + +ENTRYPOINT ["/agent/entrypoint.sh"] diff --git a/build/ubi/Dockerfile.nginxplus b/build/ubi/Dockerfile.nginxplus new file mode 100644 index 0000000000..6224136c09 --- /dev/null +++ b/build/ubi/Dockerfile.nginxplus @@ -0,0 +1,81 @@ +# syntax=docker/dockerfile:1.18 +FROM scratch AS nginx-files + +# NGINX Plus repo and key files (must be provided at build time) +ADD --link --chown=101:1001 https://cs.nginx.com/static/files/plus-9.repo nginx-plus.repo +ADD --link --chown=101:1001 https://nginx.org/keys/nginx_signing.key nginx_signing.key +ADD --link --chown=101:1001 build/ubi/repos/agent.repo agent.repo + +FROM ghcr.io/nginx/dependencies/nginx-ubi:ubi9@sha256:01a32246761b9bbe47a6a29bcd8ca6e9b6e331b3bdfa372d8987b622276f7025 AS ubi9-packages + +FROM redhat/ubi9-minimal:9.6 AS ubi-nginx-plus + +ARG NGINX_PLUS_VERSION=R35 + +# renovate: datasource=github-tags depName=nginx/agent +ARG NGINX_AGENT_VERSION=v3.3.1 +ARG NJS_DIR +ARG NGINX_CONF_DIR +ARG BUILD_AGENT + +LABEL name="F5 NGINX Gateway Fabric NGINX Plus" \ + maintainer="kubernetes@nginx.com" \ + vendor="F5 NGINX" \ + summary="NGINX Gateway Fabric" \ + description="NGINX Gateway Fabric provides an implementation for the Gateway API using NGINX as the data plane." \ + org.nginx.ngf.image.build.agent="${BUILD_AGENT}" \ + io.k8s.description="NGINX Gateway Fabric provides an implementation for the Gateway API using NGINX as the data plane." \ + io.openshift.tags="nginx,gateway,kubernetes,openshift" + +COPY --link --chown=101:1001 LICENSE /licenses/ + +# Install NGINX Plus and modules +RUN --mount=type=bind,from=nginx-files,src=nginx-plus.repo,target=/etc/yum.repos.d/nginx-plus.repo \ + --mount=type=bind,from=nginx-files,src=agent.repo,target=/etc/yum.repos.d/agent.repo \ + --mount=type=bind,from=nginx-files,src=nginx_signing.key,target=/tmp/nginx_signing.key \ + --mount=type=bind,from=ubi9-packages,src=/,target=/ubi-bin/ \ + --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + # Install shadow-utils for useradd and subscription-manager for repo access + microdnf --nodocs install -y shadow-utils subscription-manager \ + && rpm --import /tmp/nginx_signing.key \ + # Install c-ares from the dependencies image (contains required libs) + && rpm -Uvh /ubi-bin/c-ares-*.rpm \ + # Create nginx user with consistent UID/GID + && groupadd -g 1001 nginx \ + && useradd -r -u 101 -g nginx -s /sbin/nologin -d /var/cache/nginx nginx \ + # Install NGINX Plus and modules (njs, otel) + && microdnf --nodocs install -y nginx-plus-${NGINX_PLUS_VERSION,,} \ + && microdnf --nodocs install -y nginx-plus-module-njs-${NGINX_PLUS_VERSION,,} nginx-plus-module-otel-${NGINX_PLUS_VERSION,,} \ + # Install nginx-agent + && microdnf --nodocs install -y nginx-agent-${NGINX_AGENT_VERSION#v}* \ + # Clean up + && microdnf remove -y shadow-utils subscription-manager \ + && microdnf clean all \ + && rm -rf /var/cache/yum + +# Configure directories and logging +RUN mkdir -p /usr/lib/nginx/modules /var/run/nginx /usr/lib64/nginx/modules \ + # Forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ + && mv /usr/lib64/nginx/modules/ngx_* /usr/lib/nginx/modules/ + +# Copy default html files to a writable location +RUN mkdir -p /etc/nginx/html \ + && cp /usr/share/nginx/html/* /etc/nginx/html/ + +# Set proper permissions for nginx user +RUN chown -R 101:1001 /etc/nginx /var/cache/nginx + +# Copy configuration files and scripts +COPY build/entrypoint.sh /agent/entrypoint.sh +COPY ${NJS_DIR}/ /usr/lib/nginx/modules/njs/ +COPY ${NGINX_CONF_DIR}/nginx.conf /etc/nginx/nginx.conf +COPY ${NGINX_CONF_DIR}/grpc-error-locations.conf /etc/nginx/grpc-error-locations.conf +COPY ${NGINX_CONF_DIR}/grpc-error-pages.conf /etc/nginx/grpc-error-pages.conf + +# Switch to non-root user +USER 101:1001 + +ENTRYPOINT ["/agent/entrypoint.sh"] diff --git a/build/ubi/repos/agent.repo b/build/ubi/repos/agent.repo new file mode 100644 index 0000000000..36665b874b --- /dev/null +++ b/build/ubi/repos/agent.repo @@ -0,0 +1,6 @@ +[agent] +name=agent repo +baseurl=https://packages.nginx.org/nginx-agent/centos/9/$basearch/ +gpgcheck=1 +enabled=1 +module_hotfixes=true diff --git a/build/ubi/repos/nginx.repo b/build/ubi/repos/nginx.repo new file mode 100644 index 0000000000..7c8e132faf --- /dev/null +++ b/build/ubi/repos/nginx.repo @@ -0,0 +1,6 @@ +[nginx] +name=nginx repo +baseurl=https://packages.nginx.org/nginx/mainline/centos/9/$basearch/ +gpgcheck=1 +enabled=1 +module_hotfixes=true