Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
b741bcb
Test funcitonal tests with ipv6 only kind cluster:
shaun-nx Sep 5, 2025
5859e51
Add functional-ipv6-only-tests to ci.yml
shaun-nx Sep 5, 2025
48aed80
Fix end of file
shaun-nx Sep 5, 2025
981658a
Move config file
shaun-nx Sep 5, 2025
145c981
Add `kubectl get nodes -o wide` to check cluster node output for IPv6
shaun-nx Sep 5, 2025
41f36bd
Update ipv6-only tests to the same files as in PR #3792
shaun-nx Sep 5, 2025
e115526
Merge branch 'main' into tests/ipv6-only-environment
shaun-nx Sep 5, 2025
a0cd0cd
Add new line
shaun-nx Sep 5, 2025
bfd0615
Merge branch 'main' into tests/ipv6-only-environment
shaun-nx Sep 5, 2025
c9c6528
Potential fix for code scanning alert no. 486: Code injection
shaun-nx Sep 5, 2025
b694824
Merge branch 'main' into tests/ipv6-only-environment
shaun-nx Sep 8, 2025
545ed03
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 8, 2025
6361dfb
Remove sysctl
shaun-nx Sep 8, 2025
fc846cb
Update ipv6-only job in `ci.yml`
shaun-nx Sep 8, 2025
574fea9
Add project name to goreleaser.yml
shaun-nx Sep 8, 2025
9cbac69
Remove binary build stage
shaun-nx Sep 8, 2025
5ded3a8
Re-add goreleaser step
shaun-nx Sep 8, 2025
85c9ea2
Add additional args to goreleaser
shaun-nx Sep 8, 2025
c9a04d3
Explicitly specifiy goreleaser config path
shaun-nx Sep 8, 2025
031f11e
Remove --rm-dist flag
shaun-nx Sep 8, 2025
c5198bc
Update go releaser config path
shaun-nx Sep 9, 2025
d01246e
Add workflow file to test ipv6 only in GKE
shaun-nx Sep 9, 2025
bdc569d
Add cleanup step
shaun-nx Sep 9, 2025
350ffc5
Merge branch 'main' into tests/ipv6-only-environment
shaun-nx Sep 9, 2025
ea8ddde
Fix pre-commit errors
shaun-nx Sep 9, 2025
2cad235
Enable NFR tests to run in an IPv6 enabled environment
shaun-nx Sep 9, 2025
fc0295f
Enable NFR tests to run in IPv6 environments
shaun-nx Sep 9, 2025
fa04cc4
Remove IPv6 functional tests from ci
shaun-nx Sep 9, 2025
6bac829
Update logic for ipFamily helm parameter
shaun-nx Sep 9, 2025
012ac6c
Update logic for helm parameters
shaun-nx Sep 9, 2025
eb44e3d
Fix indentation
shaun-nx Sep 9, 2025
ea98277
Fix variable name
shaun-nx Sep 9, 2025
8cc7e0a
Fix helm parameters
shaun-nx Sep 9, 2025
780e2af
Add ipv6_enabled to job outputs
shaun-nx Sep 9, 2025
e2bc403
Update IPv6 fariable name in tests/Makefile
shaun-nx Sep 9, 2025
a4828f9
Update vars to `vars.inputs.ipv6_enabled`
shaun-nx Sep 9, 2025
7843b32
Update if statement
shaun-nx Sep 9, 2025
6e4b8fa
Update IPv6 variable call
shaun-nx Sep 9, 2025
6de3ba4
Update `--create-subnetwork` flag for cluster creation
shaun-nx Sep 9, 2025
6a0ef07
Test adding IPv6 VPC and Subnet.
shaun-nx Sep 10, 2025
185f5e2
Remove unused flag
shaun-nx Sep 10, 2025
8300b7e
Update ipv6-access-type to EXTERNAL
shaun-nx Sep 10, 2025
91f8e47
Add firewall rules for VPC
shaun-nx Sep 10, 2025
9b5e541
Add custom subnet to cluster creation
shaun-nx Sep 10, 2025
d6998a8
Add network to cluster creation
shaun-nx Sep 10, 2025
caa83ae
Remove networking flags for debugging
shaun-nx Sep 10, 2025
a9e6a62
Re add network flags
shaun-nx Sep 10, 2025
c5731c2
Update zone to us-west1-c
shaun-nx Sep 10, 2025
8bc4086
Create custom IPv6 networks and subnets for GCP VMs
shaun-nx Sep 11, 2025
373683b
Update subnet flag for instance creation
shaun-nx Sep 11, 2025
740f9c3
Fix subnet flag
shaun-nx Sep 11, 2025
faf23f1
Update nwtwork settings
shaun-nx Sep 11, 2025
6dc68d7
Add echos for debugging
shaun-nx Sep 11, 2025
02ac018
Add additional echos for debugging
shaun-nx Sep 11, 2025
5f50210
Correctly extract external IP for IPv6 only environments
shaun-nx Sep 11, 2025
fa7aa8b
Debug network auth for IPv6
shaun-nx Sep 11, 2025
1cc99c3
Add missing parenthesis
shaun-nx Sep 11, 2025
9a92d54
Do not update cluster networks with IPv6
shaun-nx Sep 11, 2025
141933f
Add temporary cleanup for conflicting subnet
shaun-nx Sep 11, 2025
774c0e7
Set stack tpye to dual and IPv6 to internal only
shaun-nx Sep 11, 2025
e1e46e8
Merge branch 'main' into tests/ipv6-only-environment
shaun-nx Sep 12, 2025
a5eedd0
Add cidr range to `compute networks subnets create`
shaun-nx Sep 12, 2025
03671bf
Update sutnet mask
shaun-nx Sep 12, 2025
bf3515c
Update workflow to delete conflicting resources
shaun-nx Sep 12, 2025
624beed
Delete forwarding rules
shaun-nx Sep 12, 2025
745123b
Change region to us-west1-b and set number of nodes to 1
shaun-nx Sep 12, 2025
b30d389
Update delete commands
shaun-nx Sep 12, 2025
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
227 changes: 227 additions & 0 deletions .github/workflows/ipv6-only.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
name: IPv6-Only Testing

on:
workflow_call:
inputs:
image:
required: true
type: string
k8s-version:
required: true
type: string

defaults:
run:
shell: bash

env:
PLUS_USAGE_ENDPOINT: ${{ secrets.JWT_PLUS_REPORTING_ENDPOINT }}

permissions:
contents: read

jobs:
ipv6-only-tests:
name: Run IPv6-Only Tests
runs-on: ubuntu-24.04
if: ${{ !github.event.pull_request.head.repo.fork || inputs.image != 'plus' }}
env:
DOCKER_BUILD_SUMMARY: false
steps:
- name: Checkout Repository
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
fetch-depth: 0

- name: Configure GOPROXY
id: goproxy
run: |
if [[ "${{ secrets.ARTIFACTORY_USER }}" == "" ]]; then
GOPROXY_VALUE="direct"
else
GOPROXY_VALUE="https://${{ secrets.ARTIFACTORY_USER }}:${{ secrets.ARTIFACTORY_TOKEN }}@${{ secrets.ARTIFACTORY_DEV_ENDPOINT }}"
fi
echo "GOPROXY=${GOPROXY_VALUE}" >> $GITHUB_ENV

- name: Setup Golang Environment
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: stable

- name: Set GOPATH
run: echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV

- name: Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

- name: NGF Docker meta
id: ngf-meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: |
name=ghcr.io/nginx/nginx-gateway-fabric
tags: |
type=semver,pattern={{version}}
type=schedule
type=edge
type=ref,event=pr
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}

- name: NGINX Docker meta
id: nginx-meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: |
name=ghcr.io/nginx/nginx-gateway-fabric/${{ inputs.image == 'plus' && 'nginx-plus' || inputs.image }}
tags: |
type=semver,pattern={{version}}
type=edge
type=schedule
type=ref,event=pr
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}

- name: Build binary
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
version: v2.12.0 # renovate: datasource=github-tags depName=goreleaser/goreleaser
args:
build --single-target --snapshot --clean --config=goreleaser.yml
env:
TELEMETRY_ENDPOINT: otel-collector-opentelemetry-collector.collector.svc.cluster.local:4317
TELEMETRY_ENDPOINT_INSECURE: "true"

- name: Build NGF Docker Image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
file: build/Dockerfile
tags: ${{ steps.ngf-meta.outputs.tags }}
context: "."
load: true
cache-from: type=gha,scope=ngf
pull: true
target: goreleaser

- name: Build NGINX Docker Image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
file: build/Dockerfile${{ inputs.image == 'nginx' && '.nginx' || '' }}${{ inputs.image == 'plus' && '.nginxplus' || ''}}
tags: ${{ steps.nginx-meta.outputs.tags }}
context: "."
load: true
cache-from: type=gha,scope=${{ inputs.image }}-ipv6
pull: true
build-args: |
NJS_DIR=internal/controller/nginx/modules/src
NGINX_CONF_DIR=internal/controller/nginx/conf
BUILD_AGENT=gha

- name: Setup license file for plus
if: ${{ inputs.image == 'plus' }}
env:
PLUS_LICENSE: ${{ secrets.JWT_PLUS_REPORTING }}
run: echo "${PLUS_LICENSE}" > license.jwt

- name: Deploy IPv6-Only Kubernetes
id: k8s
run: |
# Enable IPv6 and container network options
# sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
# sudo sysctl -w net.ipv6.conf.all.forwarding=1

# Create IPv6-only kind cluster
kind create cluster \
--name ${{ github.run_id }}-ipv6 \
--image=kindest/node:${{ inputs.k8s-version }} \
--config=config/cluster/kind-ipv6-only.yaml

# Load images into the cluster
kind load docker-image ${{ join(fromJSON(steps.ngf-meta.outputs.json).tags, ' ') }} ${{ join(fromJSON(steps.nginx-meta.outputs.json).tags, ' ') }} --name ${{ github.run_id }}-ipv6

# Verify nodes are ipv6 only
kubectl get nodes -o wide

- name: Install NGF with IPv6 Configuration
run: |
ngf_prefix=ghcr.io/nginx/nginx-gateway-fabric
ngf_tag=${{ steps.ngf-meta.outputs.version }}
# Install with IPv6-specific configuration
CLUSTER_NAME=${{ github.run_id }}-ipv6 \
HELM_PARAMETERS="--set nginx.config.ipFamily=ipv6 --set nginx.service.type=ClusterIP" \
make helm-install-local${{ inputs.image == 'plus' && '-with-plus' || ''}} PREFIX=${ngf_prefix} TAG=${ngf_tag}

working-directory: ./tests

- name: Deploy Test Applications
run: |
kubectl apply -f tests/manifests/ipv6-test-app.yaml

- name: Wait for NGF and Applications to be Ready
run: |
echo "Waiting for NGF to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/nginx-gateway -n nginx-gateway
echo "Waiting for test applications to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/test-app-ipv6

- name: Deploy IPv6 Test Client
run: |
kubectl apply -f tests/manifests/test-client-ipv6.yaml
kubectl wait --for=condition=ready --timeout=300s pod/ipv6-test-client

- name: Get NGF IPv6 Address
id: ngf-address
run: |
# Get the NGF service IPv6 address
NGF_IPV6=$(kubectl get service nginx-gateway -n nginx-gateway -o jsonpath='{.spec.clusterIP}')
echo "NGF IPv6 Address: $NGF_IPV6"
echo "ngf_ipv6=$NGF_IPV6" >> $GITHUB_OUTPUT

- name: Run IPv6 Connectivity Tests
run: |
echo "=== Running IPv6-Only Tests ==="
# Test 1: Basic connectivity test using test client pod
echo "Test 1: Basic IPv6 connectivity"
kubectl exec ipv6-test-client -- curl --version
kubectl exec ipv6-test-client -- nslookup nginx-gateway.nginx-gateway.svc.cluster.local
# Test 2: Test NGF service directly via IPv6
echo "Test 2: NGF Service IPv6 connectivity"
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
-H "Host: ipv6-test.example.com" \
"http://[${{ steps.ngf-address.outputs.ngf_ipv6 }}]:80/" || echo "Direct NGF test failed"
# Test 3: Test via service DNS
echo "Test 3: Service DNS IPv6 connectivity"
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
-H "Host: ipv6-test.example.com" \
"http://nginx-gateway.nginx-gateway.svc.cluster.local:80/" || echo "Service DNS test failed"

- name: Validate IPv6-Only Configuration
run: |
echo "=== Validating IPv6-Only Configuration ==="
# Check NGF configuration
echo "NGF Pod IPv6 addresses:"
kubectl get pods -n nginx-gateway -o wide
echo "NGF Service configuration:"
kubectl get service nginx-gateway -n nginx-gateway -o yaml
echo "Gateway and HTTPRoute status:"
kubectl get gateway,httproute -A -o wide
echo "Test application service configuration:"
kubectl get service test-app-ipv6-service -o yaml

- name: Collect Logs
if: always()
run: |
echo "=== Collecting logs for debugging ==="
echo "NGF Controller logs:"
kubectl logs -n nginx-gateway deployment/nginx-gateway -c nginx-gateway-controller --tail=100 || true
echo "NGINX logs:"
kubectl logs -n nginx-gateway deployment/nginx-gateway -c nginx --tail=100 || true
echo "Test client logs:"
kubectl logs ipv6-test-client --tail=100 || true
echo "Cluster events:"
kubectl get events --sort-by='.lastTimestamp' --all-namespaces --tail=50 || true

- name: Cleanup
if: always()
env:
RUN_ID: ${{ github.run_id }}
run: |
kind delete cluster --name "$RUN_ID-ipv6" || true
50 changes: 34 additions & 16 deletions .github/workflows/nfr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ on:
default: both
type: choice
options: [oss, plus, both]
ipv6_enabled:
description: Whether to run the tests in an IPv6 enabled environment
required: false
default: false
type: boolean
schedule:
- cron: "0 16 1,15 * *" # Run on the 1st and 15th of every month at 16:00 UTC

Expand All @@ -56,6 +61,7 @@ jobs:
test_label: ${{ github.event.inputs.test_label || 'all' }}
version: ${{ github.event.inputs.version || 'edge' }}
image_tag: ${{ github.event.inputs.image_tag || 'edge' }}
ipv6_enabled: ${{ github.event.inputs.ipv6_enabled || 'false' }}
types: ${{ steps.var.outputs.types }}
permissions:
contents: read
Expand Down Expand Up @@ -126,16 +132,28 @@ jobs:
echo "PLUS_ENABLED=${{ matrix.type == 'plus' }}" >> vars.env
echo "GINKGO_LABEL=" >> vars.env
echo "NGF_VERSION=${{ needs.vars.outputs.version }}" >> vars.env
echo "GKE_NUM_NODES=12" >> vars.env
echo "GKE_NUM_NODES=1" >> vars.env
echo "GKE_MACHINE_TYPE=n2d-standard-16" >> vars.env
echo "PLUS_USAGE_ENDPOINT=${{ secrets.JWT_PLUS_REPORTING_ENDPOINT }}" >> vars.env

if [ "${{ needs.vars.outputs.ipv6_enabled }}" = "true" ]; then
echo "IPV6_ENABLED=true" >> vars.env
echo "HELM_PARAMETERS=\"--set nginx.config.ipFamily=ipv6\"" >> vars.env
fi
- name: Setup license file for plus
if: matrix.type == 'plus'
env:
PLUS_LICENSE: ${{ secrets.JWT_PLUS_REPORTING }}
run: echo "${PLUS_LICENSE}" > license.jwt

# - name: TMP Cleanup conflicting resources
# working-directory: ./tests
# run: |
# echo "tmp delete conflicting subnet"
# gcloud compute forwarding-rules delete gk3-nfr-tests-17637219369-oss-b6387c3a-d2289ac6-pe --region=us-west1 --project=${{ secrets.GCP_PROJECT_ID }} --quiet || true
# gcloud compute addresses delete gk3-nfr-tests-17637219369-oss-b6387c3a-d2289ac6-pe --region=us-west1 --project=${{ secrets.GCP_PROJECT_ID }} --quiet || true
# gcloud compute networks subnets delete gke-nfr-tests-17637219369-oss-acf63488-pe-subnet --region=us-west1 --quiet || true
# rm -rf scripts/vars.env

- name: Create GKE cluster
working-directory: ./tests
run: make create-gke-cluster CI=true
Expand All @@ -148,20 +166,20 @@ jobs:
working-directory: ./tests
run: make create-gke-router || true

- name: Run Tests
working-directory: ./tests
run: |
if ${{ needs.vars.outputs.test_label != 'all' }}; then
sed -i '/^GINKGO_LABEL=/s/=.*/="${{ needs.vars.outputs.test_label }}"/' "scripts/vars.env" && make nfr-test CI=true;
else
make nfr-test CI=true;
fi

- name: Upload Artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: results-${{ matrix.type }}
path: tests/results/**/*-${{ matrix.type }}.*
# - name: Run Tests
# working-directory: ./tests
# run: |
# if ${{ needs.vars.outputs.test_label != 'all' }}; then
# sed -i '/^GINKGO_LABEL=/s/=.*/="${{ needs.vars.outputs.test_label }}"/' "scripts/vars.env" && make nfr-test CI=true;
# else
# make nfr-test CI=true;
# fi

# - name: Upload Artifacts
# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
# with:
# name: results-${{ matrix.type }}
# path: tests/results/**/*-${{ matrix.type }}.*

- name: Cleanup
working-directory: ./tests
Expand Down
1 change: 1 addition & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
version: 2
project_name: nginx-gateway-fabric
env:
- CGO_ENABLED=0

Expand Down
7 changes: 7 additions & 0 deletions config/cluster/kind-ipv6-only.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
networking:
ipFamily: ipv6
apiServerAddress: "::1"
61 changes: 61 additions & 0 deletions tests/manifests/ipv6-test-app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-ipv6
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app-ipv6
template:
metadata:
labels:
app: test-app-ipv6
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
resources:
limits:
cpu: "100m"
memory: "128Mi"
requests:
cpu: "50m"
memory: "64Mi"
---
apiVersion: v1
kind: Service
metadata:
name: test-app-ipv6-service
namespace: default
spec:
selector:
app: test-app-ipv6
ports:
- port: 80
targetPort: 80
ipFamilies: [IPv6]
ipFamilyPolicy: SingleStack
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: test-route-ipv6
namespace: default
spec:
parentRefs:
- name: nginx-gateway
namespace: nginx-gateway
hostnames:
- "ipv6-test.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: test-app-ipv6-service
port: 80
Loading
Loading