25 tháng 6, 2019

Kiến trúc Kubernetes: Nodes

Kiến trúc Kubernetes: Nodes

Một node là một worker machine bên trong Kubernetes, trước đó còn được biết như là một minion. Một node có thể là một VM hoặc một physical machine, điều này phụ thuộc vào cluster. Mỗi node sẽ chứa các service cần thiết để chạy các pod và được quản lý bởi các master component. Các service trên một node bao gồm container runtime, kubeletkube-proxy.

Node Status

Status của một node bao gồm các thông tin sau:

  • Addresses
  • Conditions
  • Capacity và Allocatable
  • Info

Node status và các thông tin chi tiết khác về một node có thể được hiển thị bằng cách sử dụng lệnh sau:

kubectl describe node <insert-node-name-here>

Addresses

Cách sử dụng của các trường này sẽ khác nhau tùy thuộc vào cloud provider của bạn hoặc cấu hình vật lý:

  • HostName: hostname được ghi lại bởi kernel của node. Có thể được ghi đè qua tham số kubelet --hostname-override

  • ExternalIP: địa chỉ IP của node có thể được định tuyến ở bên ngoài cluster

  • InternalIP: địa chỉ IP của node chỉ có thể được định tuyến bên trong cluster

Conditions

Trường conditions mô tả trạng thái của tất cả các node Running. Ví dụ, conditions sẽ bao gồm:

Node Condition Mô tả
OutOfDisk True nếu node không có đủ bộ nhớ để tạo thêm các pod mới, ngược lại là False
Ready True nếu node tình trạng tốt và sẵn sàng chấp nhận thêm pod, False nếu node không tình trạng tốt và không chấp nhận thêm pod, Unknown nếu node controller không nghe thấy được tín hiệu từ node-monitor-grace-period cuối cùng (mặc định là 40 giây)
MemoryPressure True nếu bộ nhớ của node ở mức thấp, ngược lại là False
PIDPressure True nếu có quá nhiều process chạy trong node, ngược lại là False
DiskPressure True nếu dung lượng đĩa cứng thấp, ngược lại là False
NetworkUnavailable True nếu network của node không được cấu hình đúng, ngược lại là False

Node condition được khai báo như một đối tượng JSON. Ví dụ, response dưới đây mô tả tình trạng của node:

"conditions": [
  {
    "type": "Ready",
    "status": "True",
    "reason": "KubeletReady",
    "message": "kubelet is posting ready status",
    "lastHeartbeatTime": "2019-06-05T18:38:35Z",
    "lastTransitionTime": "2019-06-05T11:41:27Z"
  }
]

Nếu trạng thái của Ready condition vẫn là Unknown hoặc False lâu hơn pod-eviction-timeout, thì một tham số được truyền đến kube-controller-manager và tất cả các Pod trên node được lên lịch để xóa bởi Node Controller. pod-eviction-timeout mặc định là năm phút. Trong một vài trường hợp khi node không thể truy cập thì apiserver sẽ không thể giao tiếp với kubelet trên node. Quyết định xóa các pod không thể được truyền đạt đến kubelet cho đến khi giao tiếp với apiserver được tái lập. Trong lúc đó, các pod đã được lên lịch để xóa vẫn có thể tiếp tục chạy trên nod được phân vùng.

Trong các version Kubernetes trước 1.5, node controller sẽ force delete các pod không thể truy cập đến từ apiserver. Tuy nhiên, từ version 1.5 và các version cao hơn, node controller không force delete các pod cho đến khi nó xác nhận rằng chúng đã ngừng chạy trong cluster. Bạn có thể thấy các pod có thể đang chạy trên một node không thể truy cập được như đang trong trạng thái Terminating hoặc Unknown. Trong các trường hợp Kubernetes không thể suy đoán ra một node đã vĩnh viễn rời khỏi cluster thì người quản trị cluster có thể cần xóa node bằng cách thủ công. Việc xóa đối tượng node từ Kubernetes dẫn đến việc tất cả Pod đang chạy trên node bị xóa khỏi apiserver và giải phóng tên của chúng.

Trong version 1.12, tính năng TaintNodesByCondition trở thành beta vì vậy node lifecycle controller tự động tạo các taint đại diện cho condition. Tương tự scheduler bỏ qua các điều kiện khi quyết định một node, thay vào đó nó chú ý vào các tainttoleration của Pod.

Capacity và Allocatable

Mô tả các tài nguyên sẵn có trong node: CPU, memory, và số lượng tối đa pod có thể được scheduled vào node.

Các trường trong capacity block chỉ ra tổng số tài nguyên mà một Node sở hữu. Allocatable block chỉ ra lượng tài nguyên trên Node đang sẵn sàng được tiêu thụ bởi các Pod thông thường.

Info

Thông tin chung về node như kernel version, Kubernetes version (kubeletkube-proxy version), Docker version (nếu sử dụng), tên của OS. Thông tin được thu thập bởi kubelet trong node.

Management

Không giống như podservice, một node vốn không được tạo ra bởi Kubernetes: nó được tạo bên ngoài bởi các cloud provider như GCE hoặc nó có sẵn trong nhóm các máy vật lý hoặc máy ảo của bạn. Vì vậy khi Kubernetes tạo một node, nó tạo một đối tượng đại diện cho node. Sau khi tạo, Kubernetes kiểm tra liệu node có hợp lệ hay không. Ví dụ, hãy thử tạo một node theo nội dung như sau:

{
  "kind": "Node",
  "apiVersion": "v1",
  "metadata": {
    "name": "10.240.79.157",
    "labels": {
      "name": "my-first-k8s-node"
    }
  }
}

Kubernetes tạo một node nội bộ (đại diện) và xác nhận node bằng cách kiểm tra tình trạng dựa trên trường metadata.name. Nếu node hợp lệ - tất cả service cần thiết đều chạy - nó sẽ đủ điều kiện để chạy một pod. Ngược lại, nó được bỏ qua trong bất kỳ hoạt động nào của cluster cho đến khi trở thành hợp lệ.

Hiện tại, có ba thành phần tương tác với Kubernetes node interface: node controller, kubeletkubectl.

Node Controller

Node controller là một master component quản lý nhiều khía cạnh khác nhau của các node.

Node controller có nhiều vai trò trong vòng đời của một node. Đầu tiên là việc gán CIDR block cho node khi nó được đăng ký (nếu CIDR assignment được bật).

Thứ hai là giữ danh sách các node nội bộ của node controller luôn cập nhật mới nhất theo danh sách các machine sẵn dùng của cloud provider. Khi chạy trong môi trường cloud, bất cứ khi nào một node trong tình trạng không tốt thì node controller sẽ hỏi cloud provider liệu VM cho node đó có sẵn dùng hay không. Nếu không, node controller xóa node đó khỏi danh sách các node của nó.

Thứ ba là theo dõi tình trạng của các node. Node controller chịu trách nhiệm cập nhật NodeReady condition của NodeStatus thành ConditionUnknown khi một node trở nên không thể truy cập đến (ví dụ như node bị down), và sau đó thu hồi tất cả pod khỏi node đó (sử dụng graceful termination) nếu node này tiếp tục không thể truy cập (timeout mặc định là 40s để khởi động báo cáo ConditionUnknown và 5 phút sau đó để khởi động quá trình thu hồi pod). Node controller liên tục kiểm tra trạng thái của mỗi node trong khoảng thời gian mỗi --node-monitor-period giây.

Trong các version Kubernetes trước 1.13, NodeStatus chính là tín hiệu theo dõi của node. Bắt đầu từ version 1.13, tính năng cho thuê node được giới thiệu là một tính năng alpha (NodeLease). Khi tính năng NodeLease được bật, mỗi node sẽ có một đối tượng Lease được liên kết trong namespace kube-node-lease, namespace được làm mới định kì; cả NodeStatusnode lease được coi như tín hiệu từ node. Các node lease được làm mới thường xuyên trong khi NodeStatus chỉ được báo cáo từ node đến master khi có các thay đổi hoặc đã đủ thời gian (mặc định là 1 phút, lâu hơn thời gian 40s timeout cho các node không thể truy cập). Vì node lease nhẹ hơn nhiều so với NodeStatus nên tính năng này làm cho tín hiệu của node trở nên rẻ hơn đáng kể từ cả hai khía cạnh là khả năng mở rộng và hiệu suất.

Từ version 1.4, node controller sẽ xem xét trạng thái của tất cả node trong cluster trước khi đưa ra quyết định thu hồi pod.

Trong nhiều trường hợp, node controller giới hạn tỉ lệ thu hồi thành --node-eviction-rate (mặc định là 0.1) mỗi giây, điều này nghĩa là nó sẽ không thu hồi pod từ hơn một node mỗi 10 giây.

Hành vi thu hồi thay đổi khi một node trong vùng khả dụng đã biết có tình trạng không tốt. Node controller kiểm tra tỉ lệ các node trong vùng tình trạng không tốt (NodeReady condition là ConditionUnknown hoặc ConditionFalse) ở trong cùng thời điểm. Nếu tỉ lệ các node trong tình trạng không tốt ít nhất là --unhealthy-zone-threshold (mặc định là 0.55) thì tỉ lệ thu hồi sẽ giảm xuống: nếu cluster nhỏ (ví dụ nhỏ hơn hoặc bằng --large-cluster-size-threshold node, mặc định 50) thì việc thu hồi bị dừng, mặt khác tỉ lệ thu hồi sẽ giảm xuống --secondary-node-eviction-rate (mặc định 0.01) mỗi giây. Lí do các chính sách này được triển khai trên mỗi vùng khả dụng là vì một vùng khả dụng có thể trở thành phân vùng từ master trong khi những các vùng còn lại vẫn được kết nối.

Từ version Kubernetes 1.6, NodeController cũng chịu trách nhiệm thu hồi các pod đang chạy trên node có các NoExecute taint, khi pod không tolerate các taint. Hơn nữa, vì là tính năng alpha nên mặc định nó bị disable, NodeContoller chịu trách nhiêm thêm các taint tương ứng với các vấn đề của node như node không thể truy cập hay không sẵn sàng (not ready).

Self-Registration

Khi flag kubelet --register-node được thiết lập là true (giá trị mặc định), kubelet sẽ cố gắng tự đăng ký với API server. Đây là mô hình được sử dụng bởi hầu hết các distro.

Để tự đăng ký, kubelet được khởi động với các option sau:

  • --kubeconfig - Đường dẫn đến các credential để tự xác thực đến apiserver.

  • --cloud-provider - cách giao tiếp với một cloud provider để đọc metadata của chính nó.

  • --register-node - tự động đăng ký với API server.

  • --register-with-taints - đăng ký node với dánh sách taint đã cung cấp (phân cách bằng dấu phảy <key>=<value>:<effect>). Không hoạt động nếu register-nodefalse.

  • --node-ip - địa chỉ IP của node.

  • --node-labels - nhãn của node khi đăng ký node trong cluster

  • --node-status-update-frequency - chỉ định tần suất kubelet gửi status của node đến master.

Khi Node authorization mode và NodeRestriction admission plugin được bật thì các kubelet chỉ được phép tạo và sửa đổi tài nguyên Node của riêng chúng

Manual Node Administration

Một quản trị viên cluster có thể tạo và sửa đổi các đối tượng node.

Nếu quản trị viên muốn tạo các đối tượng node theo cách thủ công thì cần thiết lập cờ kubelet--register-node=false.

Quản trị viên có thể sửa đổi các tài nguyên của node (kể cả thiết lập --register-node). Các sửa đổi bao gồm thiết lập các nhãn trên node và đánh dấu nó là unschedulable.

Nhãn của các node có thể được sử dụng kết hợp với các node selector trên các pod để điều khiển scheduling, ví dụ như ràng buộc một pod chỉ đủ điều kiện chạy trên một tập hợp con của các node.

Bằng cách đánh dấu một node là unschedulable sẽ ngăn chặn các pod mới được scheduled tới node đó, nhưng không áp dụng cho các pod đã tồn tại ở trên node. Việc này sẽ hữu ích vì nó như một bước chuẩn bị trước khi reboot node,... Ví dụ, để đánh dấu một node là unschedulable, ta cần chạy lệnh sau:

kubectl cordon $NODENAME

Node capacity

Capacity của một node (số lượng CPU và số lượng memory) là một thành phần của node. Thông thường, các node tự đăng ký và báo cáo capacity của chúng khi tạo node. Nếu bạn đang quản lý node theo cách thủ công thì bạn cần thiết lập node capacity khi thêm một node mới.

Kubernetes scheduler đảm bảo có đủ các tài nguyên cho tất cả pod trên một node. Nó kiểm tra tổng số request của các container trên node không lớn hơn node capacity. Điều này bao gồm tất cả container được khởi động bởi kubelet, nhưng không bao gồm các container được khởi động trực tiếp bới container runtime cũng như bất kỳ tiến trình nào chạy bên ngoài các container.