Solution¶
Triage¶
- Get pod status and restart count:
- Describe the pod to see container state and exit code:
- Attempt to read logs (will be empty):
- Check the exit code in the terminated state -- 127 means "command not found."
Root Cause¶
Exit code 127 indicates the shell could not find the command specified as the container's entrypoint. The Dockerfile uses a multi-stage build. The final stage copies the compiled binary from the build stage, but the recent Dockerfile change modified the build output path without updating the COPY instruction in the final stage. As a result, the binary is missing from the final image.
Since the entrypoint binary does not exist, the container exits immediately before any application code runs, producing zero log output.
Example of the bug in the Dockerfile:
# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o /app/bin/auth-service ./cmd/auth # Output path changed
# Final stage
FROM gcr.io/distroless/static
COPY --from=builder /app/auth-service /auth-service # OLD path, file does not exist
ENTRYPOINT ["/auth-service"]
Fix¶
- Immediate: Roll back the deployment to the previous working image:
- Fix the Dockerfile: Correct the COPY path in the final stage:
- Build, test locally, and push the corrected image:
- Update the deployment with the fixed image.
Rollback / Safety¶
kubectl rollout undois safe and instant -- it creates a new ReplicaSet with the previous pod template.- Verify the rollback succeeded:
kubectl rollout status deployment auth-service -n prod. - Add a CI step that runs
docker run <image> --versionor a smoke test to catch missing binaries before deploy.
Common Traps¶
- Assuming empty logs means a Kubernetes issue. Empty logs almost always mean the process never started. Look at the exit code.
- Confusing exit code 126 (permission denied) with 127 (not found). Both produce empty logs but have different causes.
- Not testing distroless/scratch images locally. These images have no shell, making in-cluster debugging very difficult.
- Using
kubectl execon a CrashLoopBackOff pod. The container restarts too fast. Usekubectl debugwith an ephemeral container or override the entrypoint to sleep. - Overlooking dynamic linker errors. If using a compiled binary in a minimal image, missing libc or other shared libraries also cause exit code 127. Check with
lddin the build stage.