Vấn đề: Pod bị kẹt ở trạng thái Init:CrashLoopBackOff
Bạn đã triển khai manifest của mình, nhưng Pod chỉ đứng yên đó. Trong Kubernetes, initContainers đóng vai trò như những người gác cổng. Container ứng dụng chính sẽ không cố gắng khởi động cho đến khi mọi init container hoàn thành thành công với mã thoát (exit code) là 0. Nếu một container thất bại và rơi vào vòng lặp khởi động lại, Pod của bạn sẽ bị tê liệt ở trạng thái Init:CrashLoopBackOff.
Đây là một điểm nghẽn phổ biến. Vì container chính chưa được tạo, việc chạy các lệnh log thông thường thường không trả về kết quả gì ngoài sự thất vọng. Bạn bị bỏ lại với việc gỡ lỗi một quy trình mà về mặt kỹ thuật thậm chí còn chưa bắt đầu.
Bước 1: Xác định chính xác Container bị lỗi
Các Pod thường chạy nhiều init container theo trình tự. Bước đầu tiên của bạn là xác định mắt xích cụ thể nào trong chuỗi bị hỏng. Sử dụng lệnh describe để kiểm tra trạng thái nội bộ của Pod.
kubectl describe pod <pod-name>
Cuộn xuống phần Init Containers:. Bạn cần tìm một mã thoát khác không hoặc một trạng thái lỗi cụ thể:
Init Containers:
install-assets:
Container ID: containerd://...
Image: node:18-alpine
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 127
Trong trường hợp này, container install-assets đang bị lỗi. Mã thoát 127 thường gợi ý lỗi "command not found" (không tìm thấy lệnh) bên trong shell của container.
Bước 2: Trích xuất Log chính xác
Lệnh kubectl logs <pod-name> tiêu chuẩn thường mặc định trỏ vào container ứng dụng chính. Vì container đó chưa tồn tại, lệnh sẽ thất bại. Để xem lỗi thực tế, bạn phải nhắm mục tiêu cụ thể vào init container bằng cách sử dụng flag -c.
kubectl logs <pod-name> -c <init-container-name>
Nếu container bị crash liên tục, các log hiện tại có thể trống rỗng. Hãy sử dụng flag --previous để xem log từ lần thực thi thất bại gần nhất. Đây thường là nơi chứa "bằng chứng thép" (smoking gun).
kubectl logs <pod-name> -c <init-container-name> --previous
Các nguyên nhân phổ biến và cách khắc phục
1. Không tương thích Shell Script và Binary
Nhiều nhà phát triển sử dụng các image nhẹ như alpine hoặc busybox cho các tác vụ init. Nếu script của bạn sử dụng #!/bin/bash nhưng image chỉ chứa /bin/sh, container sẽ bị crash ngay lập tức. Tương tự, việc thiếu quyền thực thi trên tệp script (chmod +x) cũng sẽ gây ra lỗi.
Cách tiếp cận cải tiến: Sử dụng một khối script mạnh mẽ trong YAML của bạn và luôn bao gồm set -e để bắt lỗi sớm.
command:
- /bin/sh
- -c
- |
set -e
echo "Đang kiểm tra kết nối cơ sở dữ liệu..."
# Sử dụng /dev/tcp nếu thiếu nc
timeout 5 sh -c 'cat < /dev/null > /dev/tcp/db-service/5432'
2. Thiếu ConfigMaps hoặc Secrets
Nếu init container của bạn yêu cầu mật khẩu cơ sở dữ liệu từ một Secret không tồn tại trong namespace hiện tại, Pod sẽ thất bại. Kubernetes thậm chí sẽ không khởi động container nếu tham chiếu valueFrom bị thiếu. Tuy nhiên, nếu secret tồn tại nhưng key bị sai, script của bạn có thể bị crash trong quá trình thực thi.
Cách khắc phục: Xác minh các secret của bạn bằng lệnh kubectl get secret và đảm bảo các key khớp chính xác với định nghĩa env của bạn.
3. Cạn kiệt tài nguyên (OOMKilled)
Các init container thực hiện các tác vụ nặng—như chạy migration cơ sở dữ liệu hoặc biên dịch asset—thường cần nhiều tài nguyên hơn ứng dụng chính. Nếu bạn đặt giới hạn bộ nhớ là 128Mi nhưng công cụ migration đạt đỉnh ở mức 256Mi, kernel sẽ kill tiến trình đó.
Giải pháp: Tìm lỗi Reason: OOMKilled trong đầu ra của lệnh describe pod. Tăng giới hạn tài nguyên cụ thể cho init container:
resources:
limits:
memory: "512Mi"
cpu: "500m"
4. Lỗi RBAC và quyền truy cập
Init container của bạn có sử dụng curl để giao tiếp với Kubernetes API không? Nếu có, nó cần một ServiceAccount với các Role phù hợp. Không có chúng, log của bạn sẽ hiển thị lỗi 403 Forbidden. Luôn kiểm tra xem serviceAccountName của Pod có các quyền cần thiết để thực hiện tác vụ của nó hay không.
Xác minh: Xác nhận bản sửa lỗi
Sau khi cập nhật manifest và áp dụng các thay đổi, hãy theo dõi quá trình chuyển đổi. Một Pod khỏe mạnh sẽ trải qua các giai đoạn sau:
Init:0/1(Init container đầu tiên đang khởi động).PodInitializing(Tất cả init container đã hoàn thành; container chính đang được pull).Running(Thành công).
Kiểm tra log sự kiện bằng lệnh kubectl get events --sort-by='.lastTimestamp' để đảm bảo không còn vấn đề lập lịch (scheduling) tiềm ẩn nào.
Những điểm chính cần lưu ý
- Init container chạy tuần tự: Chúng chạy từng cái một. Nếu một cái thất bại, toàn bộ Pod sẽ dừng lại.
- Không có health check: Init container không hỗ trợ liveness hoặc readiness probe. Chúng phụ thuộc hoàn toàn vào mã thoát (exit code).
- Tính lũy đẳng (Idempotency) là quan trọng: Vì init container có thể khởi động lại nhiều lần, các script của chúng phải đảm bảo an toàn khi chạy lặp lại mà không làm hỏng dữ liệu của bạn.
- Luôn sử dụng
-c: Bạn không thể gỡ lỗi những gì bạn không nhìn thấy. Log mục tiêu là công cụ mạnh mẽ nhất của bạn.

