Lesson 10 LoadBalancer Deep Dive
Theme:

Homework: LoadBalancer Deep Dive

Design multi-cloud LoadBalancer Services with provider annotations, traffic policies, and cost-aware Helm templates

Task 1 — Multi-Cloud LoadBalancer Template

Create a Helm chart called api-gateway with a Service template that provisions the correct LoadBalancer type depending on which cloud provider the chart is deployed to. The provider is selected via a single cloud.provider value.

Requirements

Hint

Build a dict of provider annotations using conditionals, then merge with user annotations:

{{- $cloud := dict }}
{{- if eq .Values.cloud.provider "aws" }}
  {{- $_ := set $cloud "service.beta.kubernetes.io/aws-load-balancer-type" "nlb" }}
  {{- /* ... more annotations */ -}}
{{- end }}
{{- $merged := merge $cloud (.Values.service.annotations | default dict) }}

Deliverables

  1. templates/service.yaml with the conditional annotation logic
  2. values.yaml with cloud.provider: aws as the default
  3. Rendered output from helm template for each of the three providers (use --set cloud.provider=<value>)

Self-Check

CriterionPass
AWS render includes all three service.beta.kubernetes.io/* annotations
GCP render includes networking.gke.io/load-balancer-type and cloud.google.com/neg
On-prem render includes both metallb.universe.tf/* annotations
User-defined annotations from service.annotations appear in all three renders
No provider-specific annotations leak into other providers' output
Service port is 443 with targetPort 8443 in all renders
helm template succeeds without errors for all three providers

Task 2 — Traffic Policy and Health Check Configuration

Extend your api-gateway chart to support externalTrafficPolicy, session affinity, and cloud-native health checks -- all driven by values.

Requirements

Deliverables

  1. Updated templates/service.yaml and values.yaml
  2. Rendered output with externalTrafficPolicy: Local and session affinity enabled
  3. Rendered output on AWS showing health check annotations

Self-Check

CriterionPass
externalTrafficPolicy: Local appears in rendered Service spec
sessionAffinity: ClientIP and timeoutSeconds appear when enabled
Session affinity fields are absent when sessionAffinity.enabled: false
AWS render includes all three health check annotations with correct values
GCP/on-prem renders do not include AWS health check annotations
Default values render cleanly (Cluster policy, no session affinity)

Task 3 — Internal vs External LB with Cost Controls

Create environment-specific values files that demonstrate internal vs external LoadBalancer configuration and apply cost-conscious patterns for non-production environments.

Requirements

Deliverables

  1. Updated template that respects service.internal and allows service.type override
  2. All three values files
  3. Rendered output for each environment, confirming:
    • Dev: type: ClusterIP, no LB annotations
    • Staging: type: LoadBalancer with internal annotations
    • Prod: type: LoadBalancer with external annotations, Local traffic policy, session affinity

Self-Check

CriterionPass
Dev render shows type: ClusterIP with no cloud annotations
Staging render shows internal LB annotation for the configured provider
Prod render shows external LB with externalTrafficPolicy: Local
Prod render includes sessionAffinity: ClientIP with 3600s timeout
Prod render includes AWS health check annotations
No externalTrafficPolicy field appears on the ClusterIP dev Service
All three environments render without Helm errors

Grading Criteria

AreaPoints
Task 1 -- Multi-cloud annotations render correctly per provider35
Task 2 -- Traffic policy, session affinity, and health checks are value-driven35
Task 3 -- Environment files demonstrate internal/external and cost patterns30
Total100

These tasks build on each other. Start with Task 1 to establish the base template with provider-specific annotations, then layer in traffic policy and health checks in Task 2. Task 3 ties everything together with environment-specific overrides. If you get stuck on annotation merging, review the Sprig merge and set functions and remember that provider annotations should take precedence over user-defined ones when keys collide.