- vừa được xem lúc

Xử lý lỗi Kubernetes: Phần 1 - Một số "cơn đau đầu" phổ biến nhất

0 0 6

Người đăng: Minh Hoàng

Theo Viblo Asia

Mở đầu

Chắc hẳn nhiều người trong chúng ta đều đồng ý rằng Kubernetes (K8s) đã và đang thay đổi cuộc chơi trong việc quản lý và vận hành ứng dụng containerized. Sức mạnh của nó là không thể phủ nhận: khả năng tự động hóa, co giãn linh hoạt, và quản lý tài nguyên hiệu quả. Tuy nhiên, đi kèm với sức mạnh đó là một độ phức tạp không hề nhỏ. Dù bạn là một kỹ sư dày dạn kinh nghiệm hay mới bắt đầu làm quen, việc gặp phải lỗi trong quá trình triển khai và vận hành K8s gần như là điều không thể tránh khỏi.

Từ những lỗi "kinh điển" như CrashLoopBackOff khiến pod cứ khởi động rồi lại tắt, đến những vấn đề "khó nhằn" hơn liên quan đến network hay storage, mỗi lỗi đều có thể dẫn đến downtime không mong muốn, ảnh hưởng trực tiếp đến trải nghiệm người dùng và hoạt động kinh doanh. Việc hiểu rõ bản chất của các lỗi phổ biến, biết cách chẩn đoán nhanh chóng và khắc phục hiệu quả không chỉ giúp chúng ta tiết kiệm thời gian, công sức mà còn là một kỹ năng quan trọng để nâng cao độ tin cậy của hệ thống.

Trong series này, với vai trò là một người đã "ăn nằm" với Kubernetes qua 1 vài dự án lớn nhỏ, tôi muốn chia sẻ lại kinh nghiệm thực tế về việc xử lý các lỗi mà tôi và đồng nghiệp thường xuyên gặp phải nhất. Mục tiêu không phải là liệt kê lại lý thuyết suông, mà là đi sâu vào mô tả lỗi, phân tích nguyên nhân gốc rễ, đưa ra các bước khắc phục cụ thể và những mẹo nhỏ để phòng tránh chúng trong tương lai. Hy vọng rằng những chia sẻ này sẽ phần nào giúp anh em tự tin hơn khi đối mặt với những "cơn đau đầu" mang tên Kubernetes.

Chúng ta cùng bắt đầu nhé!


1. CrashLoopBackOff: Vòng lặp tử thần của Pod

image.png

Đây có lẽ là một trong những trạng thái lỗi "ám ảnh" nhất đối với bất kỳ ai vận hành Kubernetes. Nhìn thấy một Pod liên tục chuyển sang trạng thái CrashLoopBackOff thực sự là một tín hiệu không lành.

Mô tả lỗi:

Khi bạn kiểm tra trạng thái Pod bằng lệnh kubectl get pods, bạn thấy một hoặc nhiều Pod có status là CrashLoopBackOff. Điều này có nghĩa là container bên trong Pod đó đã khởi động thành công, nhưng ngay sau đó lại bị crash (kết thúc đột ngột). Kubelet (agent chạy trên mỗi node) cố gắng khởi động lại container, nhưng nó lại tiếp tục crash. Sau vài lần thử lại không thành công, Kubelet sẽ bắt đầu giãn khoảng thời gian giữa các lần khởi động lại (back-off) để tránh tạo ra gánh nặng không cần thiết, dẫn đến trạng thái CrashLoopBackOff.

Nguyên nhân:

Nguyên nhân gốc rễ thường nằm ở chính ứng dụng hoặc môi trường chạy bên trong container:

  • Lỗi trong code ứng dụng: Đây là nguyên nhân phổ biến nhất. Có thể ứng dụng gặp phải một exception không được xử lý, lỗi logic nghiêm trọng khiến nó tự động thoát, hoặc không thể kết nối tới database/service cần thiết khi khởi động.
  • Cấu hình sai: Các biến môi trường (environment variables) bị thiếu hoặc sai giá trị, đường dẫn file cấu hình không đúng, hoặc các tham số khởi động ứng dụng không chính xác.
  • Thiếu dependencies: Ứng dụng cần một thư viện hoặc file nào đó nhưng không tìm thấy trong container image.
  • Thiếu tài nguyên (Resource Limits): Container cố gắng sử dụng nhiều CPU hoặc Memory hơn giới hạn (limit) được cấp phát trong manifest. Điều này có thể dẫn đến việc nó bị OOMKilled (Out Of Memory) bởi hệ điều hành hoặc bị giới hạn CPU quá mức, gây crash.
  • Liveness Probe thất bại: Nếu bạn cấu hình Liveness Probe và nó liên tục thất bại (ví dụ: ứng dụng không phản hồi đúng cách tại endpoint kiểm tra), Kubelet sẽ coi container là không khỏe mạnh và tiến hành restart, dẫn đến vòng lặp crash nếu vấn đề không được giải quyết.

Cách khắc phục:

Bước đầu tiên và quan trọng nhất là phải tìm ra tại sao container lại crash. Kubernetes cung cấp cho chúng ta các công cụ để làm việc này:

  1. Kiểm tra logs của container bị crash:

    kubectl logs <tên-pod-bị-lỗi>
    

    Lệnh này sẽ hiển thị output (stdout/stderr) của lần chạy container gần nhất. Hãy tìm kiếm các thông báo lỗi, stack trace, hoặc bất kỳ dấu hiệu bất thường nào ngay trước khi nó dừng hoạt động.

  2. Kiểm tra logs của lần chạy trước đó (nếu có): Đôi khi lỗi chỉ xảy ra sau một thời gian chạy, và logs của lần chạy cuối cùng (vừa mới crash) có thể không đủ thông tin. Bạn có thể xem logs của container trước khi nó bị restart lần cuối:

    kubectl logs <tên-pod-bị-lỗi> --previous
    # hoặc
    kubectl logs <tên-pod-bị-lỗi> -p
    
  3. Kiểm tra Events của Pod: Events cung cấp cái nhìn tổng quan về vòng đời của Pod và các sự kiện quan trọng xảy ra với nó.

    kubectl describe pod <tên-pod-bị-lỗi>
    

    Trong output của lệnh này, hãy chú ý đến phần Events. Bạn có thể thấy các thông báo như Back-off restarting failed container hoặc các lý do khác liên quan đến việc restart.

  4. Kiểm tra Resource Requests và Limits: Nếu nghi ngờ vấn đề tài nguyên, hãy xem lại phần resources trong manifest của Pod/Deployment. Có thể memory limit quá thấp (OOMKilled thường sẽ xuất hiện trong describe pod nếu đây là nguyên nhân) hoặc CPU limit quá chặt.

    # Ví dụ trong manifest
    resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" # Có thể quá thấp? cpu: "500m"
    

    Hãy thử tăng limit lên và theo dõi xem tình trạng có cải thiện không. Tuy nhiên, đây chỉ là giải pháp tạm thời nếu nguyên nhân gốc là memory leak trong ứng dụng.

  5. Kiểm tra cấu hình và dependencies: Double-check các ConfigMap, Secret, biến môi trường được truyền vào Pod. Đảm bảo chúng tồn tại và chứa giá trị đúng.

Mẹo phòng tránh:

  • Đảm bảo code ứng dụng ổn định: Xử lý exception cẩn thận, ghi log đầy đủ.
  • Cấu hình Liveness và Readiness Probes hợp lý: Probes giúp K8s biết khi nào ứng dụng thực sự sẵn sàng nhận traffic (Readiness) và khi nào nó cần được restart do bị treo (Liveness). Tuy nhiên, cấu hình probe sai cũng có thể gây ra CrashLoopBackOff. Đảm bảo endpoint/command của probe hoạt động đúng và đặt initialDelaySeconds, timeoutSeconds, failureThreshold phù hợp.
  • Đặt Resource Requests và Limits thực tế: Dựa trên profiling ứng dụng để đặt giới hạn tài nguyên phù hợp, tránh đặt quá thấp hoặc quá cao.
  • Sử dụng Init Containers: Nếu ứng dụng cần một số điều kiện tiên quyết (ví dụ: chờ database sẵn sàng) trước khi khởi động, hãy dùng Init Containers để thực hiện các tác vụ chuẩn bị này thay vì để logic đó trong container chính.
  • Kiểm tra kỹ container image: Đảm bảo image chứa đủ dependencies và cấu hình cần thiết.

2. ImagePullBackOff / ErrImagePull: Không thể "rước" Image về nhà

image.png

Cặp đôi lỗi ImagePullBackOffErrImagePull là những vị khách không mời mà đến khá thường xuyên, đặc biệt khi bạn làm việc với các private container registry hoặc có cấu hình mạng phức tạp. Về bản chất, cả hai đều báo hiệu cùng một vấn đề: Kubelet trên node không thể kéo (pull) container image được chỉ định trong Pod manifest về máy.

Mô tả lỗi:

Khi bạn chạy kubectl get pods, bạn sẽ thấy status của Pod là ImagePullBackOff hoặc ErrImagePull. ErrImagePull thường xuất hiện ngay khi Kubelet cố gắng kéo image lần đầu và thất bại. Nếu thất bại lặp đi lặp lại, Kubelet sẽ chuyển sang trạng thái ImagePullBackOff, tương tự như cơ chế back-off của CrashLoopBackOff, để giảm tải cho registry và hệ thống.

Nguyên nhân:

Có vài lý do chính khiến Kubelet không thể "rước nàng dâu" image về:

  • Sai tên Image hoặc Tag: Đây là lỗi cơ bản nhất. Có thể bạn gõ nhầm tên image, tag (phiên bản) không tồn tại trong registry, hoặc quên không chỉ định registry (ví dụ: chỉ ghi my-app:latest thay vì my-private-registry.com/my-app:latest).
  • Vấn đề xác thực với Registry (Authentication): Nếu image nằm trong một private registry, Kubelet cần có credentials (thường là username/password hoặc token) để xác thực. Nguyên nhân có thể là:
    • Bạn chưa tạo Secret loại kubernetes.io/dockerconfigjson chứa thông tin đăng nhập registry.
    • Bạn đã tạo Secret nhưng quên không khai báo nó trong imagePullSecrets của Pod hoặc ServiceAccount.
    • Credentials trong Secret đã hết hạn hoặc không còn hợp lệ.
  • Registry không tồn tại hoặc không thể truy cập: Địa chỉ registry bị sai, hoặc có vấn đề về mạng khiến node không thể kết nối tới registry (DNS lookup lỗi, firewall chặn, network policy không cho phép...). Đôi khi registry bị quá tải hoặc gặp sự cố cũng gây ra lỗi này.
  • Image không tồn tại cho kiến trúc của Node: Ví dụ, bạn cố gắng chạy một image chỉ build cho amd64 trên một node arm64.

Cách khắc phục:

Việc gỡ rối bắt đầu bằng việc xác định chính xác nguyên nhân:

  1. Kiểm tra lại tên Image và Tag: Soi thật kỹ phần spec.containers[].image trong file manifest (Deployment, Pod, StatefulSet...). Đảm bảo tên registry (nếu có), tên image, và tag là hoàn toàn chính xác.

    kubectl describe pod <tên-pod-bị-lỗi>
    # Tìm dòng 'Image:' để xem Kubelet đang cố gắng pull image nào
    
  2. Kiểm tra Events của Pod: Lệnh describe pod một lần nữa là cứu cánh. Phần Events thường sẽ cho biết lý do cụ thể hơn, ví dụ như "failed to pull image... authentication required" hoặc "repository not found".

    kubectl describe pod <tên-pod-bị-lỗi>
    
  3. Kiểm tra imagePullSecrets (nếu dùng private registry):

    • Đảm bảo Secret chứa credentials tồn tại:
      kubectl get secret <tên-secret>
      
    • Đảm bảo Secret được khai báo đúng trong spec.imagePullSecrets của Pod hoặc trong ServiceAccount mà Pod đang sử dụng.
      # Ví dụ trong Pod spec
      spec: containers: - name: my-private-app image: my-private-registry.com/my-app:v1.0 imagePullSecrets: - name: my-registry-secret # Đảm bảo secret này tồn tại và đúng
      
  4. Kiểm tra kết nối mạng từ Node tới Registry: Đây là bước quan trọng nếu nghi ngờ vấn đề network. Bạn cần SSH vào node mà Pod đang cố gắng được schedule lên (có thể xem tên node trong kubectl describe pod) và thử:

    • Pull image thủ công bằng Docker/containerd/CRI-O:
      # Ví dụ với Docker
      docker pull my-private-registry.com/my-app:v1.0
      
      Nếu lệnh này cũng lỗi, vấn đề nằm ở tầng node/mạng.
    • Kiểm tra DNS:
      nslookup my-private-registry.com
      dig my-private-registry.com
      
    • Kiểm tra kết nối TCP tới cổng của registry (thường là 443 cho HTTPS):
      curl -v https://my-private-registry.com/v2/
      nc -zv my-private-registry.com 443
      
    • Kiểm tra firewall/Network Policy: Đảm bảo không có rule nào chặn kết nối từ node tới địa chỉ IP/port của registry.
  5. Xác thực lại Credentials: Nếu dùng private registry, hãy thử đăng nhập thủ công từ node bằng credentials trong Secret để chắc chắn chúng còn hoạt động.

Mẹo phòng tránh:

  • Luôn double-check tên image/tag: Copy-paste từ nguồn tin cậy thay vì gõ tay.
  • Quản lý imagePullSecrets cẩn thận: Sử dụng ServiceAccount để tự động gắn Secret cho các Pod trong một namespace thay vì khai báo lặp lại ở từng Pod.
  • Tự động hóa việc cập nhật credentials: Nếu credentials có thời hạn (như token), xây dựng cơ chế tự động làm mới Secret.
  • Sử dụng image proxy/cache nội bộ: Nếu có nhiều cluster hoặc node cần pull cùng image từ registry bên ngoài, cân nhắc thiết lập một registry proxy/cache bên trong mạng nội bộ (như Harbor, Nexus) để giảm tải cho registry gốc và tăng tốc độ pull.
  • Đảm bảo Network Policy thông thoáng: Nếu sử dụng Network Policy, hãy chắc chắn rằng các Pod được phép kết nối ra ngoài tới địa chỉ của container registry.

3. Pod Pending: Chờ đợi trong vô vọng

image.png

Trạng thái Pending của Pod giống như một người đang xếp hàng chờ đợi nhưng không biết bao giờ mới đến lượt mình. Pod đã được tạo trong API server, nhưng Kubernetes scheduler chưa thể tìm được một node phù hợp để "gửi gắm" nó vào.

Mô tả lỗi:

Khi bạn tạo một Pod (trực tiếp hoặc thông qua Deployment, StatefulSet, etc.), lệnh kubectl get pods hiển thị status là Pending và không thay đổi sau một thời gian đáng kể. Pod này không hề chạy trên bất kỳ node nào trong cluster.

Nguyên nhân:

Việc Pod bị kẹt ở trạng thái Pending thường xuất phát từ việc scheduler không tìm thấy node nào thỏa mãn tất cả các yêu cầu của Pod đó. Các lý do phổ biến bao gồm:

  • Thiếu tài nguyên Cluster: Đây là nguyên nhân hàng đầu. Pod yêu cầu một lượng CPU hoặc Memory (spec.containers[].resources.requests) nhất định, nhưng không có node nào trong cluster còn đủ tài nguyên trống để đáp ứng yêu cầu đó. Tổng tài nguyên yêu cầu của tất cả các Pod đang chạy cộng với Pod mới này vượt quá khả năng cung cấp của các node.
  • Không thỏa mãn Node Selector/Affinity/Anti-Affinity:
    • Node Selector: Bạn chỉ định Pod phải chạy trên các node có label cụ thể (spec.nodeSelector), nhưng không có node nào hiện có label đó.
    • Node Affinity/Anti-Affinity: Các quy tắc phức tạp hơn về việc Pod nên/không nên chạy trên node nào (dựa trên label của node hoặc của các Pod khác đang chạy) không được thỏa mãn bởi bất kỳ node nào.
  • Node bị Taints và Pod thiếu Tolerations: Node có thể được đánh dấu bằng các Taints để ngăn không cho Pod được schedule lên đó trừ khi Pod có Tolerations tương ứng. Nếu Pod không "chịu đựng" được Taint của tất cả các node có khả năng chạy nó, nó sẽ bị kẹt.
  • PersistentVolumeClaim (PVC) chưa được Bind: Nếu Pod yêu cầu một PVC (ví dụ: cho StatefulSet hoặc Pod cần lưu trữ dữ liệu lâu dài), và PVC đó chưa tìm được PersistentVolume (PV) phù hợp để bind (cũng đang ở trạng thái Pending), thì Pod sẽ không thể khởi động và cũng bị kẹt ở Pending.
  • Giới hạn về số lượng Pod trên Node: Mỗi node có một giới hạn về số lượng Pod tối đa có thể chạy (cấu hình trong kubelet). Nếu tất cả các node đã đạt giới hạn này, Pod mới sẽ phải chờ.
  • Scheduler có vấn đề: Trường hợp hiếm gặp hơn là chính Kubernetes scheduler (kube-scheduler) bị lỗi hoặc không hoạt động.

Cách khắc phục:

Chìa khóa là tìm ra lý do tại sao scheduler lại "bó tay". Lệnh kubectl describe pod một lần nữa là người bạn đồng hành đáng tin cậy:

  1. Kiểm tra Events của Pod:

    kubectl describe pod <tên-pod-bị-pending>
    

    Hãy xem kỹ phần Events ở cuối output. Scheduler thường sẽ ghi lại lý do tại sao nó không thể schedule Pod, ví dụ:

    • 0/3 nodes are available: 1 Insufficient cpu, 2 Insufficient memory. (Không đủ tài nguyên)
    • 0/3 nodes are available: 3 node(s) didn't match node selector. (Không khớp nodeSelector)
    • 0/3 nodes are available: 1 node(s) had taints that the pod didn't tolerate, 2 node(s) didn't match pod affinity/anti-affinity. (Vướng Taint hoặc Affinity)
  2. Kiểm tra Resource Requests của Pod: Xem lại spec.containers[].resources.requests trong manifest của Pod. Liệu yêu cầu có quá cao so với khả năng của cluster không?

  3. Kiểm tra tài nguyên còn lại của Nodes:

    kubectl describe nodes <tên-node>
    # Hoặc xem tổng quan
    kubectl top nodes
    

    So sánh Allocatable resources của các node với Requests của Pod đang Pending và các Pod khác đang chạy.

  4. Kiểm tra Labels, Taints của Nodes:

    kubectl get nodes --show-labels
    kubectl describe node <tên-node> | grep Taints
    

    Đối chiếu với nodeSelector, affinity, và tolerations trong manifest của Pod.

  5. Kiểm tra trạng thái PVC (nếu có):

    kubectl get pvc <tên-pvc-mà-pod-dùng>
    

    Nếu PVC cũng đang Pending, bạn cần xử lý vấn đề về PV/StorageClass trước.

  6. Xem xét tăng Capacity: Nếu nguyên nhân là thiếu tài nguyên, bạn cần xem xét việc bổ sung thêm node vào cluster hoặc tối ưu lại resource requests của các ứng dụng đang chạy.

Mẹo phòng tránh:

  • Lập kế hoạch Capacity: Dự đoán nhu cầu tài nguyên và đảm bảo cluster có đủ khả năng đáp ứng, có thể sử dụng Cluster Autoscaler.
  • Sử dụng Resource Requests và Limits hợp lý: Đặt requests sát với nhu cầu thực tế tối thiểu của ứng dụng và limits để ngăn chặn việc tiêu thụ quá mức. Tránh đặt requests quá cao không cần thiết.
  • Cấu hình Scheduling Rules cẩn thận: Sử dụng nodeSelector, affinity, taints/tolerations một cách có chủ đích và đảm bảo chúng phù hợp với cấu trúc cluster.
  • Monitor trạng thái Cluster: Theo dõi sát sao tài nguyên cluster, trạng thái node, và trạng thái PVC để phát hiện sớm các vấn đề tiềm ẩn.

4. PodInitializing: Mắc kẹt ở bước khởi động

image.png

Khác với Pending (chưa được schedule), trạng thái PodInitializing cho thấy Pod đã được scheduler "chọn mặt gửi vàng" cho một node cụ thể, nhưng đang gặp trục trặc trong quá trình chuẩn bị trước khi các container chính của ứng dụng có thể bắt đầu chạy.

Mô tả lỗi:

Bạn thấy Pod của mình hiển thị status Initializing hoặc PodInitializing khi chạy kubectl get pods. Nếu kiểm tra chi tiết hơn bằng kubectl describe pod <tên-pod>, bạn sẽ thấy một hoặc nhiều Init Containers đang chạy hoặc chờ đợi, trong khi các container ứng dụng chính (Containers) chưa được khởi tạo.

Nguyên nhân:

Trạng thái này xảy ra khi các Init Containers (nếu có) chưa hoàn thành nhiệm vụ của chúng, hoặc khi Kubernetes đang thực hiện các bước chuẩn bị cần thiết khác cho Pod. Các lý do phổ biến bao gồm:

  • Init Container chạy quá lâu: Init Container thực hiện một tác vụ tốn thời gian (ví dụ: tải dữ liệu lớn, chờ một service khác sẵn sàng) và chưa kết thúc.
  • Init Container bị lỗi: Tương tự như container chính, Init Container cũng có thể bị crash (CrashLoopBackOff) do lỗi code, cấu hình sai, thiếu tài nguyên, hoặc không thể kết nối tới tài nguyên cần thiết (ví dụ: database, API).
  • Vấn đề về Volume Mount: Pod cần mount một PersistentVolumeClaim (PVC), Secret, hoặc ConfigMap, nhưng việc mount gặp sự cố:
    • PVC chưa được bind hoặc volume chưa sẵn sàng (ví dụ: đang attach ở cloud provider).
    • Secret hoặc ConfigMap được tham chiếu trong volumeMounts hoặc envFrom không tồn tại trong namespace đó.
    • Quyền truy cập vào volume không đúng.
  • Vấn đề Network trong Init Container: Init Container cần kết nối mạng để thực hiện nhiệm vụ (ví dụ: gọi API, kiểm tra service) nhưng bị chặn bởi Network Policy hoặc gặp lỗi kết nối khác.
  • Kubelet đang chuẩn bị môi trường: Trong một số trường hợp, Kubelet cần thời gian để thiết lập network namespace, mount volumes, v.v., trước khi Init Containers có thể chạy.

Cách khắc phục:

Việc gỡ rối tập trung vào việc xác định xem Init Container nào đang gặp vấn đề hoặc bước chuẩn bị nào đang bị chậm trễ:

  1. Kiểm tra trạng thái Init Containers:

    kubectl describe pod <tên-pod-bị-initializing>
    

    Xem kỹ phần Init Containers trong output. Bạn sẽ thấy trạng thái của từng Init Container (ví dụ: Running, Terminated, Waiting). Nếu có Init Container nào ở trạng thái Waiting hoặc bị restart liên tục (có Last State: Terminated với Reason: Error hoặc Exit Code khác 0), đó chính là điểm cần tập trung.

  2. Kiểm tra logs của Init Container: Nếu một Init Container cụ thể bị nghi ngờ, hãy xem logs của nó:

    kubectl logs <tên-pod-bị-initializing> -c <tên-init-container>
    

    Tìm kiếm thông báo lỗi hoặc dấu hiệu cho thấy tại sao nó không thể hoàn thành.

  3. Kiểm tra Volumes, Secrets, ConfigMaps:

    • Xem lại phần VolumesvolumeMounts trong describe pod. Đảm bảo các PVC, Secret, ConfigMap được tham chiếu thực sự tồn tại:
      kubectl get pvc <tên-pvc>
      kubectl get secret <tên-secret>
      kubectl get configmap <tên-configmap>
      
    • Nếu PVC đang Pending, bạn cần xử lý vấn đề đó trước (quay lại Lỗi 3).
  4. Kiểm tra Network Connectivity (nếu Init Container cần mạng):

    • Xem lại Network Policies có thể đang chặn kết nối của Init Container.
    • Nếu có thể, thử exec vào một Pod khác trong cùng namespace và kiểm tra kết nối tới đích mà Init Container cần.
  5. Đảm bảo tài nguyên đủ cho Init Containers: Mặc dù thường không yêu cầu nhiều, Init Containers cũng cần CPU/Memory. Nếu node quá tải, chúng có thể chạy chậm.

Mẹo phòng tránh:

  • Tối ưu Init Containers: Giữ cho logic trong Init Containers đơn giản và nhanh chóng nhất có thể. Tránh các tác vụ quá nặng nề hoặc phụ thuộc vào các yếu tố bên ngoài không ổn định.
  • Đảm bảo Dependencies sẵn sàng: Sử dụng các cơ chế phù hợp để đảm bảo volumes, secrets, configmaps, hoặc các services mà Init Container phụ thuộc đã sẵn sàng trước khi Pod được tạo.
  • Sử dụng Readiness Probes cho Dependencies: Nếu Init Container cần chờ một service khác, hãy cân nhắc việc service đó có Readiness Probe để Init Container có thể kiểm tra trạng thái một cách đáng tin cậy.
  • Cấu hình Timeout hợp lý: Mặc dù không có timeout trực tiếp cho Init Container, nhưng nếu nó chạy quá lâu, có thể gây ảnh hưởng đến thời gian khởi động ứng dụng.

5. CreateContainerConfigError: Lỗi khi tạo cấu hình Container

image.png

Lỗi CreateContainerConfigError nghe có vẻ hơi chung chung, nhưng nó thường chỉ đích danh một vấn đề khá cụ thể: Kubernetes gặp sự cố khi cố gắng thu thập và áp dụng các cấu hình cần thiết ngay trước khi tạo ra container. Lỗi này thường xuất hiện khi Pod cố gắng sử dụng thông tin từ ConfigMap hoặc Secret nhưng không tìm thấy chúng.

Mô tả lỗi:

Khi bạn kiểm tra Pod bằng kubectl get pods, status hiển thị là CreateContainerConfigError. Nếu dùng kubectl describe pod <tên-pod>, bạn sẽ thấy thông báo lỗi rõ ràng hơn trong phần Events, thường chỉ ra rằng một ConfigMap hoặc Secret cụ thể nào đó không tìm thấy hoặc không hợp lệ.

Nguyên nhân:

Nguyên nhân cốt lõi của CreateContainerConfigError hầu như luôn liên quan đến việc tham chiếu đến các tài nguyên cấu hình không tồn tại hoặc không hợp lệ:

  • Tham chiếu đến ConfigMap không tồn tại: Pod manifest của bạn định nghĩa việc sử dụng một ConfigMap (ví dụ: để mount thành volume hoặc lấy dữ liệu làm biến môi trường thông qua envFrom hoặc valueFrom) nhưng ConfigMap với tên được chỉ định không tồn tại trong namespace đó.
  • Tham chiếu đến Secret không tồn tại: Tương tự như ConfigMap, Pod cần dùng một Secret (ví dụ: chứa API key, password, TLS certificate) nhưng Secret đó không có mặt.
  • Thiếu Key trong ConfigMap/Secret: Pod manifest yêu cầu lấy một key cụ thể từ ConfigMap hoặc Secret (ví dụ: valueFrom.configMapKeyRef.key hoặc valueFrom.secretKeyRef.key), nhưng key đó lại không tồn tại bên trong ConfigMap/Secret được tham chiếu.
  • Quyền truy cập (RBAC): Mặc dù ít phổ biến hơn cho lỗi này, nhưng trong một số trường hợp phức tạp, ServiceAccount mà Pod đang sử dụng có thể không có quyền đọc (get) ConfigMap hoặc Secret cần thiết.

Cách khắc phục:

Việc khắc phục lỗi này thường khá thẳng thắn:

  1. Kiểm tra Events của Pod: Đây là bước đầu tiên và quan trọng nhất. Lệnh describe sẽ cho bạn biết chính xác ConfigMap hay Secret nào đang bị thiếu hoặc key nào không tìm thấy.

    kubectl describe pod <tên-pod-bị-lỗi>
    # Tìm trong phần Events, ví dụ: 'Error: configmap "my-config" not found'
    # Hoặc: 'Error: secret "my-secret" not found'
    # Hoặc: 'Error: key "database_url" not found in configmap "app-config"'
    
  2. Xác minh sự tồn tại của ConfigMap/Secret: Dựa vào thông báo lỗi, hãy kiểm tra xem ConfigMap hoặc Secret đó có thực sự tồn tại trong đúng namespace không.

    kubectl get configmap <tên-configmap-bị-thiếu> -n <tên-namespace>
    kubectl get secret <tên-secret-bị-thiếu> -n <tên-namespace>
    

    Nếu không tìm thấy, bạn cần tạo ra chúng hoặc kiểm tra lại tên đã khai báo trong Pod manifest.

  3. Kiểm tra Keys bên trong ConfigMap/Secret: Nếu lỗi báo thiếu key cụ thể, hãy kiểm tra nội dung của ConfigMap/Secret đó.

    # Xem keys trong ConfigMap
    kubectl get configmap <tên-configmap> -n <tên-namespace> -o yaml # Xem keys trong Secret (dữ liệu thường được base64 encoded)
    kubectl get secret <tên-secret> -n <tên-namespace> -o yaml
    # Bạn có thể cần decode giá trị để xem key có đúng không
    # echo '<giá-trị-base64>' | base64 --decode
    

    Đảm bảo key mà Pod manifest đang tham chiếu (valueFrom...keyRef.key) tồn tại chính xác trong phần data của ConfigMap/Secret.

  4. Kiểm tra Namespace: Đảm bảo Pod và ConfigMap/Secret đang ở cùng một namespace, trừ khi bạn đang tham chiếu đến tài nguyên ở namespace khác (điều này ít phổ biến và cần cấu hình đặc biệt).

  5. Kiểm tra RBAC (nếu cần): Nếu mọi thứ có vẻ đúng nhưng lỗi vẫn xảy ra, hãy kiểm tra Role/ClusterRole và RoleBinding/ClusterRoleBinding liên quan đến ServiceAccount của Pod để đảm bảo nó có quyền get đối với ConfigMaps và/hoặc Secrets.

Mẹo phòng tránh:

  • Luôn kiểm tra sự tồn tại trước khi tham chiếu: Trước khi triển khai một Pod/Deployment sử dụng ConfigMap/Secret, hãy đảm bảo các tài nguyên đó đã được tạo và chứa đúng dữ liệu.
  • Sử dụng Helm hoặc Kustomize: Các công cụ quản lý manifest này giúp quản lý dependencies tốt hơn. Ví dụ, bạn có thể đảm bảo ConfigMap/Secret được tạo ra trước Deployment sử dụng chúng.
  • Đặt tên nhất quán: Sử dụng quy tắc đặt tên rõ ràng cho ConfigMap và Secret để tránh nhầm lẫn.
  • Tránh tham chiếu key cụ thể nếu không cần thiết: Nếu có thể, hãy mount toàn bộ ConfigMap/Secret thành volume thay vì lấy từng key làm biến môi trường, điều này giảm nguy cơ lỗi do thiếu key.

Tổng kết phần 1

Cảm ơn anh em đã dành thời gian theo dõi đến cuối bài viết! Hy vọng 5 lỗi phổ biến đầu tiên được chia sẻ ở phần này đã giúp bạn hiểu rõ hơn về cách xử lý các sự cố thường gặp "nhất" trong quá trình vận hành Kubernetes.

Tất nhiên, đây mới chỉ là một phần của chặng đường mà thôi. Trong phần tiếp theo của series, mình sẽ tiếp tục phân tích thêm 5 lỗi khác – có thể ít gặp hơn, nhưng thường gây "đau đầu" hơn vì độ phức tạp và ảnh hưởng đến hệ thống.

Hãy tiếp tục theo dõi để không bỏ lỡ phần 2 – nơi chúng ta cùng “mổ xẻ” những lỗi khó nhằn hơn và cách xử lý chúng một cách bài bản, thực tế và dễ áp dụng nhé anh em!!!

----> Phần 2 tại đây

Bình luận

Bài viết tương tự

- vừa được xem lúc

Đề thi interview DevOps ở Châu Âu

Well. Chào mọi người, mình là Rice - một DevOps Engineers ở đâu đó tại Châu Âu.

0 0 105

- vừa được xem lúc

In calculus, love also means zero.

Mình nhớ hồi năm 2 đại học, thầy giáo môn calculus, trong một giây phút ngẫu hứng, đã đưa ra cái definition này. Lúc đấy mình cũng không nghĩ gì nhiều.

0 0 74

- vừa được xem lúc

Chuyện thay đổi

Thay đổi là một thứ gì đó luôn luôn đáng sợ. Cách đây vài tháng mình có duyên đi làm cho một banking solution tên là X.

0 0 59

- vừa được xem lúc

Pet vs Cattle - Thú cưng và gia súc

Khái niệm. Pets vs Cattle là một khái niệm cơ bản của DevOps. Bài viết này sẽ nói về sự phát triển của các mô hình dịch vụ từ cốt lõi Pets and Cattle. 1.

0 0 45

- vừa được xem lúc

Git workflow được Google và Facebook sử dụng có gì hay ho

Với developer thì Git hẳn là công cụ rất quen thuộc và không thể thiếu rồi. Thế nhưng có mấy ai thực sự hiểu được Git.

0 0 97

- vừa được xem lúc

Kubernetes - Học cách sử dụng Kubernetes Namespace cơ bản

Namespace trong Kubernetes là gì. Tại sao nên sử dụng namespace.

0 0 127