CNB lifecycle
When kpack
Kubernetes-native build service that runs CNB builds on-cluster and pushes images to a registry. builds Pulse
Sample app in this lab — HTTP service monitor with dashboard, API, and Kubernetes health probes., Cloud Native Buildpacks
Cloud Native Buildpacks (CNB) — turn application source into OCI images without a Dockerfile per app.
buildpacks.io run in ordered phases inside a build pod on EKS
Amazon Elastic Kubernetes Service — this lab uses cluster name `cluster-1`. — trigger, lifecycle, then the image in ECR.
vs CodeBuild
Section titled “vs CodeBuild”| Familiar (CodeBuild) | This lab |
|---|---|
buildspec.yml phases |
CNB lifecycle phases (diagram above) |
| Build project pulls git, runs Docker | kpack Kubernetes-native build service that runs CNB builds on-cluster and pushes images to a registry. Image schedules a build pod |
docker build / push in post_build |
Lifecycle Export → ECR Amazon Elastic Container Registry — stores OCI images built by kpack; EKS pulls from here. via IRSA IAM Roles for Service Accounts — pods use a Kubernetes service account annotated with an IAM role ARN. |
| App repo owns a Dockerfile | Source + optional project.toml only |
Before the phases
Section titled “Before the phases”Trigger
Section titled “Trigger”kpack polls CodeCommit
AWS managed Git hosting — GitHub alternative used for app source and deploy manifests in this lab. pulse-app (or reacts after you push). Watch the Image:
export AWS_PROFILE=sandboxexport AWS_PAGER=""export AWS_REGION=ap-southeast-2
kubectl get image pulse -wA Ready Image with latestSuccessfulImage pointing at …/pulse:main means a build already finished. To re-watch phases, push a commit to pulse-app or note the next build pod name below.
Inputs
Section titled “Inputs”# No Dockerfile in the app treefind demo/app -iname 'Dockerfile*' -o -iname '*.dockerfile' | head
cat demo/app/project.tomlproject.toml tells Paketo
Paketo Buildpacks — mature open-source builders for Go, Node, Java, Python, and more. which Go package to build (BP_GO_TARGETS):
[[build.env]]name = "BP_GO_TARGETS"value = "./cmd/pulse"Builder on the cluster:
kubectl get clusterbuilder defaultLifecycle steps
Section titled “Lifecycle steps”Find the latest build pod and follow its logs:
kubectl get pods -n default -l image.kpack.io/image=pulse \ --sort-by=.metadata.creationTimestamp
BUILD_POD=$(kubectl get pods -n default -l image.kpack.io/image=pulse \ --sort-by=.metadata.creationTimestamp \ -o jsonpath='{.items[-1:].metadata.name}')echo "BUILD_POD=$BUILD_POD"kubectl -n default logs -f "$BUILD_POD" --all-containersIf no build pods remain, trigger a rebuild (push to pulse-app) or inspect a completed Build:
kubectl get builds -n defaultkubectl describe build pulse-build-1 -n defaultPhases match the diagram. In kpack’s creator logs you often see Detect / Restore / Build / Export as these signatures (not always the classic === DETECTING === banners):
1 · Analyze
Section titled “1 · Analyze”Validates registry access and reads metadata from the previous app image so later phases can reuse layers. Look for lines about restoring metadata / previous image.
2 · Detect
Section titled “2 · Detect”Chooses which Paketo buildpacks apply. For Pulse expect something like:
5 of 9 buildpacks participatingpaketo-buildpacks/go-distpaketo-buildpacks/go-mod-vendorpaketo-buildpacks/go-build3 · Restore
Section titled “3 · Restore”Copies cached layers from earlier builds (Restoring metadata for "…" from app image).
4 · Build
Section titled “4 · Build”Buildpacks transform source into runnable artifacts. With BP_GO_TARGETS=./cmd/pulse, Paketo runs Go build — for example:
Paketo Buildpack for Go Build … Running 'go build … ./cmd/pulse'5 · Export
Section titled “5 · Export”Assembles the OCI image and pushes pulse:main to ECR (kpack service account + IRSA — no docker push from your laptop):
Saving …/pulse:main...Build successfulConfirm the Image and registry:
kubectl get image pulseaws ecr describe-images --repository-name pulse --image-ids imageTag=main \ --query 'imageDetails[0].{pushed:imagePushedAt,digest:imageDigest}' \ --output tableRebuild loop
Section titled “Rebuild loop”- Edit
demo/app/, commit, push to CodeCommitpulse-app kubectl get image pulse -wuntil Ready again- Watch the new build pod logs through Detect → Build → Export
- Restart the workload so it picks up the
:maintag (eval uses a mutable tag):
kubectl rollout restart deployment/pulse -n defaultNo Dockerfile and no manual docker push.
Optional local check (same engine as the cluster): see kpack vs pack and pack
CLI from the CNB project — builds images locally or in CI using builders and buildpacks. inspect-image once you have pulled pulse:main.
Success criteria
Section titled “Success criteria”- No Dockerfile under
demo/app/pulse-app - Build pod logs show Detect → Build → Export (CNB lifecycle)
-
pulse:mainin ECR after the build - Rebuild on CodeCommit push without a laptop
docker push
Verify the service — LoadBalancer, dashboard, /healthz.