-
Notifications
You must be signed in to change notification settings - Fork 0
223 lines (204 loc) · 9.68 KB
/
Copy pathe2e.yml
File metadata and controls
223 lines (204 loc) · 9.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
name: e2e
on:
pull_request:
paths:
- 'charts/llama-8b/**'
- 'policies/**'
- 'httproutes/**'
- 'gateway/**'
- '.github/workflows/e2e.yml'
push:
branches: [main]
workflow_dispatch:
jobs:
kind-install:
name: kind cluster + chart install + admission checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install kind cluster
uses: helm/kind-action@v1.10.0
with:
cluster_name: e2e
version: v0.24.0
node_image: kindest/node:v1.30.4
- name: install Gateway API v1 CRDs (experimental channel)
run: |
kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/experimental-install.yaml
for crd in gateways httproutes tlsroutes backendtlspolicies; do
for i in $(seq 1 30); do
status=$(kubectl get crd ${crd}.gateway.networking.k8s.io \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' 2>/dev/null || true)
[ "$status" = "True" ] && break
sleep 2
done
kubectl get crd ${crd}.gateway.networking.k8s.io \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' | grep -q True
done
- name: install KEDA CRDs only
run: |
kubectl apply --server-side -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1-crds.yaml
# Poll until Established shows up — bare `kubectl wait` races with
# a nil status.conditions and errors "<nil> is of the type <nil>".
for i in $(seq 1 30); do
status=$(kubectl get crd scaledobjects.keda.sh \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' 2>/dev/null || true)
[ "$status" = "True" ] && break
sleep 2
done
kubectl get crd scaledobjects.keda.sh \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' | grep -q True
- name: install Prometheus Operator CRDs (for ServiceMonitor)
run: |
kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.76.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
kubectl wait --for condition=established --timeout=60s crd/servicemonitors.monitoring.coreos.com
- name: install Gateway API Inference Extension CRDs
run: |
# v1.5.0 config/crd/bases has: inferencepools.inference.networking.k8s.io (v1)
# and inferenceobjectives.inference.networking.x-k8s.io (v1alpha2).
kubectl apply --server-side -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.5.0/config/crd/bases/inference.networking.k8s.io_inferencepools.yaml
for i in $(seq 1 30); do
status=$(kubectl get crd inferencepools.inference.networking.k8s.io \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' 2>/dev/null || true)
[ "$status" = "True" ] && break
sleep 2
done
- name: install minimal Argo Workflows CRD (referenced by mutate-workflow-ttl policy)
# The upstream v3.6.2 CRD uses schemaless fields that k8s 1.30 rejects
# for structural-schema violations. We don't need the full schema in
# e2e — Kyverno only needs to resolve group/version/resource. This
# inline CRD satisfies both.
run: |
cat <<'EOF' | kubectl apply --server-side -f -
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: workflows.argoproj.io
spec:
group: argoproj.io
scope: Namespaced
names:
kind: Workflow
plural: workflows
singular: workflow
shortNames: [wf]
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
for i in $(seq 1 30); do
status=$(kubectl get crd workflows.argoproj.io \
-o jsonpath='{.status.conditions[?(@.type=="Established")].status}' 2>/dev/null || true)
[ "$status" = "True" ] && break
sleep 2
done
- name: install Kyverno (admission enforcement path)
run: |
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --version 3.3.0 \
--namespace kyverno --create-namespace \
--set admissionController.replicas=1 \
--set backgroundController.enabled=false \
--set reportsController.enabled=false \
--set cleanupController.enabled=false \
--wait --timeout=5m
- name: apply our ClusterPolicies
run: |
kubectl apply -f policies/
# Give Kyverno a moment to register the webhook configurations
sleep 15
- name: create supporting resources (fake secrets + namespaces + nvidia RuntimeClass stub)
run: |
kubectl create namespace llama
kubectl create secret generic hf-token -n llama --from-literal=token=fake
kubectl create secret generic vllm-api-key -n llama --from-literal=token=fake-api-key
kubectl create namespace gateway || true
kubectl create namespace monitoring || true
kubectl create namespace argo || true
# Stub RuntimeClass so pod admission passes on kind (which has no
# nvidia-container-runtime). Handler=runc means pods just run under
# normal runc — sufficient for admission testing.
cat <<'EOF' | kubectl apply -f -
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: runc
EOF
- name: helm install the chart (with fake image so pod won't try to pull real vLLM)
run: |
helm install llama charts/llama-8b \
--namespace llama \
--set image=nginx:alpine \
--set otlp.installSdk=false \
--set otlp.tracesEndpoint="" \
--set persistence.hfCache.storageClass=standard \
--set rolloutGate.enabled=false \
--set autoscaling.enabled=false \
--wait --timeout=2m || true
# ^^ pods won't be Ready (nginx doesn't serve /health on 8000), but the manifests must apply
- name: verify every expected resource exists
run: |
set -euxo pipefail
kubectl -n llama get deployment llama-llama-8b
kubectl -n llama get service llama-llama-8b
kubectl -n llama get pvc llama-llama-8b-hf-cache
kubectl -n llama get networkpolicy llama-llama-8b-default-deny
kubectl -n llama get networkpolicy llama-llama-8b-allow
kubectl -n llama get servicemonitor llama-llama-8b
kubectl get priorityclass gpu-inference
- name: verify chart renders runtimeClassName correctly on Deployment template
run: |
rc=$(kubectl -n llama get deploy llama-llama-8b \
-o jsonpath='{.spec.template.spec.runtimeClassName}')
[ "$rc" = "nvidia" ] || { echo "expected nvidia, got $rc"; exit 1; }
- name: verify Kyverno mutate policy actually fires on a bare Pod
# Apply a Pod that requests GPU but has NO runtimeClassName. Kyverno's
# mutate-nvidia-runtime-class should stamp it before admission finishes.
run: |
# Wait for Kyverno webhook to be responsive
for i in $(seq 1 60); do
kubectl -n kyverno get validatingwebhookconfiguration kyverno-policy-validating-webhook-cfg >/dev/null 2>&1 && break
sleep 2
done
sleep 10
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: mutation-test
namespace: default
spec:
containers:
- name: c
image: nginx:alpine
resources:
requests: {nvidia.com/gpu: 1}
limits: {nvidia.com/gpu: 1}
EOF
rc=$(kubectl get pod mutation-test -o jsonpath='{.spec.runtimeClassName}')
echo "runtimeClassName after Kyverno mutation: $rc"
[ "$rc" = "nvidia" ] || { echo "Kyverno mutation did not fire"; kubectl -n kyverno logs -l app.kubernetes.io/component=admission-controller --tail=50; exit 1; }
kubectl delete pod mutation-test
- name: verify no Kyverno policy is denying anything unexpected
run: |
# If Kyverno reports blocking violations on the chart, dump them and fail.
# In audit mode our validate policies produce PolicyReports; grab them.
kubectl -n llama get policyreport -o yaml 2>/dev/null | tee /tmp/policyreports.yaml || true
# Fail only if a policy is in enforce mode and a chart resource was rejected.
# (We already applied resources above; if enforce policies had rejected them,
# the previous kubectl get calls would have returned NotFound.)
- name: dump diagnostics if anything failed
if: failure()
run: |
echo "=== events ==="
kubectl -n llama get events --sort-by=.lastTimestamp | tail -50
echo "=== pods ==="
kubectl -n llama describe pods
echo "=== kyverno logs ==="
kubectl -n kyverno logs -l app.kubernetes.io/component=admission-controller --tail=100 || true