Skip to content

Funny insects/keda exercise refactor#878

Open
stephen2002119 wants to merge 22 commits into
masterfrom
funny-insects/keda-exercise-refactor
Open

Funny insects/keda exercise refactor#878
stephen2002119 wants to merge 22 commits into
masterfrom
funny-insects/keda-exercise-refactor

Conversation

@stephen2002119
Copy link
Copy Markdown
Contributor

@stephen2002119 stephen2002119 commented May 18, 2026

Summary by CodeRabbit

  • Documentation
    • Added a new KEDA module with step-by-step exercises, specs, proofs, quizzes, and sidebar/README renumbering for chapters 9.6–9.9.
  • New Features
    • Added a complete KEDA lab: producer/consumer microservices, Kubernetes manifests and overlays, local automation tasks, and a k6 flash-sale load test to demonstrate queue-depth vs HPA scaling.

Review Change Stack

stephen2002119 and others added 18 commits May 12, 2026 10:31
- checkout-service: HTTP server with POST /checkout -> Redis RPUSH
- order-processor: BLPOP consumer with configurable delay + CPU loop
- Multi-stage Dockerfiles using golang:1.26-alpine -> alpine:3.23 with SHA pinning
- Both images build successfully (checkout-service:local, order-processor:local)

Related to T1.0 in Spec 01
- Kustomize base: namespace, redis-secret, redis, checkout-service, order-processor, keda-trigger-auth
- Local overlay patches imagePullPolicy: Never for k3d compatibility
- Redis upgraded to 8.6-alpine with SHA pinning
- HPA omitted from base — left for students to write in Exercise 3

Related to T2.0 in Spec 01
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Warning

Rate limit exceeded

@stephen2002119 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 30 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 110d5e57-f9a3-4a40-b2b3-89e3636c1fce

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1d81a and b0235e0.

📒 Files selected for processing (3)
  • docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md
  • examples/ch9/keda/Taskfile.yml
  • examples/ch9/keda/order-processor/Dockerfile
📝 Walkthrough

Walkthrough

Adds a new chapter (9.6) KEDA exercise with docs/specs, two Go example services and Dockerfiles, Kustomize manifests and overlay, Taskfile automation, k6 load script, and renumbers subsequent chapter files and sidebar/README entries.

Changes

KEDA Exercise and Chapter Reorganization

Layer / File(s) Summary
Documentation structure and chapter renumbering
docs/9-kubernetes-container-orchestration/9.6-keda.md, docs/9-kubernetes-container-orchestration/9.7-webhooks.md, docs/9-kubernetes-container-orchestration/9.7.1-validating-admission-policy.md, docs/9-kubernetes-container-orchestration/9.8-*.md, docs/9-kubernetes-container-orchestration/9.9-controllers.md, docs/README.md, docs/_sidebar.md, .cspell.json
Inserted 9.6-keda.md, updated headings/quiz IDs and README catalog, and renumbered sidebar/lesson entries (Webhooks→9.7, Declarative Configuration→9.8, Controllers→9.9).
Exercise specifications and proof artifacts
docs/specs/01-spec-keda-exercise/01-spec-keda-exercise.md, docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md, docs/specs/01-spec-keda-exercise/01-questions-1-keda-exercise.md, docs/specs/01-spec-keda-exercise/01-proofs/01-task-*.md
Added complete KEDA exercise spec, task definitions, question page, and three proof artifacts capturing Docker/Kustomize/k6 CLI outputs and verification notes.
Go microservices: checkout and order processor
examples/ch9/keda/checkout-service/main.go, examples/ch9/keda/checkout-service/go.mod, examples/ch9/keda/checkout-service/Dockerfile, examples/ch9/keda/order-processor/main.go, examples/ch9/keda/order-processor/go.mod, examples/ch9/keda/order-processor/Dockerfile
Implemented checkout-service (POST /checkout → Redis RPUSH with padding) and order-processor (blocking BLPOP → simulated IO and CPU work). Added go.mod and multi-stage Dockerfiles for both services.
Kubernetes manifests: base and local overlay
examples/ch9/keda/k8s/base/namespace.yaml, examples/ch9/keda/k8s/base/redis-secret.yaml, examples/ch9/keda/k8s/base/redis.yaml, examples/ch9/keda/k8s/base/checkout-service.yaml, examples/ch9/keda/k8s/base/order-processor.yaml, examples/ch9/keda/k8s/base/kustomization.yaml, examples/ch9/keda/k8s/overlays/local/image-pull-policy-patch.yaml, examples/ch9/keda/k8s/overlays/local/kustomization.yaml
Added Kustomize base resources (namespace, secret, Redis deployment/service, app Deployments) and a local overlay to set imagePullPolicy: Never for local k3d testing.
Taskfile automation and k6 load test
examples/ch9/keda/Taskfile.yml, examples/ch9/keda/load/flash-sale.js
New Taskfile tasks to create/delete k3d cluster, install metrics-server and KEDA via Helm, build/load images, deploy manifests (excluding ScaledObject), run k6 flash-sale load test, and observe queue depth/pod count/CPU. Added k6 script parameterized by CHECKOUT_URL/VUS/DURATION.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I stitched a lesson, doc and test,
Two Go friends push and then digest,
Redis queues hum, the load begins,
KEDA listens where CPU thins,
Rabbits cheer as autoscale wins. 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Funny insects/keda exercise refactor' is vague and unclear; 'Funny insects' appears unrelated to the actual changeset (KEDA exercise implementation), making it difficult for reviewers to understand the primary purpose. Revise the title to clearly describe the main change, such as 'Add KEDA event-driven autoscaling exercise module' or 'Implement 9.6 KEDA exercise with queue-depth scaling demo'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch funny-insects/keda-exercise-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/9-kubernetes-container-orchestration/9.9-controllers.md (1)

43-43: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update chapter reference from 9.6 to 9.7.

After the chapter renumbering, the Webhooks chapter moved from 9.6 to 9.7, but this cross-reference was not updated.

🔗 Proposed fix
-If you've been working through the bootcamp, you've already been exposed to both CRDs and custom controllers. In the first exercise of chapter 9.6, Webhooks, you were tasked with setting up a basic admission webhook, which required installing cert-manager. `cert-manager` is a powerful tool that combines a set of custom resource definitions (CRDs) with a custom controller to automate the issuance, renewal, and management of TLS certificates that webhooks require to securely interact with the Kubernetes API server. By leveraging CRDs like Certificate, Issuer, and ClusterIssuer, cert-manager enables you to declare and manage certificates directly within Kubernetes, removing the need for manual intervention in obtaining and maintaining certificates. This automation is not only convenient but essential in high-scale environments where TLS certificates need frequent renewal to ensure secure connections across applications and services.
+If you've been working through the bootcamp, you've already been exposed to both CRDs and custom controllers. In the first exercise of chapter 9.7, Webhooks, you were tasked with setting up a basic admission webhook, which required installing cert-manager. `cert-manager` is a powerful tool that combines a set of custom resource definitions (CRDs) with a custom controller to automate the issuance, renewal, and management of TLS certificates that webhooks require to securely interact with the Kubernetes API server. By leveraging CRDs like Certificate, Issuer, and ClusterIssuer, cert-manager enables you to declare and manage certificates directly within Kubernetes, removing the need for manual intervention in obtaining and maintaining certificates. This automation is not only convenient but essential in high-scale environments where TLS certificates need frequent renewal to ensure secure connections across applications and services.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/9-kubernetes-container-orchestration/9.9-controllers.md` at line 43,
Update the cross-reference string "chapter 9.6, Webhooks" to "chapter 9.7,
Webhooks" in the text so the Webhooks chapter number matches the renumbered
chapters; search for the literal phrase "chapter 9.6, Webhooks" in the docs
(e.g., within the paragraph mentioning cert-manager and webhooks) and replace it
with "chapter 9.7, Webhooks".
♻️ Duplicate comments (1)
docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md (1)

86-86: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve HPA manifest inclusion decision.

Task 2.6 states hpa.yaml is "intentionally omitted — left for students to write as part of Exercise 3," but Task 4.6 (line 141) instructs students to "apply k8s/base/hpa.yaml with kubectl apply -f."

If the file is omitted from the repository, students cannot apply it from that path. This is the same inconsistency flagged in 01-spec-keda-exercise.md line 68.

Recommended resolution: Provide hpa.yaml in k8s/base/ as a reference implementation (students apply it in Exercise 3), but keep the ScaledObject as student-written (Exercise 5). This maintains the learning objective of writing KEDA resources while reducing friction in the HPA comparison exercise.

Also applies to: 141-141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md` at line 86, Task
2.6 claims hpa.yaml is intentionally omitted but later steps ask students to
apply k8s/base/hpa.yaml; add a reference HPA manifest so exercises are
consistent: create k8s/base/hpa.yaml containing a HorizontalPodAutoscaler named
order-processor-hpa in namespace keda-demo targeting the order-processor
Deployment with minReplicas: 1, maxReplicas: 10 and a Resource metric cpu
targetUtilizationPercentage: 50, while leaving the KEDA ScaledObject for
students to author in the later exercise.
🧹 Nitpick comments (1)
examples/ch9/keda/k8s/base/redis-secret.yaml (1)

7-7: ⚡ Quick win

Decouple Redis address from hardcoded namespace.

Using redis.keda-demo.svc.cluster.local:6379 couples this secret to a single namespace. Prefer redis:6379 (same-namespace service DNS) to keep overlays portable.

Proposed fix
 stringData:
-  REDIS_ADDR: redis.keda-demo.svc.cluster.local:6379
+  REDIS_ADDR: redis:6379
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ch9/keda/k8s/base/redis-secret.yaml` at line 7, The REDIS_ADDR
secret value is hardcoded to a namespace-specific FQDN; update the REDIS_ADDR
entry in redis-secret.yaml (the REDIS_ADDR key) to use the same-namespace
service DNS (e.g., "redis:6379") so the secret is portable across overlays and
not tied to the keda-demo namespace.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.cspell.json:
- Line 102: Replace the misspelled dictionary entry "observabity" with the
correct word "observability" in the cspell word list; locate the literal string
"observabity" in the .cspell.json word array and update it to "observability" so
the spellchecker accepts the correct term going forward.

In `@docs/9-kubernetes-container-orchestration/9.6-keda.md`:
- Line 95: The sentence that currently reads "Before installing KEDA, you must
remove the HPA you created in Exercise 3." is referencing the wrong exercise;
update the text to reference "Exercise 2" instead of "Exercise 3" so it
correctly points to where the HPA was created (locate the paragraph that begins
"Before installing KEDA..." in the KEDA exercise content and replace "Exercise
3" with "Exercise 2").
- Line 91: Replace the Markdown image syntax referencing
"img9/dank-hpa-meme.jpg" with an HTML <img> tag that points to the image placed
in the root img/ folder (e.g., src="img/dank-hpa-meme.jpg") and preserve the alt
text ("dank hpa meme") and centering class (e.g., class="img-center"); move the
file from img9/ into img/ and update the image reference in the document
accordingly.
- Line 65: Replace the Markdown image syntax referencing
"img9/producer-consumer.jpg" with an HTML <img> tag that points to the root img
folder (e.g., src="/img/producer-consumer.jpg"), preserve the class "img-center"
and the alt text "producer consumer image", and remove the old markdown line so
the content uses the HTML <img> element instead of the Markdown image reference.

In `@docs/specs/01-spec-keda-exercise/01-proofs/01-task-02-proofs.md`:
- Line 115: The proof uses image "redis:8.6-alpine@sha256:..." while the spec
and task docs reference "redis:7-alpine"; pick one source of truth and make them
consistent: either update the spec and task documents
("01-spec-keda-exercise.md" and "01-tasks-keda-exercise.md") to reference
"redis:8.6-alpine" (and remove or update SHA pins where appropriate), or change
the proof artifact in "01-task-02-proofs.md" to use "redis:7-alpine" (and if you
keep a SHA, pin the correct digest for v7); ensure all three files use the exact
same image string.

In `@docs/specs/01-spec-keda-exercise/01-spec-keda-exercise.md`:
- Line 68: The spec text contradicts Task 2.6 about whether k8s/base/hpa.yaml is
provided or left for students: reconcile the documents by choosing A or B and
update both files accordingly; if you decide A (provide it) change the sentence
in docs/specs/01-spec-keda-exercise/01-spec-keda-exercise.md to explicitly state
that k8s/base/hpa.yaml is included and ensure Task 2.6 in
01-tasks-keda-exercise.md no longer says it is omitted, or if you decide B
(students write it) change the spec sentence to state that k8s/base/hpa.yaml is
intentionally omitted and ensure Task 2.6 continues to reflect that; update any
references and examples in both files so they consistently reference
k8s/base/hpa.yaml and Task 2.6.

In `@examples/ch9/keda/checkout-service/Dockerfile`:
- Around line 8-11: The runtime Dockerfile currently runs the container as root;
to fix, modify the final stage (the Dockerfile containing COPY --from=builder
/checkout-service /checkout-service, EXPOSE 8080, ENTRYPOINT
["/checkout-service"]) to create or use a non-root user, chown the
/checkout-service binary to that user, and add a USER <nonroot> directive before
the ENTRYPOINT so the process runs unprivileged; ensure the created user has
permission to execute the binary and any required runtime directories.

In `@examples/ch9/keda/checkout-service/main.go`:
- Line 44: Replace the use of context.Background() in the Redis enqueue call so
the operation respects request cancellation/timeouts: create a request-scoped
context with a deadline (e.g., using context.WithTimeout on the handler's ctx),
defer the cancel, and pass that context into rdb.RPush(ctx, "orders:queue",
payload). Update the call site where rdb.RPush is invoked (replace the
context.Background() argument) so stalls or client cancellations will cancel the
Redis operation.
- Around line 69-71: The server is started with http.ListenAndServe(nil) and no
timeouts, which risks slow clients; replace the ListenAndServe call by creating
an http.Server struct (set Addr to ":"+port, Handler to http.DefaultServeMux or
the mux used for checkoutHandler) and configure ReadTimeout, ReadHeaderTimeout,
WriteTimeout and IdleTimeout with sensible values, then call
server.ListenAndServe() (or ListenAndServeTLS if needed); update references
around checkoutHandler and the existing println/log.Fatal to use the new server
variable.

In `@examples/ch9/keda/k8s/base/checkout-service.yaml`:
- Around line 15-31: Add explicit pod and container security contexts for the
checkout-service: under the pod spec add a podSecurityContext with
seccompProfile.type set to "RuntimeDefault"; under the container entry for name:
checkout-service add a securityContext with runAsNonRoot: true,
allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], and
readOnlyRootFilesystem: true (apply to the container named checkout-service in
the existing spec). Ensure the fields are placed alongside the existing
resources/env to harden the workload without changing other settings.

In `@examples/ch9/keda/k8s/base/order-processor.yaml`:
- Around line 15-31: Add explicit pod and container security contexts to harden
the order-processor pod: in the Pod spec add a podSecurityContext (e.g.,
runAsNonRoot: true, runAsUser: 1000, fsGroup: 2000) and inside the container
named "order-processor" add a securityContext that enforces least privilege
(runAsNonRoot: true, runAsUser: 1000 if not inherited, allowPrivilegeEscalation:
false, readOnlyRootFilesystem: true, capabilities: drop: ["ALL"], and
seccompProfile: { type: "RuntimeDefault" }). Update the "order-processor"
container block and the surrounding spec to include these fields so the pod and
container both enforce non-root execution and restricted capabilities.

In `@examples/ch9/keda/k8s/base/redis.yaml`:
- Around line 15-25: Add a pod- and container-level securityContext to the Redis
Pod spec to harden the container: under the Pod spec add securityContext with
seccompProfile.type: RuntimeDefault, and under the container entry for name:
redis add securityContext with allowPrivilegeEscalation: false,
capabilities.drop: ["ALL"], and runAsNonRoot: true; update the existing
container block (container name "redis") rather than creating a new container
and ensure these fields are applied alongside the current image/args/ports
entries.

In `@examples/ch9/keda/order-processor/Dockerfile`:
- Around line 8-10: The final stage of the Dockerfile currently runs as root
(ENTRYPOINT ["/order-processor"]); create and switch to an unprivileged user in
the runtime image and ensure the binary is owned/executable by that user.
Specifically, in the final stage (the stage that copies /order-processor from
the builder and sets ENTRYPOINT) add a non-root user (e.g., create user
"appuser"), chown the /order-processor binary to that user, and add a USER
appuser instruction before ENTRYPOINT so the container runs the binary as a
non-root principal.

In `@examples/ch9/keda/Taskfile.yml`:
- Line 67: The task description string starting with "desc: Run k6 load test
(defaults — CHECKOUT_URL=http://localhost:8080, VUS=50, DURATION=60s)" is
inconsistent with the actual default VUS value (VUS=10) defined elsewhere;
update that desc text to reflect the real default (VUS=10) so the description
matches the default variable, i.e., edit the desc line to show VUS=10 (or
alternatively change the default VUS variable to 50 if you intend that to be the
true default) — look for the "desc: Run k6 load test..." string and the VUS
default declaration to make them consistent.
- Around line 66-73: The load:run target defaults CHECKOUT_URL to
http://localhost:8080 which is unreachable from the host because the stack only
creates in-cluster resources; update the default CHECKOUT_URL in the load:run
Taskfile target to a cluster-accessible address (for example the service DNS
like http://checkout-service.<namespace>.svc.cluster.local:8080) or
document/offer an alternative env var (e.g., CHECKOUT_URL=https://<host>:<port>
with port-forwarding) so load/flash-sale.js can reach the checkout service
without manual port-forwarding.

---

Outside diff comments:
In `@docs/9-kubernetes-container-orchestration/9.9-controllers.md`:
- Line 43: Update the cross-reference string "chapter 9.6, Webhooks" to "chapter
9.7, Webhooks" in the text so the Webhooks chapter number matches the renumbered
chapters; search for the literal phrase "chapter 9.6, Webhooks" in the docs
(e.g., within the paragraph mentioning cert-manager and webhooks) and replace it
with "chapter 9.7, Webhooks".

---

Duplicate comments:
In `@docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md`:
- Line 86: Task 2.6 claims hpa.yaml is intentionally omitted but later steps ask
students to apply k8s/base/hpa.yaml; add a reference HPA manifest so exercises
are consistent: create k8s/base/hpa.yaml containing a HorizontalPodAutoscaler
named order-processor-hpa in namespace keda-demo targeting the order-processor
Deployment with minReplicas: 1, maxReplicas: 10 and a Resource metric cpu
targetUtilizationPercentage: 50, while leaving the KEDA ScaledObject for
students to author in the later exercise.

---

Nitpick comments:
In `@examples/ch9/keda/k8s/base/redis-secret.yaml`:
- Line 7: The REDIS_ADDR secret value is hardcoded to a namespace-specific FQDN;
update the REDIS_ADDR entry in redis-secret.yaml (the REDIS_ADDR key) to use the
same-namespace service DNS (e.g., "redis:6379") so the secret is portable across
overlays and not tied to the keda-demo namespace.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e21a29c-2fa3-4109-8f35-c3b368426967

📥 Commits

Reviewing files that changed from the base of the PR and between a0aa011 and 3cceea8.

⛔ Files ignored due to path filters (4)
  • docs/9-kubernetes-container-orchestration/img9/dank-hpa-meme.jpg is excluded by !**/*.jpg
  • docs/9-kubernetes-container-orchestration/img9/producer-consumer.jpg is excluded by !**/*.jpg
  • examples/ch9/keda/checkout-service/go.sum is excluded by !**/*.sum
  • examples/ch9/keda/order-processor/go.sum is excluded by !**/*.sum
📒 Files selected for processing (36)
  • .cspell.json
  • docs/9-kubernetes-container-orchestration/9.6-keda.md
  • docs/9-kubernetes-container-orchestration/9.7-webhooks.md
  • docs/9-kubernetes-container-orchestration/9.7.1-validating-admission-policy.md
  • docs/9-kubernetes-container-orchestration/9.8-declarative-configuration.md
  • docs/9-kubernetes-container-orchestration/9.8.1-kustomize.md
  • docs/9-kubernetes-container-orchestration/9.8.2-helm.md
  • docs/9-kubernetes-container-orchestration/9.9-controllers.md
  • docs/README.md
  • docs/_sidebar.md
  • docs/specs/01-spec-keda-exercise/01-proofs/01-task-01-proofs.md
  • docs/specs/01-spec-keda-exercise/01-proofs/01-task-02-proofs.md
  • docs/specs/01-spec-keda-exercise/01-proofs/01-task-03-proofs.md
  • docs/specs/01-spec-keda-exercise/01-questions-1-keda-exercise.md
  • docs/specs/01-spec-keda-exercise/01-spec-keda-exercise.md
  • docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md
  • examples/ch9/keda/Taskfile.yml
  • examples/ch9/keda/checkout-service/Dockerfile
  • examples/ch9/keda/checkout-service/go.mod
  • examples/ch9/keda/checkout-service/main.go
  • examples/ch9/keda/k8s/base/checkout-service.yaml
  • examples/ch9/keda/k8s/base/kustomization.yaml
  • examples/ch9/keda/k8s/base/namespace.yaml
  • examples/ch9/keda/k8s/base/order-processor.yaml
  • examples/ch9/keda/k8s/base/redis-secret.yaml
  • examples/ch9/keda/k8s/base/redis.yaml
  • examples/ch9/keda/k8s/overlays/local/image-pull-policy-patch.yaml
  • examples/ch9/keda/k8s/overlays/local/kustomization.yaml
  • examples/ch9/keda/load/flash-sale.js
  • examples/ch9/keda/order-processor/Dockerfile
  • examples/ch9/keda/order-processor/go.mod
  • examples/ch9/keda/order-processor/main.go
  • examples/ch9/keda/order-processor/order-processor
  • src/quizzes/chapter-9/9.7.1/validatingadmissionpolicy-quiz.js
  • src/quizzes/chapter-9/9.8.1/kustomize-quiz.js
  • src/quizzes/chapter-9/9.8.2/helm-quiz.js

Comment thread .cspell.json Outdated
Comment thread docs/9-kubernetes-container-orchestration/9.6-keda.md
Comment thread docs/9-kubernetes-container-orchestration/9.6-keda.md
Comment thread docs/9-kubernetes-container-orchestration/9.6-keda.md Outdated
Comment thread docs/specs/01-spec-keda-exercise/01-proofs/01-task-02-proofs.md
Comment on lines +15 to +31
spec:
containers:
- name: order-processor
image: order-processor:local
env:
- name: REDIS_ADDR
valueFrom:
secretKeyRef:
name: redis-secret
key: REDIS_ADDR
- name: PROCESS_DELAY_MS
value: "500"
resources:
requests:
cpu: 100m
limits:
cpu: 500m
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

fd -t f "order-processor.yaml" examples/

Repository: liatrio/engineering-bootcamp

Length of output: 120


🏁 Script executed:

cat -n examples/ch9/keda/k8s/base/order-processor.yaml

Repository: liatrio/engineering-bootcamp

Length of output: 974


🌐 Web query:

Kubernetes security context best practices pod level container level securityContext

💡 Result:

In Kubernetes, a security context defines privilege and access control settings for a Pod or Container [1][2]. Implementing these settings is essential for enforcing the principle of least privilege and hardening your workloads [3][4]. Key Best Practices 1. Understand Hierarchy and Overrides: Security settings can be defined at both the Pod level (applying to all containers in the Pod) and the Container level (applying only to that specific container) [1][2]. Container-level settings override Pod-level settings when there is overlap [1][3][4]. Use Pod-level settings for baseline configurations that apply to all containers, and use Container-level settings for granular, workload-specific requirements [3][4]. 2. Enforce Least Privilege: - Run as Non-Root: Always set runAsNonRoot: true and specify a non-zero runAsUser [5]. This prevents processes from running with root privileges, which is a primary target for attackers [5]. - Disable Privilege Escalation: Set allowPrivilegeEscalation: false to prevent child processes from gaining more privileges than their parent [5]. - Drop Unnecessary Capabilities: Use the capabilities field to drop all default Linux capabilities (drop: ["ALL"]) and explicitly add back only those strictly required by the application [1][5][2]. - Use Read-Only Filesystems: Set readOnlyRootFilesystem: true whenever possible to prevent unauthorized modifications to the container's filesystem [5][4]. 3. Leverage Pod Security Standards (PSS): PSS provides a standardized way to enforce security policies at the namespace level [6][7]. - Restricted Policy: This is the recommended profile for production environments [8]. It enforces current pod hardening best practices, such as requiring non-root users and blocking privilege escalation [6][8]. - Baseline Policy: Use this for development or less sensitive workloads; it prevents known privilege escalations while remaining broadly compatible [6][8]. - Avoid Privileged: The Privileged policy is unrestricted and should be avoided unless absolutely necessary for system-level workloads [8][7]. 4. Use Modern Security Profiles: - Seccomp: Explicitly set the seccompProfile to RuntimeDefault to restrict the system calls a container can make [2][6]. - AppArmor: Use the appArmorProfile field to apply pre-configured security profiles on the node [1][2]. 5. Implementation Strategy: - Gradual Adoption: When implementing PSS, use the audit and warn enforcement modes first to identify potential violations without breaking existing workloads [7][9]. - Strategic Namespacing: Organize namespaces based on the required PSS profile (e.g., separate namespaces for Restricted and Baseline workloads) [9]. - Regular Audits: Combine security contexts with other Kubernetes security features like RBAC and Network Policies to ensure a defense-in-depth posture [8][10].

Citations:


Harden order-processor runtime permissions.

The pod spec (line 15) and container definition (line 17) currently lack explicit security context configuration, allowing default privilege behavior. Add pod-level and container-level security context to enforce least privilege principles.

Suggested patch
   template:
     metadata:
       labels:
         app: order-processor
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: order-processor
           image: order-processor:local
+          securityContext:
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+            capabilities:
+              drop: ["ALL"]
+            runAsNonRoot: true
           env:
             - name: REDIS_ADDR
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spec:
containers:
- name: order-processor
image: order-processor:local
env:
- name: REDIS_ADDR
valueFrom:
secretKeyRef:
name: redis-secret
key: REDIS_ADDR
- name: PROCESS_DELAY_MS
value: "500"
resources:
requests:
cpu: 100m
limits:
cpu: 500m
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: order-processor
image: order-processor:local
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
runAsNonRoot: true
env:
- name: REDIS_ADDR
valueFrom:
secretKeyRef:
name: redis-secret
key: REDIS_ADDR
- name: PROCESS_DELAY_MS
value: "500"
resources:
requests:
cpu: 100m
limits:
cpu: 500m
🧰 Tools
🪛 Checkov (3.2.528)

[medium] 1-31: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 1-31: Minimize the admission of root containers

(CKV_K8S_23)

🪛 Trivy (0.69.3)

[error] 17-31: Root file system is not read-only

Container 'order-processor' of Deployment 'order-processor' should set 'securityContext.readOnlyRootFilesystem' to true

Rule: KSV-0014

Learn more

(IaC/Kubernetes)


[error] 17-31: Default security context configured

container order-processor in keda-demo namespace is using the default security context

Rule: KSV-0118

Learn more

(IaC/Kubernetes)


[error] 15-31: Default security context configured

deployment order-processor in keda-demo namespace is using the default security context, which allows root privileges

Rule: KSV-0118

Learn more

(IaC/Kubernetes)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ch9/keda/k8s/base/order-processor.yaml` around lines 15 - 31, Add
explicit pod and container security contexts to harden the order-processor pod:
in the Pod spec add a podSecurityContext (e.g., runAsNonRoot: true, runAsUser:
1000, fsGroup: 2000) and inside the container named "order-processor" add a
securityContext that enforces least privilege (runAsNonRoot: true, runAsUser:
1000 if not inherited, allowPrivilegeEscalation: false, readOnlyRootFilesystem:
true, capabilities: drop: ["ALL"], and seccompProfile: { type: "RuntimeDefault"
}). Update the "order-processor" container block and the surrounding spec to
include these fields so the pod and container both enforce non-root execution
and restricted capabilities.

Comment on lines +15 to +25
spec:
containers:
- name: redis
image: redis:8.6-alpine@sha256:d146f83b1e0f02fc27c26a50cee39338c736674c5959db84363e6ae3cd9e02d2
args:
- --maxmemory
- 5mb
- --maxmemory-policy
- noeviction
ports:
- containerPort: 6379
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

git ls-files "examples/ch9/keda/k8s/base/redis.yaml"

Repository: liatrio/engineering-bootcamp

Length of output: 110


🏁 Script executed:

cat -n examples/ch9/keda/k8s/base/redis.yaml

Repository: liatrio/engineering-bootcamp

Length of output: 1027


🌐 Web query:

Redis 8.6 alpine runAsNonRoot securityContext compatibility

💡 Result:

The official Redis Docker image (including the Alpine variant) is designed to run as a non-root user by default [1][2]. Starting with Redis 8.0.2, the image automatically drops privileges by switching to the 'redis' user and removing unnecessary capabilities upon startup [1][2]. Because the image already defaults to a non-root user, it is inherently compatible with Kubernetes securityContext settings such as runAsNonRoot: true [3][1]. You generally do not need to perform complex workarounds to satisfy this requirement [3]. Key considerations for your deployment: 1. Default Behavior: The image handles the transition to the 'redis' user internally [1][2]. If you attempt to run the container with a specific securityContext, ensure that the user ID (UID) and group ID (GID) you specify have the necessary permissions to access the data directory (typically /data) [3][1]. 2. Privilege Dropping: This automatic privilege dropping can be bypassed if you explicitly set the --user option in Docker or use the SKIP_DROP_PRIVS=1 environment variable [1][2]. Using these overrides is not recommended as it reduces container security [1][2]. 3. Volume Permissions: If you are mounting volumes (e.g., for persistence), you may need to ensure the host directory is owned by the appropriate user or use fsGroup in your Kubernetes securityContext to allow the containerized process to read and write to the volume [3]. In summary, Redis 8.6 Alpine is fully compatible with runAsNonRoot: true out of the box, as it is engineered to drop root privileges automatically [1][2].

Citations:


🌐 Web query:

Kubernetes securityContext capabilities drop ALL redis container compatibility

💡 Result:

Yes, the Redis container is fully compatible with dropping all Linux capabilities in Kubernetes [1]. Standard Redis deployments do not require any special Linux capabilities to function [1]. Dropping all capabilities is a recommended security best practice that aligns with the principle of least privilege [1][2][3]. To implement this in your Kubernetes manifest, configure the securityContext for your Redis container as follows: spec: containers: - name: redis image: redis:latest securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL Key considerations for this configuration: 1. Compatibility: The standard Redis server process operates in user space and does not need kernel-level privileges (such as NET_BIND_SERVICE or SYS_RESOURCE) for normal operations [1]. 2. Security Best Practice: Dropping all capabilities (drop: ["ALL"]) removes potential attack vectors that could be exploited if the container process were compromised [1][3]. 3. Privilege Escalation: Setting allowPrivilegeEscalation to false is a critical companion setting [1][4]. It prevents the container process from gaining new privileges, which effectively reinforces the dropping of capabilities [4]. 4. Exceptions: Some specialized Redis distributions or enterprise configurations (such as Redis Enterprise) may optionally request capabilities like SYS_RESOURCE to automatically adjust system limits [5]. If you are using a standard Redis image, these are not required [1]. If you encounter issues with resource limits, it is recommended to configure those limits on the host or via Kubernetes resources rather than granting the container elevated capabilities [6][5]. By combining drop: ["ALL"] with allowPrivilegeEscalation: false and running as a non-root user, you achieve a hardened security posture for your Redis workload [1][3].

Citations:


🌐 Web query:

Kubernetes seccompProfile RuntimeDefault redis container

💡 Result:

In Kubernetes, the RuntimeDefault seccomp profile is a recommended security baseline that restricts a container's system calls to a sane, runtime-defined set, blocking dangerous operations while maintaining application compatibility [1][2][3]. By default, Kubernetes does not apply this profile, leaving containers in an Unconfined state unless explicitly configured otherwise [1][2][4]. To apply the RuntimeDefault profile to a Redis container, you have two primary options: 1. Per-Pod/Container Configuration: You can explicitly set the seccomp profile in the security context of your Redis deployment or pod manifest [5][4]. This is the most common approach for individual workloads [3][6]. apiVersion: v1 kind: Pod metadata: name: redis-secure spec: securityContext: seccompProfile: type: RuntimeDefault containers: - name: redis image: redis:latest 2. Cluster-Wide Defaulting: If you want all workloads in your cluster (including Redis) to use RuntimeDefault by default, you can enable the SeccompDefault feature gate [1][2][4]. This requires configuring the kubelet on each node with the --seccomp-default flag (or via the kubelet configuration file) [1][2][7]. When enabled, any pod that does not explicitly specify a seccomp profile will automatically use the RuntimeDefault profile instead of Unconfined [1][2][8]. Note that the specific system calls allowed or blocked by RuntimeDefault depend on the underlying container runtime (e.g., containerd or CRI-O) and the host's architecture [1][2][7]. For specialized Redis deployments, such as those requiring specific capabilities like SYS_RESOURCE for managing file descriptors, you may need to ensure your security context or SecurityContextConstraints (SCC) are configured to allow those specific requirements alongside the seccomp profile [9].

Citations:


Add security context to harden the Redis container.

The pod and container specs lack security hardening. Redis 8.6-alpine is fully compatible with the following security settings which should be applied:

  • Pod-level securityContext.seccompProfile.type: RuntimeDefault restricts dangerous system calls
  • Container-level securityContext.allowPrivilegeEscalation: false prevents privilege escalation
  • Container-level securityContext.capabilities.drop: ["ALL"] removes unused Linux capabilities (Redis requires none)
  • Container-level securityContext.runAsNonRoot: true enforces non-root execution (Redis 8.0.2+ switches to the redis user automatically)
Suggested patch
 spec:
   replicas: 1
   selector:
     matchLabels:
       app: redis
   template:
     metadata:
       labels:
         app: redis
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: redis
           image: redis:8.6-alpine@sha256:d146f83b1e0f02fc27c26a50cee39338c736674c5959db84363e6ae3cd9e02d2
+          securityContext:
+            allowPrivilegeEscalation: false
+            capabilities:
+              drop: ["ALL"]
+            runAsNonRoot: true
           args:
             - --maxmemory
             - 5mb
             - --maxmemory-policy
             - noeviction
🧰 Tools
🪛 Trivy (0.69.3)

[error] 17-25: Root file system is not read-only

Container 'redis' of Deployment 'redis' should set 'securityContext.readOnlyRootFilesystem' to true

Rule: KSV-0014

Learn more

(IaC/Kubernetes)


[error] 17-25: Default security context configured

container redis in keda-demo namespace is using the default security context

Rule: KSV-0118

Learn more

(IaC/Kubernetes)


[error] 15-25: Default security context configured

deployment redis in keda-demo namespace is using the default security context, which allows root privileges

Rule: KSV-0118

Learn more

(IaC/Kubernetes)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ch9/keda/k8s/base/redis.yaml` around lines 15 - 25, Add a pod- and
container-level securityContext to the Redis Pod spec to harden the container:
under the Pod spec add securityContext with seccompProfile.type: RuntimeDefault,
and under the container entry for name: redis add securityContext with
allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], and runAsNonRoot:
true; update the existing container block (container name "redis") rather than
creating a new container and ensure these fields are applied alongside the
current image/args/ports entries.

Comment thread examples/ch9/keda/order-processor/Dockerfile
Comment thread examples/ch9/keda/Taskfile.yml
Comment thread examples/ch9/keda/Taskfile.yml Outdated
stephen2002119 and others added 3 commits May 18, 2026 09:09
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
docs/9-kubernetes-container-orchestration/9.6-keda.md (1)

65-65: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use HTML <img> tags from the root img/ directory.

Both images still use Markdown syntax and img9/... paths. Please switch to HTML image tags and root img/ paths.

As per coding guidelines, "Use HTML <img> tags for images and place all images in the root img/ folder."

Proposed fix
-![producer consumer image](img9/producer-consumer.jpg ':class=img-center :alt= producer consumer image')
+<img src="img/producer-consumer.jpg" class="img-center" alt="producer consumer image">

-![dank hpa meme](img9/dank-hpa-meme.jpg ':class=img-center :alt= dank hpa meme')
+<img src="img/dank-hpa-meme.jpg" class="img-center" alt="dank hpa meme">

Also applies to: 91-91

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/9-kubernetes-container-orchestration/9.6-keda.md` at line 65, Replace
the Markdown image syntax using the relative img9/... path with an HTML <img>
tag pointing to the root img/ directory and convert the attributes: change
"![producer consumer image](img9/producer-consumer.jpg ':class=img-center :alt=
producer consumer image')" to an HTML <img> element using
src="img/producer-consumer.jpg", class="img-center" and alt="producer consumer
image"; apply the same transformation for the other occurrence referenced (line
91) so all images use HTML <img> tags and src paths under img/.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/9-kubernetes-container-orchestration/9.6-keda.md`:
- Line 54: Replace top-level exercise section headers that currently use '##'
with H3 headers '###' — specifically change "## Exercise 1 — Meet the System" to
"### Exercise 1 — Meet the System" and update the other exercise section
headings that use '##' (the other two exercise headers mentioned) to use '###'
instead so the doc follows the guideline of reserving H2 for navigation/TOC.

In `@docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md`:
- Line 44: Change the page-level section headings that currently use "##" to
"###" so that only the navigation TOC uses H2; specifically update the "##
Tasks" heading (and the other occurrences using "##" on the same page) to "###
Tasks" (and likewise replace other "##" headings with "###") to follow the docs
convention described.
- Line 86: The task docs contain contradictory instructions about hpa.yaml: one
line says hpa.yaml is intentionally omitted for students to write an HPA and
another line requires adding hpa.yaml to the base kustomization.yaml; fix by
choosing one flow and making both lines consistent—either remove the requirement
to add hpa.yaml from kustomization.yaml (so students must create
HorizontalPodAutoscaler named order-processor-hpa in namespace keda-demo
targeting the order-processor Deployment with minReplicas: 1, maxReplicas: 10
and CPU utilization 50) or change the omission note to state that a template
hpa.yaml is provided in the base and update the omission line accordingly;
ensure references to hpa.yaml, kustomization.yaml, HorizontalPodAutoscaler,
order-processor-hpa, keda-demo, and order-processor are all aligned.

---

Duplicate comments:
In `@docs/9-kubernetes-container-orchestration/9.6-keda.md`:
- Line 65: Replace the Markdown image syntax using the relative img9/... path
with an HTML <img> tag pointing to the root img/ directory and convert the
attributes: change "![producer consumer image](img9/producer-consumer.jpg
':class=img-center :alt= producer consumer image')" to an HTML <img> element
using src="img/producer-consumer.jpg", class="img-center" and alt="producer
consumer image"; apply the same transformation for the other occurrence
referenced (line 91) so all images use HTML <img> tags and src paths under img/.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6fa50f58-eef2-4695-8f3f-c9582a673bb5

📥 Commits

Reviewing files that changed from the base of the PR and between 3cceea8 and 5d1d81a.

📒 Files selected for processing (4)
  • .cspell.json
  • docs/9-kubernetes-container-orchestration/9.6-keda.md
  • docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md
  • examples/ch9/keda/checkout-service/Dockerfile
✅ Files skipped from review due to trivial changes (1)
  • .cspell.json

Comment thread docs/9-kubernetes-container-orchestration/9.6-keda.md

---

## Tasks
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Align section header levels with docs convention.

This page uses ## as the default section level; please switch default content sections to ### and reserve ## for navigation TOC usage only.

As per coding guidelines, "Use H3 headers (###) as default within documentation pages, with H2 headers (##) reserved for navigation table of contents."

Also applies to: 68-68, 94-94, 123-123

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md` at line 44,
Change the page-level section headings that currently use "##" to "###" so that
only the navigation TOC uses H2; specifically update the "## Tasks" heading (and
the other occurrences using "##" on the same page) to "### Tasks" (and likewise
replace other "##" headings with "###") to follow the docs convention described.

Comment thread docs/specs/01-spec-keda-exercise/01-tasks-keda-exercise.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants