Skip to content

Commit d01246e

Browse files
committed
Add workflow file to test ipv6 only in GKE
1 parent c5198bc commit d01246e

File tree

5 files changed

+306
-2
lines changed

5 files changed

+306
-2
lines changed

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,22 @@ jobs:
301301
image: ${{ matrix.image }}
302302
k8s-version: ${{ matrix.k8s-version }}
303303

304+
gke-ipv6-only-tests:
305+
name: GKE IPv6 Only Tests
306+
needs: [vars, build-oss]
307+
strategy:
308+
fail-fast: false
309+
matrix:
310+
image: [nginx]
311+
k8s-version:
312+
[
313+
"${{ needs.vars.outputs.k8s_latest }}",
314+
]
315+
uses: ./.github/workflows/gke-ipv6-only.yml
316+
with:
317+
image: ${{ matrix.image }}
318+
k8s-version: ${{ matrix.k8s-version }}
319+
304320
conformance-tests:
305321
name: Conformance tests
306322
needs: [vars, build-oss, build-plus]
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
name: GKE IPv6-Only Testing
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
image:
7+
required: true
8+
type: string
9+
k8s-version:
10+
required: true
11+
type: string
12+
13+
defaults:
14+
run:
15+
shell: bash
16+
17+
env:
18+
PLUS_USAGE_ENDPOINT: ${{ secrets.JWT_PLUS_REPORTING_ENDPOINT }}
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
ipv6-only-tests:
25+
name: Run IPv6-Only Tests
26+
runs-on: ubuntu-24.04
27+
if: ${{ !github.event.pull_request.head.repo.fork || inputs.image != 'plus' }}
28+
env:
29+
DOCKER_BUILD_SUMMARY: false
30+
steps:
31+
- name: Checkout Repository
32+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
33+
with:
34+
fetch-depth: 0
35+
36+
- name: Authenticate to Google Cloud
37+
id: auth
38+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
39+
with:
40+
token_format: access_token
41+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY }}
42+
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
43+
44+
- name: Login to GAR
45+
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
46+
with:
47+
registry: us-docker.pkg.dev
48+
username: oauth2accesstoken
49+
password: ${{ steps.auth.outputs.access_token }}
50+
51+
- name: Set up Cloud SDK
52+
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
53+
with:
54+
project_id: ${{ secrets.GCP_PROJECT_ID }}
55+
install_components: kubectl
56+
57+
- name: Create GKE cluster
58+
working-directory: ./tests
59+
run: make create-gke-cluster CI=true IPv6_ONLY=true
60+
61+
- name: Create and setup VM
62+
working-directory: ./tests
63+
run: make create-and-setup-vm
64+
65+
- name: Create and setup Router
66+
working-directory: ./tests
67+
run: make create-gke-router || true
68+
69+
- name: Configure GOPROXY
70+
id: goproxy
71+
run: |
72+
if [[ "${{ secrets.ARTIFACTORY_USER }}" == "" ]]; then
73+
GOPROXY_VALUE="direct"
74+
else
75+
GOPROXY_VALUE="https://${{ secrets.ARTIFACTORY_USER }}:${{ secrets.ARTIFACTORY_TOKEN }}@${{ secrets.ARTIFACTORY_DEV_ENDPOINT }}"
76+
fi
77+
echo "GOPROXY=${GOPROXY_VALUE}" >> $GITHUB_ENV
78+
79+
- name: Setup Golang Environment
80+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
81+
with:
82+
go-version: stable
83+
84+
- name: Set GOPATH
85+
run: echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
86+
87+
- name: Docker Buildx
88+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
89+
90+
- name: NGF Docker meta
91+
id: ngf-meta
92+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
93+
with:
94+
images: |
95+
name=ghcr.io/nginx/nginx-gateway-fabric
96+
tags: |
97+
type=semver,pattern={{version}}
98+
type=schedule
99+
type=edge
100+
type=ref,event=pr
101+
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}
102+
103+
- name: NGINX Docker meta
104+
id: nginx-meta
105+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
106+
with:
107+
images: |
108+
name=ghcr.io/nginx/nginx-gateway-fabric/${{ inputs.image == 'plus' && 'nginx-plus' || inputs.image }}
109+
tags: |
110+
type=semver,pattern={{version}}
111+
type=edge
112+
type=schedule
113+
type=ref,event=pr
114+
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}
115+
116+
- name: Build binary
117+
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
118+
with:
119+
version: v2.12.0 # renovate: datasource=github-tags depName=goreleaser/goreleaser
120+
args:
121+
build --single-target --snapshot --clean --config=goreleaser.yml
122+
env:
123+
TELEMETRY_ENDPOINT: otel-collector-opentelemetry-collector.collector.svc.cluster.local:4317
124+
TELEMETRY_ENDPOINT_INSECURE: "true"
125+
126+
- name: Build NGF Docker Image
127+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
128+
with:
129+
file: build/Dockerfile
130+
tags: ${{ steps.ngf-meta.outputs.tags }}
131+
context: "."
132+
load: true
133+
cache-from: type=gha,scope=ngf
134+
pull: true
135+
target: goreleaser
136+
137+
- name: Build NGINX Docker Image
138+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
139+
with:
140+
file: build/Dockerfile${{ inputs.image == 'nginx' && '.nginx' || '' }}${{ inputs.image == 'plus' && '.nginxplus' || ''}}
141+
tags: ${{ steps.nginx-meta.outputs.tags }}
142+
context: "."
143+
load: true
144+
cache-from: type=gha,scope=${{ inputs.image }}-ipv6
145+
pull: true
146+
build-args: |
147+
NJS_DIR=internal/controller/nginx/modules/src
148+
NGINX_CONF_DIR=internal/controller/nginx/conf
149+
BUILD_AGENT=gha
150+
151+
# - name: Setup license file for plus
152+
# if: ${{ inputs.image == 'plus' }}
153+
# env:
154+
# PLUS_LICENSE: ${{ secrets.JWT_PLUS_REPORTING }}
155+
# run: echo "${PLUS_LICENSE}" > license.jwt
156+
157+
# - name: Deploy IPv6-Only Kubernetes
158+
# id: k8s
159+
# run: |
160+
# # Enable IPv6 and container network options
161+
# # sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
162+
# # sudo sysctl -w net.ipv6.conf.all.forwarding=1
163+
164+
# # Create IPv6-only kind cluster
165+
# kind create cluster \
166+
# --name ${{ github.run_id }}-ipv6 \
167+
# --image=kindest/node:${{ inputs.k8s-version }} \
168+
# --config=config/cluster/kind-ipv6-only.yaml
169+
170+
# # Load images into the cluster
171+
# 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
172+
173+
# # Verify nodes are ipv6 only
174+
# kubectl get nodes -o wide
175+
176+
- name: Push Docker Images to GAR
177+
# if: ${{ github.event_name != 'pull_request' }}
178+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
179+
with:
180+
context: "."
181+
push: true
182+
tags: |
183+
${{ steps.ngf-meta.outputs.tags }}
184+
${{ steps.nginx-meta.outputs.tags }}
185+
186+
- name: Install NGF with IPv6 Configuration
187+
run: |
188+
ngf_prefix=ghcr.io/nginx/nginx-gateway-fabric
189+
ngf_tag=${{ steps.ngf-meta.outputs.version }}
190+
# Install with IPv6-specific configuration
191+
CLUSTER_NAME=${{ github.run_id }}-ipv6 \
192+
HELM_PARAMETERS="--set nginx.config.ipFamily=ipv6 --set nginx.service.type=ClusterIP" \
193+
make helm-install-local${{ inputs.image == 'plus' && '-with-plus' || ''}} PREFIX=${ngf_prefix} TAG=${ngf_tag}
194+
working-directory: ./tests
195+
196+
- name: Deploy Test Applications
197+
run: |
198+
kubectl apply -f tests/manifests/ipv6-test-app.yaml
199+
200+
- name: Wait for NGF and Applications to be Ready
201+
run: |
202+
echo "Waiting for NGF to be ready..."
203+
kubectl wait --for=condition=available --timeout=300s deployment/nginx-gateway -n nginx-gateway
204+
echo "Waiting for test applications to be ready..."
205+
kubectl wait --for=condition=available --timeout=300s deployment/test-app-ipv6
206+
207+
- name: Deploy IPv6 Test Client
208+
run: |
209+
kubectl apply -f tests/manifests/test-client-ipv6.yaml
210+
kubectl wait --for=condition=ready --timeout=300s pod/ipv6-test-client
211+
212+
- name: Get NGF IPv6 Address
213+
id: ngf-address
214+
run: |
215+
# Get the NGF service IPv6 address
216+
NGF_IPV6=$(kubectl get service nginx-gateway -n nginx-gateway -o jsonpath='{.spec.clusterIP}')
217+
echo "NGF IPv6 Address: $NGF_IPV6"
218+
echo "ngf_ipv6=$NGF_IPV6" >> $GITHUB_OUTPUT
219+
220+
- name: Run IPv6 Connectivity Tests
221+
run: |
222+
echo "=== Running IPv6-Only Tests ==="
223+
# Test 1: Basic connectivity test using test client pod
224+
echo "Test 1: Basic IPv6 connectivity"
225+
kubectl exec ipv6-test-client -- curl --version
226+
kubectl exec ipv6-test-client -- nslookup nginx-gateway.nginx-gateway.svc.cluster.local
227+
# Test 2: Test NGF service directly via IPv6
228+
echo "Test 2: NGF Service IPv6 connectivity"
229+
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
230+
-H "Host: ipv6-test.example.com" \
231+
"http://[${{ steps.ngf-address.outputs.ngf_ipv6 }}]:80/" || echo "Direct NGF test failed"
232+
# Test 3: Test via service DNS
233+
echo "Test 3: Service DNS IPv6 connectivity"
234+
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
235+
-H "Host: ipv6-test.example.com" \
236+
"http://nginx-gateway.nginx-gateway.svc.cluster.local:80/" || echo "Service DNS test failed"
237+
238+
- name: Validate IPv6-Only Configuration
239+
run: |
240+
echo "=== Validating IPv6-Only Configuration ==="
241+
# Check NGF configuration
242+
echo "NGF Pod IPv6 addresses:"
243+
kubectl get pods -n nginx-gateway -o wide
244+
echo "NGF Service configuration:"
245+
kubectl get service nginx-gateway -n nginx-gateway -o yaml
246+
echo "Gateway and HTTPRoute status:"
247+
kubectl get gateway,httproute -A -o wide
248+
echo "Test application service configuration:"
249+
kubectl get service test-app-ipv6-service -o yaml
250+
251+
- name: Collect Logs
252+
if: always()
253+
run: |
254+
echo "=== Collecting logs for debugging ==="
255+
echo "NGF Controller logs:"
256+
kubectl logs -n nginx-gateway deployment/nginx-gateway -c nginx-gateway-controller --tail=100 || true
257+
echo "NGINX logs:"
258+
kubectl logs -n nginx-gateway deployment/nginx-gateway -c nginx --tail=100 || true
259+
echo "Test client logs:"
260+
kubectl logs ipv6-test-client --tail=100 || true
261+
echo "Cluster events:"
262+
kubectl get events --sort-by='.lastTimestamp' --all-namespaces --tail=50 || true
263+
264+
- name: Cleanup
265+
if: always()
266+
env:
267+
RUN_ID: ${{ github.run_id }}
268+
run: |
269+
kind delete cluster --name "$RUN_ID-ipv6" || true

.github/workflows/ipv6-only.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ jobs:
6666
type=edge
6767
type=ref,event=pr
6868
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}
69+
6970
- name: NGINX Docker meta
7071
id: nginx-meta
7172
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
@@ -78,6 +79,7 @@ jobs:
7879
type=schedule
7980
type=ref,event=pr
8081
type=ref,event=branch,suffix=-rc,enable=${{ startsWith(github.ref, 'refs/heads/release') }}
82+
8183
- name: Build binary
8284
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
8385
with:
@@ -112,6 +114,7 @@ jobs:
112114
NJS_DIR=internal/controller/nginx/modules/src
113115
NGINX_CONF_DIR=internal/controller/nginx/conf
114116
BUILD_AGENT=gha
117+
115118
- name: Setup license file for plus
116119
if: ${{ inputs.image == 'plus' }}
117120
env:
@@ -136,6 +139,7 @@ jobs:
136139
137140
# Verify nodes are ipv6 only
138141
kubectl get nodes -o wide
142+
139143
- name: Install NGF with IPv6 Configuration
140144
run: |
141145
ngf_prefix=ghcr.io/nginx/nginx-gateway-fabric
@@ -144,6 +148,7 @@ jobs:
144148
CLUSTER_NAME=${{ github.run_id }}-ipv6 \
145149
HELM_PARAMETERS="--set nginx.config.ipFamily=ipv6 --set nginx.service.type=ClusterIP" \
146150
make helm-install-local${{ inputs.image == 'plus' && '-with-plus' || ''}} PREFIX=${ngf_prefix} TAG=${ngf_tag}
151+
147152
working-directory: ./tests
148153

149154
- name: Deploy Test Applications
@@ -213,6 +218,7 @@ jobs:
213218
kubectl logs ipv6-test-client --tail=100 || true
214219
echo "Cluster events:"
215220
kubectl get events --sort-by='.lastTimestamp' --all-namespaces --tail=50 || true
221+
216222
- name: Cleanup
217223
if: always()
218224
env:

tests/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CI ?= false
2+
IPv6_ONLY ?= false
23
CLUSTER_NAME ?= kind
34
CONFORMANCE_PREFIX = conformance-test-runner## Prefix for the conformance test runner image
45
CONFORMANCE_TAG = latest## Tag for the conformance test runner image
@@ -90,7 +91,7 @@ setup-gcp-and-run-nfr-tests: create-gke-router create-and-setup-vm nfr-test ## C
9091

9192
.PHONY: create-gke-cluster
9293
create-gke-cluster: ## Create a GKE cluster
93-
./scripts/create-gke-cluster.sh $(CI)
94+
./scripts/create-gke-cluster.sh $(CI) $(IPv6_ONLY)
9495

9596
.PHONY: create-and-setup-vm
9697
create-and-setup-vm: ## Create and setup a GCP VM for tests

tests/scripts/create-gke-cluster.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ ip_random_digit=$((1 + RANDOM % 250))
88

99
IS_CI=${1:-false}
1010

11+
IPV6_ENABLE=${2:-${IPV6_ENABLE:-false}}
12+
13+
IPV6_FLAGS=""
14+
if [ "$IPV6_ENABLE" = "true" ]; then
15+
IPV6_FLAGS="\
16+
--enable-ipv6 \
17+
--cluster-ipv6-cidr=fd00:1234::/56 \
18+
--services-ipv6-cidr=fd00:4321::/112 \
19+
--create-subnetwork name=\"${GKE_CLUSTER_NAME}-subnet\",range=10.0.0.0/16,fd00:abcd::/64,stack-type=IPV4_IPV6"
20+
fi
21+
1122
if [ -z "$GKE_MACHINE_TYPE" ]; then
1223
# If the environment variable is not set, use a default value
1324
GKE_MACHINE_TYPE="e2-medium"
@@ -31,7 +42,8 @@ gcloud container clusters create "${GKE_CLUSTER_NAME}" \
3142
--logging=SYSTEM,WORKLOAD \
3243
--machine-type "${GKE_MACHINE_TYPE}" \
3344
--num-nodes "${GKE_NUM_NODES}" \
34-
--no-enable-insecure-kubelet-readonly-port
45+
--no-enable-insecure-kubelet-readonly-port \
46+
$IPV6_FLAGS
3547

3648
# Add current IP to GKE master control node access, if this script is not invoked during a CI run.
3749
if [ "${IS_CI}" = "false" ]; then

0 commit comments

Comments
 (0)