Commit ab4cebc
AKS E2E tests: Redis variant, port fix, and reliability improvements (dotnet#14371)
* Add AKS starter deployment E2E test (Phase 1)
This adds a new end-to-end deployment test that validates Azure Kubernetes Service (AKS) infrastructure creation:
- Creates resource group, ACR, and AKS cluster
- Configures kubectl credentials
- Verifies cluster connectivity
- Cleans up resources after test
Phase 1 focuses on infrastructure only - Aspire deployment will be added in subsequent phases.
* Fix AKS test: register required resource providers
Add step to register Microsoft.ContainerService and Microsoft.ContainerRegistry
resource providers before attempting to create AKS resources. This fixes the
MissingSubscriptionRegistration error when the subscription hasn't been
configured for AKS usage.
* Fix AKS test: use Standard_B2s_v2 VM size
The subscription in westus3 doesn't have access to Standard_B2s, only
the v2 series VMs. Changed to Standard_B2s_v2 which is available.
* Fix AKS test: use Standard_D2s_v3 VM size
The subscription has zero quota for B-series VMs in westus3. Changed to
Standard_D2s_v3 which is a widely-available D-series VM with typical quota.
* Add Phase 2 & 3: Aspire project creation, Helm chart generation, and AKS deployment
Phase 2 additions:
- Create Aspire starter project using 'aspire new'
- Add Aspire.Hosting.Kubernetes package via 'aspire add'
- Modify AppHost.cs to call AddKubernetesEnvironment() with ACR config
- Login to ACR for Docker image push
- Run 'aspire publish' to generate Helm charts and push images
Phase 3 additions:
- Deploy Helm chart to AKS using 'helm install'
- Verify pods are running with kubectl
- Verify deployments are healthy
This completes the full end-to-end flow: AKS cluster creation -> Aspire project
creation -> Helm chart generation -> Deployment to Kubernetes
* Fix Kubernetes deployment: Add container build/push step
Changes:
- Remove invalid ContainerRegistry property from AddKubernetesEnvironment
- Add pragma warning disable for experimental ASPIREPIPELINES001
- Add container build step using dotnet publish /t:PublishContainer
- Push container images to ACR before Helm deployment
- Override Helm image values with ACR image references
The Kubernetes publisher generates Helm charts but doesn't build containers.
We need to build and push containers separately using dotnet publish.
* Fix duplicate Service ports in Kubernetes publisher
When multiple endpoints resolve to the same port number, the Service
manifest generator was creating duplicate port entries, which Kubernetes
rejects as invalid. This fix deduplicates ports by (port, protocol)
before adding them to the Service spec.
Fixes the error:
Service 'xxx-service' is invalid: spec.ports[1]: Duplicate value
* Add explicit AKS-ACR attachment verification step
Added Step 6 to explicitly run 'az aks update --attach-acr' after AKS
cluster creation to ensure the AcrPull role assignment has properly
propagated. This addresses potential image pull permission issues where
AKS cannot pull images from the attached ACR.
Also renumbered all subsequent steps to maintain proper ordering.
* Fix AKS image pull: correct Helm value paths and add ACR check
* Fix duplicate Service/container ports: compare underlying values not Helm expressions
* Re-enable AppService deployment tests
* Add endpoint verification via kubectl port-forward to AKS test
* Wait for pods to be ready before port-forward verification
* Use retry loop for health endpoint verification and log HTTP status codes
* Use real app endpoints: /weatherforecast and / instead of /health
* Improve comments explaining duplicate port dedup rationale
* Refactor cleanup to async pattern matching other deployment tests
* Fix duplicate K8s ports: skip DefaultHttpsEndpoint in ProcessEndpoints
The Kubernetes publisher was generating duplicate Service/container ports
(both 8080/TCP) for ProjectResources with default http+https endpoints.
The root cause is that GenerateDefaultProjectEndpointMapping assigns the
same default port 8080 to every endpoint with None target port.
The proper fix mirrors the core framework's SetBothPortsEnvVariables()
behavior: skip the DefaultHttpsEndpoint (which the container won't listen
on — TLS termination happens at ingress/service mesh). The https endpoint
still gets an EndpointMapping (for service discovery) but reuses the http
endpoint's HelmValue, so no duplicate K8s port is generated.
Added Aspire.Hosting.Kubernetes to InternalsVisibleTo to access
ProjectResource.DefaultHttpsEndpoint. The downstream dedup in ToService()
and WithContainerPorts() remains as defense-in-depth.
Fixes dotnet#14029
* Add AKS + Redis E2E deployment test
Validates the Aspire starter template with Redis cache enabled deploys
correctly to AKS. Exercises the full pipeline: webfrontend → apiservice
→ Redis by hitting the /weather page (SSR, uses Redis output caching).
Key differences from the base AKS test:
- Selects 'Yes' for Redis Cache in aspire new prompts
- Redis uses public container image (no ACR push needed)
- Verifies /weather page content (confirms Redis integration works)
* Fix ACR name collision between parallel AKS tests
Both AKS tests generated the same ACR name from RunId+RunAttempt.
Use different prefixes (acrs/acrr) to ensure uniqueness.
* Fix Redis Helm deployment: provide missing cross-resource secret value
Work around K8s publisher bug where cross-resource secret references create
Helm value paths under the consuming resource instead of referencing the
owning resource's secret. The webfrontend template expects
secrets.webfrontend.cache_password but values.yaml only has
secrets.cache.REDIS_PASSWORD. Provide the missing value via --set.
* Move ACR login before AKS creation to avoid OIDC token expiration
The OIDC federated token expires after ~5 minutes, but AKS cluster
creation takes 10-15 minutes. By the time the test reaches az acr login,
the assertion is stale. Moving ACR auth to right after ACR creation
ensures the OIDC token is still fresh, and Docker credentials persist
in ~/.docker/config.json for later use.
* Add pod diagnostics for Redis test: accept kubectl wait failure gracefully
The kubectl wait step was blocking the test when Redis pods failed to
start. Now accepts either OK or ERR exit, captures pod logs for
diagnostics, and continues to verify what we can.
* Wait only for project resource pods, skip Redis (K8s publisher bug dotnet#14370)
Redis container crashes with 'cannot open redis-server: No such file'
due to incorrect container command generated by the K8s publisher.
The webfrontend handles Redis being unavailable gracefully. Wait only
for apiservice and webfrontend pods using label selectors, and capture
Redis pod logs for diagnostics.
* Remove redundant weather page grep check (Blazor SSR streaming issue)
The curl -sf /weather | grep 'Weather' step fails because Blazor SSR
streaming rendering returns incomplete initial HTML via curl. The
/weather endpoint already returns 200 (verified in previous step),
which is sufficient to confirm the full pipeline works.
* Add --max-time 10 to /weather curl (Blazor SSR streaming keeps connection open)
Blazor SSR streaming rendering keeps the HTTP connection open to stream
updates to the browser. curl waits indefinitely for the response to
complete, causing the WaitForSuccessPrompt to time out. Adding --max-time
ensures curl returns after receiving the initial 200 status code.
* Fix /weather curl: capture status code in variable to handle SSR streaming
curl --max-time exits with code 28 (timeout) even when HTTP 200 was
received, because Blazor SSR streaming keeps the connection open. This
causes the && chain to fail, so echo/break never execute. Fix by using
semicolons and capturing the status code in a variable, then checking
it explicitly with [ "$S" = "200" ].
* Fix K8s publisher: set ExecutionContext on CommandLineArgsCallbackContext
The K8s publisher was not setting ExecutionContext when creating the
CommandLineArgsCallbackContext in ProcessArgumentsAsync, causing it to
default to Run mode. This made Redis's WithArgs callback produce
individual args instead of a single -c shell command string, resulting
in '/bin/sh redis-server' (open as script) instead of
'/bin/sh -c "redis-server ..."' (execute as command).
Matches the Docker Compose publisher which correctly sets
ExecutionContext = executionContext.
Also updates the Redis E2E test to wait for all pods (including cache)
and verify Redis responds to PING.
* Avoid leaking Redis password in test logs
Expand $REDIS_PASSWORD inside the container shell instead of extracting
it from the K8s secret on the host. Also use --no-auth-warning to
suppress redis-cli's password-on-command-line warning.
* Replace kubectl exec redis-cli with pod status check to avoid container name issue
* Set REDIS_PASSWORD in helm install to prevent redis-server --requirepass with empty arg
* Fix Helm secret path: use parameter name (cache_password) not env var key (REDIS_PASSWORD)
The K8s publisher AllocateParameter creates Helm expressions using the parameter
name (cache-password -> cache_password), but AddValuesToHelmSectionAsync writes
values using the env var key (REDIS_PASSWORD). The template references
.Values.secrets.cache.cache_password but values.yaml has REDIS_PASSWORD, so the
password is always empty and Redis crashes with 'requirepass' having no argument.
* Use dynamically generated GUID for Redis password instead of hardcoded value
* Pass same Redis password to webfrontend so it can authenticate to Redis cache
---------
Co-authored-by: Mitch Denny <mitch@mitchdeny.com>1 parent a6b68c7 commit ab4cebc
File tree
3 files changed
+55
-34
lines changed- src/Aspire.Hosting.Kubernetes
- tests/Aspire.Deployment.EndToEnd.Tests
3 files changed
+55
-34
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
287 | 287 | | |
288 | 288 | | |
289 | 289 | | |
290 | | - | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
291 | 294 | | |
292 | 295 | | |
293 | 296 | | |
| |||
Lines changed: 11 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
142 | 151 | | |
143 | 152 | | |
144 | 153 | | |
| |||
274 | 283 | | |
275 | 284 | | |
276 | 285 | | |
277 | | - | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
| 286 | + | |
| 287 | + | |
283 | 288 | | |
284 | 289 | | |
285 | 290 | | |
| |||
Lines changed: 40 additions & 27 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
139 | 140 | | |
140 | 141 | | |
141 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
142 | 152 | | |
143 | 153 | | |
144 | 154 | | |
| |||
271 | 281 | | |
272 | 282 | | |
273 | 283 | | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
279 | | - | |
| 284 | + | |
| 285 | + | |
280 | 286 | | |
281 | 287 | | |
282 | 288 | | |
| |||
331 | 337 | | |
332 | 338 | | |
333 | 339 | | |
334 | | - | |
335 | | - | |
336 | | - | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
337 | 346 | | |
338 | 347 | | |
339 | 348 | | |
340 | 349 | | |
341 | 350 | | |
342 | | - | |
| 351 | + | |
| 352 | + | |
343 | 353 | | |
344 | 354 | | |
345 | 355 | | |
346 | | - | |
347 | | - | |
| 356 | + | |
| 357 | + | |
348 | 358 | | |
349 | | - | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
350 | 362 | | |
351 | 363 | | |
352 | 364 | | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
353 | 372 | | |
354 | 373 | | |
355 | 374 | | |
| |||
392 | 411 | | |
393 | 412 | | |
394 | 413 | | |
395 | | - | |
396 | | - | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
397 | 417 | | |
398 | 418 | | |
399 | | - | |
| 419 | + | |
400 | 420 | | |
401 | | - | |
402 | | - | |
403 | | - | |
404 | | - | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
| 421 | + | |
409 | 422 | | |
410 | | - | |
411 | | - | |
| 423 | + | |
| 424 | + | |
412 | 425 | | |
413 | 426 | | |
414 | 427 | | |
415 | 428 | | |
416 | 429 | | |
417 | | - | |
| 430 | + | |
418 | 431 | | |
419 | 432 | | |
420 | 433 | | |
| |||
0 commit comments