Day 43 of building OrderHub in public takes yesterday's docker compose up and turns it into a real Kubernetes deployment — 8 Spring Boot services, each with liveness and readiness probes wired to Spring Boot Actuator, plus a ConfigMap, a Secret, and a JUnit test that parses every manifest so the topology can't silently drift.
One Deployment + Service per app
Each of the 8 runnable services (config-server, eureka, gateway, order, inventory, payment, shipping, notification) gets a Deployment and a ClusterIP Service. The images are the ones built on Day 42 (orderhub/<svc>:0.1.0), the container port matches the EXPOSE, and the Service port lines up with it. Shared config comes from a ConfigMap (orderhub-config) and secrets from a Secret (orderhub-secrets) — consumed via envFrom, so no config is baked into an image.
Probes wired to Actuator — the important part
Kubernetes has three probes and they do different jobs:
-
readiness →
/actuator/health/readiness— gates whether the Service sends traffic to the pod. Fails during startup or when a dependency is down, so no request hits a half-ready app. -
liveness →
/actuator/health/liveness— gates restarts. If the app deadlocks, Kubernetes kills and replaces it. - startup → shields a slow JVM cold start so liveness doesn't kill the pod before it's up.
Spring Boot exposes those two health groups only when you turn them on:
# activated ONLY under the k8s profile — local/compose behaviour is unchanged
spring:
config:
activate:
on-profile: k8s
management:
endpoint:
health:
probes:
enabled: true
group:
readiness:
include: readinessState,db
liveness:
include: livenessState
The whole k8s wiring is profile-gated (SPRING_PROFILES_ACTIVE=k8s set in the ConfigMap), so the local Docker Compose and the test suite stay byte-for-byte the same.
readinessProbe:
httpGet: { path: /actuator/health/readiness, port: 8082 }
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet: { path: /actuator/health/liveness, port: 8082 }
periodSeconds: 10
Test the manifests, don't hope
Day 42 shipped a test that parsed docker-compose.yml; Day 43 does the same for Kubernetes. KubernetesManifestTest loads every YAML with SnakeYAML (no cluster needed) and asserts: each app has a Deployment + a Service, images and ports match, every Deployment declares liveness and readiness probes pointing at the actuator paths, and each one envFroms the ConfigMap and Secret. If someone adds a service and forgets a probe, the build goes red.
mvn clean test across all 8 modules: BUILD SUCCESS, 155 tests (up from 152 — the +3 are the manifest test).
The Secret holds only clearly-labelled base64 placeholders — real values come from the platform (a sealed secret / vault) at deploy time, never the repo.
Full manifests + the kill-a-pod self-heal walkthrough:
- Live: https://dev48v.infy.uk/orderhub/day43-kubernetes.html
- Repo: https://github.com/dev48v/order-hub-from-zero
Next: Helm + Ingress, so the whole stack installs with one helm install.
Top comments (0)