Cách JVM Nhận Biết Giới Hạn Tài Nguyên Trong Môi Trường Kubernetes

Trong môi trường Kubernetes, các container thường được giới hạn tài nguyên thông qua cgroup. Tuy nhiên, các ứng dụng Java (chạy trên JVM) trước phiên bản 8u191 hoặc JDK 10 trở xuống không tự động nhận diện giới hạn tài nguyên từ cgroup, dẫn đến việc JVM có thể sử dụng vượt mức tài nguyên được cấp phát cho container.

Từ JDK 8u191 và JDK 10 trở lên, JVM đã hỗ trợ tự động phát hiện giới hạn bộ nhớ và CPU từ cgroup v1. Để kích hoạt tính năng này, cần đảm bảo:

  • Sử dụng phiên bản JVM hỗ trợ cgroup (từ 8u191+ hoặc 10+)
  • Kubernetes đang chạy với cgroup v1 (mặc định trên hầu hết các hệ thống Linux hiện tại)
  • Không ghi đè tham số -Xmx hoặc -XX:MaxRAMPercentage một cách cố định

Ví dụ cấu hình khuyến nghị trong Dockerfile hoặc manifest Kubernetes:

# Thiết lập biến môi trường để JVM tuân theo giới hạn container
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"

Hoặc trong file triển khai Kubernetes:

spec:
  containers:
  - name: app
    image: my-java-app:latest
    env:
    - name: JAVA_OPTS
      value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
    resources:
      limits:
        memory: "512Mi"
        cpu: "500m"
      requests:
        memory: "256Mi"
        cpu: "200m"

Lưu ý: -XX:+UseContainerSupport là mặc định bật từ JDK 10+, nhưng nên khai báo rõ ràng để đảm bảo tương thích ngược.

Kiến trúc Kubernetes cơ bản

Kubernetes gồm các thành phần chính:

  • Control Plane: kube-apiserver, etcd, kube-scheduler, kube-controller-manager, cloud-controller-manager
  • Node Components: kubelet, kube-proxy, container runtime (Docker, containerd, CRI-O)

Vòng đời Pod

Pod trải qua các trạng thái: PendingRunning → (Succeeded / Failed). Trạng thái NotReady thường do kubelet lỗi hoặc container crash.

Xử lý sự cố thường gặp

1. Node ở trạng thái NotReady do bật swap:

# Tắt swap tạm thời
sudo swapoff -a

# Vô hiệu hóa swap vĩnh viễn
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# Khởi động lại kubelet
sudo systemctl restart kubelet

2. Lỗi docker login do proxy:

# Di chuyển file cấu hình proxy
sudo mv /usr/lib/systemd/system/docker.service.d/http-proxy.conf{,.bak}

# Reload và khởi động lại Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

Truy cập dịch vụ qua NodePort

Sau khi triển khai service kiểu NodePort, có thể truy cập qua địa chỉ IP của bất kỳ node nào kèm cổng được ánh xạ:

kubectl get svc nginx
# Output: nginx   NodePort   10.99.204.232   <none>   80:31681/TCP

Truy cập: http://<NODE_IP>:31681

Tài nguyên học tập đáng chú ý

  • Hướng dẫn kiến trúc Kubernetes: kubernetes.io
  • Tài liệu thực hành từ qikqiak.com: troubleshooting, networking, CI/CD
  • Hướng dẫn Helm, Prometheus, Istio trong hệ sinh thái Cloud Native

Thẻ: Kubernetes JVM cgroup docker Helm

Đăng vào ngày 19 tháng 5 lúc 17:15