This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Container

Công nghệ đóng gói một ứng dụng cùng với các thành phần phụ thuộc mà ứng dụng cần khi chạy.

Trang này trình bày về container và container image, cũng như cách sử dụng chúng trong vận hành và phát triển giải pháp.

Từ container được dùng với nhiều nghĩa khác nhau. Mỗi khi dùng từ này, bạn hãy kiểm tra xem người nghe có hiểu theo cùng một định nghĩa với bạn hay không.

Mỗi container mà bạn chạy đều có thể tái lập (repeatable); việc chuẩn hóa bằng cách đóng gói kèm các thành phần phụ thuộc giúp bạn nhận được cùng một hành vi ở bất cứ nơi nào bạn chạy container đó.

Container tách rời ứng dụng khỏi hạ tầng máy chủ (host) bên dưới. Điều này giúp việc triển khai trở nên dễ dàng hơn trên các môi trường đám mây hoặc hệ điều hành khác nhau.

Mỗi node trong một cluster Kubernetes chạy các container tạo nên các Pod được gán cho node đó. Các container trong một Pod luôn được đặt cùng vị trí (co-located) và lập lịch cùng nhau (co-scheduled) để chạy trên cùng một node.

Container image

Một container image là một gói phần mềm sẵn sàng để chạy, chứa mọi thứ cần thiết để chạy một ứng dụng: mã chương trình và mọi runtime mà nó cần, các thư viện ứng dụng và thư viện hệ thống, cùng với giá trị mặc định cho mọi thiết lập thiết yếu.

Container được thiết kế theo hướng stateless và bất biến: bạn không nên thay đổi mã của một container đang chạy. Nếu bạn có một ứng dụng đã được container hóa và muốn thay đổi nó, quy trình đúng là build một image mới có chứa thay đổi đó, sau đó tạo lại container để khởi động từ image đã được cập nhật.

Container runtime

Một thành phần cơ bản mà ủy quyền cho Kubernetes chạy các container một cách có hiệu quả. Nó chịu trách nhiệm quản lý việc thực thi và vòng đời của các container trong môi trường Kubernetes.

Kubernetes hỗ trợ các container runtime như containerd, CRI-O, và bất kỳ những triển khai nào của Kubernetes CRI (Container Runtime Interface).

Thông thường, bạn có thể để cluster tự chọn container runtime mặc định cho một Pod. Nếu bạn cần dùng nhiều hơn một container runtime trong cluster, bạn có thể chỉ định RuntimeClass cho Pod để đảm bảo rằng Kubernetes chạy các container đó bằng một container runtime cụ thể.

Bạn cũng có thể dùng RuntimeClass để chạy các Pod khác nhau với cùng một container runtime nhưng với các thiết lập khác nhau.

1 - Image

Một container image là dữ liệu nhị phân đóng gói một ứng dụng cùng toàn bộ các thành phần phụ thuộc phần mềm của nó. Container image là các gói phần mềm có thể thực thi, có thể chạy độc lập và có những giả định được xác định rất rõ ràng về môi trường runtime của chúng.

Thông thường, bạn tạo một container image cho ứng dụng của mình và push nó lên một registry trước khi tham chiếu tới nó trong một Pod.

Trang này trình bày tổng quan về khái niệm container image.

Lưu ý:

Nếu bạn đang tìm các container image cho một bản phát hành Kubernetes (chẳng hạn v1.37, bản phát hành minor mới nhất), hãy truy cập Tải xuống Kubernetes.

Tên image

Container image thường được đặt tên như pause, example/mycontainer hoặc kube-apiserver. Image cũng có thể bao gồm hostname của registry; ví dụ: fictional.registry.example/imagename, và có thể có cả số cổng; ví dụ: fictional.registry.example:10443/imagename.

Nếu bạn không chỉ định hostname của registry, Kubernetes sẽ giả định rằng bạn muốn dùng Docker public registry. Bạn có thể thay đổi hành vi này bằng cách thiết lập một image registry mặc định trong cấu hình của container runtime.

Sau phần tên image, bạn có thể thêm tag hoặc digest (giống như khi dùng với các lệnh như docker hoặc podman). Tag giúp bạn phân biệt các phiên bản khác nhau trong cùng một loạt image. Digest là định danh duy nhất cho một phiên bản cụ thể của image. Digest là giá trị băm (hash) của nội dung image, và không thể thay đổi. Tag có thể được chuyển sang trỏ tới các image khác, nhưng digest thì cố định.

Tag của image gồm các chữ cái thường và chữ hoa, chữ số, dấu gạch dưới (_), dấu chấm (.) và dấu gạch ngang (-). Một tag có thể dài tối đa 128 ký tự, và phải tuân theo mẫu regex sau: [a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}. Bạn có thể đọc thêm và tìm regex dùng để kiểm tra tính hợp lệ trong OCI Distribution Specification. Nếu bạn không chỉ định tag, Kubernetes sẽ giả định rằng bạn muốn dùng tag latest.

Digest của image gồm một thuật toán băm (chẳng hạn sha256) và một giá trị băm. Ví dụ: sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07. Bạn có thể tìm thêm thông tin về định dạng digest trong OCI Image Specification.

Một số ví dụ về tên image mà Kubernetes có thể sử dụng:

  • busybox — Chỉ có tên image, không có tag hay digest. Kubernetes sẽ dùng Docker public registry và tag latest. Tương đương với docker.io/library/busybox:latest.
  • busybox:1.32.0 — Tên image kèm tag. Kubernetes sẽ dùng Docker public registry. Tương đương với docker.io/library/busybox:1.32.0.
  • registry.k8s.io/pause:latest — Tên image với registry tùy chỉnh và tag latest.
  • registry.k8s.io/pause:3.5 — Tên image với registry tùy chỉnh và tag không phải latest.
  • registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — Tên image kèm digest.
  • registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — Tên image kèm tag và digest. Khi pull image, chỉ digest được sử dụng.

Cập nhật image

Khi bạn tạo lần đầu một Deployment, StatefulSet, Pod, hoặc đối tượng khác có chứa PodTemplate, và chính sách pull (pull policy) không được chỉ định rõ ràng, thì theo mặc định, chính sách pull của tất cả các container trong Pod đó sẽ được đặt thành IfNotPresent. Chính sách này khiến kubelet bỏ qua việc pull một image nếu image đó đã tồn tại.

Chính sách pull image

imagePullPolicy của một container và tag của image cùng ảnh hưởng tới thời điểm kubelet cố gắng pull (tải xuống) image được chỉ định.

Dưới đây là danh sách các giá trị bạn có thể đặt cho imagePullPolicy và tác dụng của từng giá trị:

IfNotPresent
image chỉ được pull nếu nó chưa có sẵn ở máy cục bộ.
Always
mỗi khi kubelet khởi chạy một container, kubelet yêu cầu container runtime pull image. Container runtime liên hệ với registry, phân giải tag hoặc tên image thành một digest, và tải xuống các layer chưa được lưu đệm (cache) ở máy cục bộ. Nếu tất cả các layer đã có sẵn, container runtime sẽ dùng image đã được cache mà không tải lại. Bản thân kubelet không kiểm tra xem image đã được cache ở máy cục bộ hay chưa; kubelet luôn giao việc này cho container runtime.
Never
kubelet không cố gắng tải image. Nếu bằng cách nào đó image đã có sẵn ở máy cục bộ, kubelet sẽ cố gắng khởi động container; nếu không, quá trình khởi động sẽ thất bại. Xem image được pull sẵn để biết thêm chi tiết.

Nhờ cơ chế cache của container runtime, ngay cả imagePullPolicy: Always cũng hoạt động hiệu quả, miễn là registry luôn truy cập được ổn định. Container runtime có thể nhận biết rằng các layer của image đã tồn tại trên node nên không cần tải xuống lại.

Lưu ý:

Bạn nên tránh dùng tag :latest khi triển khai container trong môi trường production vì khi đó sẽ khó theo dõi phiên bản nào của image đang chạy hơn và khó rollback đúng cách hơn.

Thay vào đó, hãy chỉ định một tag có ý nghĩa như v1.42.0 và/hoặc một digest.

Để đảm bảo Pod luôn dùng cùng một phiên bản của container image, bạn có thể chỉ định digest của image; thay <image-name>:<tag> bằng <image-name>@<digest> (ví dụ, image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2).

Khi dùng tag của image, nếu image registry thay đổi phần mã mà tag của image đó đại diện, bạn có thể gặp tình trạng lẫn lộn giữa các Pod chạy mã cũ và mã mới. Digest của image định danh duy nhất một phiên bản cụ thể của image, vì vậy Kubernetes sẽ chạy cùng một mã mỗi khi khởi động một container với tên image và digest đó. Việc chỉ định image bằng digest sẽ cố định mã mà bạn chạy, nhờ đó thay đổi ở registry không thể gây ra tình trạng lẫn lộn phiên bản như vậy.

Có những admission controller của bên thứ ba có thể thay đổi (mutate) các Pod (và PodTemplate) khi chúng được tạo, sao cho workload đang chạy được xác định dựa trên digest của image thay vì tag. Điều đó có thể hữu ích nếu bạn muốn đảm bảo toàn bộ workload của mình đang chạy cùng một mã, bất kể tag ở registry thay đổi thế nào.

Chính sách pull image mặc định

Khi bạn (hoặc một controller) gửi một Pod mới tới API server, cluster của bạn sẽ đặt trường imagePullPolicy khi thỏa mãn các điều kiện cụ thể sau:

  • nếu bạn bỏ qua trường imagePullPolicy và chỉ định digest cho container image, imagePullPolicy sẽ tự động được đặt thành IfNotPresent.
  • nếu bạn bỏ qua trường imagePullPolicy và tag của container image là :latest, imagePullPolicy sẽ tự động được đặt thành Always.
  • nếu bạn bỏ qua trường imagePullPolicy và không chỉ định tag cho container image, imagePullPolicy sẽ tự động được đặt thành Always.
  • nếu bạn bỏ qua trường imagePullPolicy và chỉ định một tag cho container image không phải là :latest, imagePullPolicy sẽ tự động được đặt thành IfNotPresent.

Lưu ý:

Giá trị imagePullPolicy của container luôn được đặt khi đối tượng được tạo lần đầu, và không được cập nhật nếu tag hoặc digest của image thay đổi sau đó.

Ví dụ, nếu bạn tạo một Deployment với image có tag không phải là :latest, và sau đó cập nhật image của Deployment đó sang tag :latest, trường imagePullPolicy sẽ không chuyển thành Always. Bạn phải tự thay đổi chính sách pull của bất kỳ đối tượng nào sau khi nó được tạo lần đầu.

Bắt buộc pull image

Nếu bạn muốn luôn bắt buộc pull, bạn có thể làm theo một trong các cách sau:

  • Đặt imagePullPolicy của container thành Always.
  • Bỏ qua imagePullPolicy và dùng :latest làm tag cho image cần dùng; Kubernetes sẽ đặt chính sách thành Always khi bạn gửi Pod.
  • Bỏ qua imagePullPolicy và tag cho image cần dùng; Kubernetes sẽ đặt chính sách thành Always khi bạn gửi Pod.
  • Bật admission controller AlwaysPullImages.

ImagePullBackOff

Khi kubelet bắt đầu tạo các container cho một Pod bằng container runtime, có thể container sẽ ở trạng thái Waiting do ImagePullBackOff.

Trạng thái ImagePullBackOff có nghĩa là container không thể khởi động vì Kubernetes không thể pull container image (vì những lý do như tên image không hợp lệ, hoặc pull từ một registry riêng tư mà không có imagePullSecret). Phần BackOff cho biết Kubernetes sẽ tiếp tục thử pull image, với độ trễ back-off tăng dần.

Kubernetes tăng độ trễ giữa các lần thử cho tới khi đạt giới hạn được biên dịch sẵn, là 300 giây (5 phút).

Pull image theo runtime class

TRẠNG THÁI TÍNH NĂNG: Alpha since Kubernetes v1.29; disabled by default
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the RuntimeClassInImageCriApi feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Kubernetes có hỗ trợ ở mức alpha cho việc pull image dựa trên RuntimeClass của Pod.

Nếu bạn bật feature gate RuntimeClassInImageCriApi, kubelet sẽ tham chiếu container image bằng một bộ (tuple) gồm tên image và runtime handler thay vì chỉ dùng tên image hoặc digest. Container runtime của bạn có thể điều chỉnh hành vi dựa trên runtime handler được chọn. Pull image dựa trên runtime class hữu ích cho các container chạy trên máy ảo (VM), chẳng hạn container Windows Hyper-V.

Pull image tuần tự và song song

Theo mặc định, kubelet pull các image một cách tuần tự. Nói cách khác, tại mỗi thời điểm kubelet chỉ gửi một yêu cầu pull image tới image service. Các yêu cầu pull image khác phải đợi cho tới khi yêu cầu đang được xử lý hoàn tất.

Mỗi node đưa ra quyết định pull image một cách độc lập. Ngay cả khi bạn dùng chế độ pull image tuần tự, hai node khác nhau vẫn có thể pull cùng một image song song.

Nếu bạn muốn bật pull image song song, bạn có thể đặt trường serializeImagePulls thành false trong cấu hình kubelet. Khi serializeImagePulls được đặt thành false, các yêu cầu pull image sẽ được gửi ngay tới image service, và nhiều image sẽ được pull cùng lúc.

Khi bật pull image song song, hãy đảm bảo rằng image service của container runtime có thể xử lý việc pull image song song.

Kubelet không bao giờ pull nhiều image song song cho cùng một Pod. Ví dụ, nếu bạn có một Pod gồm một init container và một container ứng dụng, việc pull image cho hai container này sẽ không diễn ra song song. Tuy nhiên, nếu bạn có hai Pod dùng các image khác nhau, và tính năng pull image song song được bật, kubelet sẽ pull các image song song cho hai Pod khác nhau đó.

Số lượng pull image song song tối đa

TRẠNG THÁI TÍNH NĂNG: GA since Kubernetes v1.35

Khi serializeImagePulls được đặt thành false, theo mặc định kubelet không giới hạn số lượng image tối đa được pull cùng lúc. Nếu bạn muốn giới hạn số lượng pull image song song, bạn có thể đặt trường maxParallelImagePulls trong cấu hình kubelet. Khi maxParallelImagePulls được đặt thành n, chỉ n image có thể được pull cùng lúc, và mọi lượt pull image vượt quá n sẽ phải đợi cho tới khi ít nhất một lượt pull image đang diễn ra hoàn tất.

Việc giới hạn số lượng pull image song song giúp tránh việc pull image tiêu tốn quá nhiều băng thông mạng hoặc I/O ổ đĩa, khi pull image song song được bật.

Bạn có thể đặt maxParallelImagePulls thành một số dương lớn hơn hoặc bằng 1. Nếu bạn đặt maxParallelImagePulls lớn hơn hoặc bằng 2, bạn phải đặt serializeImagePulls thành false. Kubelet sẽ không khởi động được nếu thiết lập maxParallelImagePulls không hợp lệ.

Image đa kiến trúc với image index

Ngoài việc cung cấp các image nhị phân, một container registry cũng có thể cung cấp một container image index. Một image index có thể trỏ tới nhiều image manifest cho các phiên bản dành riêng cho từng kiến trúc của một container. Ý tưởng là bạn có thể có một tên cho image (ví dụ: pause, example/mycontainer, kube-apiserver) và cho phép các hệ thống khác nhau tải về đúng image nhị phân cho kiến trúc máy mà chúng đang sử dụng.

Dự án Kubernetes thường tạo container image cho các bản phát hành của mình với tên có hậu tố -$(ARCH). Để tương thích ngược, hãy tạo các image cũ hơn kèm hậu tố. Ví dụ, một image có tên pause sẽ là một image đa kiến trúc chứa manifest cho tất cả các kiến trúc được hỗ trợ, trong khi pause-amd64 sẽ là phiên bản tương thích ngược cho các cấu hình cũ hơn, hoặc cho các file YAML có tên image kèm hậu tố được viết cứng (hardcode).

Sử dụng registry riêng tư

Registry riêng tư (private registry) có thể yêu cầu xác thực thì mới khám phá và/hoặc pull được image từ đó. Thông tin xác thực (credential) có thể được cung cấp theo nhiều cách:

Các tùy chọn này được giải thích chi tiết hơn ở bên dưới.

Chỉ định imagePullSecrets trên một Pod

Lưu ý:

Đây là cách được khuyến nghị để chạy các container dựa trên image trong registry riêng tư.

Kubernetes hỗ trợ chỉ định khóa của container image registry trên một Pod. Tất cả imagePullSecrets phải là các Secret tồn tại trong cùng Namespace với Pod. Các Secret này phải có kiểu kubernetes.io/dockercfg hoặc kubernetes.io/dockerconfigjson.

Cấu hình node để xác thực với registry riêng tư

Hướng dẫn cụ thể về cách thiết lập thông tin xác thực phụ thuộc vào container runtime và registry mà bạn chọn sử dụng. Bạn nên tham khảo tài liệu của giải pháp mà bạn dùng để có thông tin chính xác nhất.

Để xem ví dụ về cách cấu hình một container image registry riêng tư, hãy xem tác vụ Pull một Image từ Registry riêng tư. Ví dụ đó sử dụng một registry riêng tư trên Docker Hub.

Kubelet credential provider cho việc pull image có xác thực

Bạn có thể cấu hình kubelet để gọi một plugin dạng tệp nhị phân (binary) nhằm lấy thông tin xác thực registry cho một container image một cách động. Đây là cách mạnh mẽ và linh hoạt nhất để lấy thông tin xác thực cho registry riêng tư, nhưng cũng đòi hỏi phải cấu hình ở cấp kubelet để bật.

Kỹ thuật này đặc biệt hữu ích khi chạy các static Pod cần container image được lưu trữ trong registry riêng tư. Bạn không thể dùng ServiceAccount hoặc Secret để cung cấp thông tin xác thực cho registry riêng tư trong đặc tả của một static Pod, vì static Pod không thể tham chiếu tới các tài nguyên API khác trong đặc tả của mình.

Xem Cấu hình kubelet image credential provider để biết thêm chi tiết.

Cách diễn giải config.json

Cách diễn giải config.json khác nhau giữa bản triển khai Docker gốc và cách diễn giải của Kubernetes. Trong Docker, các key trong auths chỉ có thể chỉ định URL gốc, trong khi Kubernetes cho phép cả URL dạng glob lẫn đường dẫn khớp theo tiền tố. Hạn chế duy nhất là các mẫu glob (*) phải bao gồm dấu chấm (.) cho mỗi subdomain. Số lượng subdomain được khớp phải bằng số lượng mẫu glob (*.), ví dụ:

  • *.kubernetes.io sẽ không khớp với kubernetes.io, nhưng sẽ khớp với abc.kubernetes.io.
  • *.*.kubernetes.io sẽ không khớp với abc.kubernetes.io, nhưng sẽ khớp với abc.def.kubernetes.io.
  • prefix.*.io sẽ khớp với prefix.kubernetes.io.
  • *-good.kubernetes.io sẽ khớp với prefix-good.kubernetes.io.

Điều này có nghĩa là một config.json như sau là hợp lệ:

{
    "auths": {
        "my-registry.example/images": { "auth": "…" },
        "*.my-registry.example/images": { "auth": "…" }
    }
}

Các thao tác pull image sẽ chuyển thông tin xác thực tới CRI container runtime cho mọi mẫu hợp lệ. Ví dụ, các tên container image sau sẽ được khớp thành công:

  • my-registry.example/images
  • my-registry.example/images/my-image
  • my-registry.example/images/another-image
  • sub.my-registry.example/images/my-image

Tuy nhiên, các tên container image sau sẽ không được khớp:

  • a.sub.my-registry.example/images/my-image
  • a.b.sub.my-registry.example/images/my-image

Kubelet thực hiện pull image tuần tự với từng thông tin xác thực tìm được. Điều này có nghĩa là config.json cũng có thể có nhiều mục cho các đường dẫn khác nhau:

{
    "auths": {
        "my-registry.example/images": {
            "auth": "…"
        },
        "my-registry.example/images/subpath": {
            "auth": "…"
        }
    }
}

Khi đó, nếu một container chỉ định image my-registry.example/images/subpath/my-image cần được pull, kubelet sẽ thử tải image bằng cả hai nguồn xác thực nếu một trong hai nguồn thất bại.

Image được pull sẵn

Lưu ý:

Cách này phù hợp nếu bạn có thể kiểm soát cấu hình node. Nó sẽ không hoạt động ổn định nếu nhà cung cấp đám mây của bạn quản lý các node và tự động thay thế chúng.

Theo mặc định, kubelet cố gắng pull từng image từ registry được chỉ định. Tuy nhiên, nếu thuộc tính imagePullPolicy của container được đặt thành IfNotPresent hoặc Never, thì image cục bộ sẽ được sử dụng (tương ứng là ưu tiên dùng hoặc chỉ dùng image cục bộ).

Nếu bạn muốn dựa vào các image được pull sẵn để thay thế cho việc xác thực với registry, bạn phải đảm bảo tất cả các node trong cluster đều có cùng các image được pull sẵn.

Cách này có thể được dùng để tải trước một số image nhằm tăng tốc độ hoặc làm phương án thay thế cho việc xác thực với registry riêng tư.

Tương tự như cách dùng kubelet credential provider, các image được pull sẵn cũng phù hợp để khởi chạy các static Pod phụ thuộc vào image được lưu trữ trong registry riêng tư.

Lưu ý:

TRẠNG THÁI TÍNH NĂNG: Beta since Kubernetes v1.35; enabled by default

Quyền truy cập vào các image được pull sẵn có thể được cấp phép theo cơ chế xác minh thông tin xác thực khi pull image.

Đảm bảo xác minh thông tin xác thực khi pull image

TRẠNG THÁI TÍNH NĂNG: Beta since Kubernetes v1.35; enabled by default

Nếu feature gate KubeletEnsureSecretPulledImages được bật cho cluster của bạn, Kubernetes sẽ kiểm tra thông tin xác thực của mọi image cần thông tin xác thực để pull, ngay cả khi image đó đã có sẵn trên node. Việc kiểm tra này đảm bảo rằng những image trong yêu cầu của Pod chưa từng được pull thành công bằng thông tin xác thực được cung cấp sẽ phải được pull lại từ registry. Ngoài ra, các lượt pull image dùng lại cùng thông tin xác thực đã từng pull image thành công trước đó sẽ không cần pull lại từ registry mà được kiểm tra cục bộ, không cần truy cập registry (với điều kiện image có sẵn ở máy cục bộ). Việc này được điều khiển bởi trường imagePullCredentialsVerificationPolicy trong cấu hình Kubelet.

Cấu hình này quy định khi nào phải xác minh thông tin xác thực pull image nếu image đã có sẵn trên node:

  • NeverVerify: Mô phỏng hành vi khi feature gate này bị tắt. Nếu image có sẵn ở máy cục bộ, thông tin xác thực pull image sẽ không được xác minh.
  • NeverVerifyPreloadedImages: Các image được pull bên ngoài kubelet sẽ không được xác minh, nhưng tất cả các image khác sẽ được xác minh thông tin xác thực. Đây là hành vi mặc định.
  • NeverVerifyAllowListedImages: Các image được pull bên ngoài kubelet và có trong preloadedImagesVerificationAllowlist được chỉ định trong cấu hình kubelet sẽ không được xác minh.
  • AlwaysVerify: Tất cả các image sẽ được xác minh thông tin xác thực trước khi có thể được sử dụng.

Việc xác minh này áp dụng cho image được pull sẵn, image được pull bằng secret ở cấp node, và image được pull bằng secret ở cấp Pod.

Lưu ý:

Trong trường hợp xoay vòng thông tin xác thực (credential rotation), thông tin xác thực trước đây đã dùng để pull image sẽ tiếp tục được xác minh mà không cần truy cập registry. Thông tin xác thực mới hoặc đã được xoay vòng sẽ yêu cầu image phải được pull lại từ registry.

Bật KubeletEnsureSecretPulledImages lần đầu tiên

Khi KubeletEnsureSecretPulledImages được bật lần đầu tiên, dù là do nâng cấp kubelet hay do bật tính năng một cách tường minh, nếu kubelet có thể truy cập bất kỳ image nào vào thời điểm đó, tất cả các image này sẽ được coi là đã được pull sẵn. Điều này xảy ra vì trong trường hợp này kubelet không có bản ghi nào về việc các image đã được pull. Kubelet chỉ có thể bắt đầu tạo bản ghi pull image khi một image bất kỳ được pull lần đầu tiên.

Nếu đây là điều bạn lo ngại, bạn nên dọn khỏi các node tất cả những image không nên được coi là pull sẵn trước khi bật tính năng này.

Lưu ý rằng việc xóa thư mục chứa các bản ghi pull image cũng sẽ có tác dụng tương tự khi kubelet khởi động lại, cụ thể là các image đang được container runtime cache trên các node đều sẽ được coi là đã được pull sẵn.

Tạo Secret bằng cấu hình Docker

Bạn cần biết tên người dùng, mật khẩu registry và địa chỉ email client để xác thực với registry, cũng như hostname của registry đó. Chạy lệnh sau, thay các giá trị giữ chỗ bằng giá trị phù hợp:

kubectl create secret docker-registry <name> \
  --docker-server=<docker-registry-server> \
  --docker-username=<docker-user> \
  --docker-password=<docker-password> \
  --docker-email=<docker-email>

Nếu bạn đã có sẵn file thông tin xác thực Docker thì thay vì dùng lệnh ở trên, bạn có thể import file thông tin xác thực đó thành một Secret của Kubernetes. Tạo Secret dựa trên thông tin xác thực Docker hiện có giải thích cách thiết lập việc này.

Cách này đặc biệt hữu ích nếu bạn đang dùng nhiều container registry riêng tư, vì kubectl create secret docker-registry tạo ra một Secret chỉ hoạt động với một registry riêng tư duy nhất.

Lưu ý:

Pod chỉ có thể tham chiếu tới image pull secret trong namespace của chính nó, vì vậy quy trình này cần được thực hiện một lần cho mỗi namespace.

Tham chiếu imagePullSecrets trên một Pod

Bây giờ, bạn có thể tạo các pod tham chiếu tới secret đó bằng cách thêm phần imagePullSecrets vào định nghĩa Pod. Mỗi mục trong mảng imagePullSecrets chỉ có thể tham chiếu tới một Secret trong cùng namespace.

Ví dụ:

cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey
EOF

cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF

Việc này cần được thực hiện cho mỗi Pod sử dụng registry riêng tư.

Tuy nhiên, bạn có thể tự động hóa quy trình này bằng cách chỉ định phần imagePullSecrets trong tài nguyên ServiceAccount. Xem Thêm ImagePullSecrets vào Service Account để biết hướng dẫn chi tiết.

Bạn có thể dùng cách này kết hợp với file .docker/config.json trên từng node. Các thông tin xác thực sẽ được hợp nhất.

Các trường hợp sử dụng

Có một số giải pháp để cấu hình registry riêng tư. Dưới đây là một số trường hợp sử dụng phổ biến và giải pháp được đề xuất.

  1. Cluster chỉ chạy các image không độc quyền (ví dụ: mã nguồn mở). Không cần ẩn image.
    • Sử dụng image công khai từ registry công khai
      • Không cần cấu hình.
      • Một số nhà cung cấp đám mây tự động cache hoặc mirror các image công khai, giúp cải thiện tính sẵn sàng và giảm thời gian pull image.
  2. Cluster chạy một số image độc quyền cần được ẩn với những người bên ngoài công ty, nhưng hiển thị với tất cả người dùng cluster.
    • Sử dụng một registry riêng tư được lưu trữ (hosted)
      • Có thể cần cấu hình thủ công trên các node cần truy cập registry riêng tư.
    • Hoặc, chạy một registry riêng tư nội bộ phía sau tường lửa với quyền đọc mở.
      • Không cần cấu hình Kubernetes.
    • Sử dụng một dịch vụ container image registry được lưu trữ (hosted) có kiểm soát quyền truy cập image
      • Cách này sẽ hoạt động tốt hơn với tính năng tự động điều chỉnh số lượng Node (Node autoscaling) so với cấu hình node thủ công.
    • Hoặc, trên một cluster mà việc thay đổi cấu hình node gây bất tiện, hãy dùng imagePullSecrets.
  3. Cluster có các image độc quyền, trong đó một vài image yêu cầu kiểm soát truy cập nghiêm ngặt hơn.
    • Đảm bảo admission controller AlwaysPullImages đang hoạt động. Nếu không, tất cả các Pod đều có khả năng truy cập vào mọi image.
    • Chuyển dữ liệu nhạy cảm vào một tài nguyên Secret, thay vì đóng gói nó trong image.
  4. Một cluster nhiều tenant (multi-tenant), trong đó mỗi tenant cần registry riêng tư của riêng mình.
    • Đảm bảo admission controller AlwaysPullImages đang hoạt động. Nếu không, tất cả các Pod của tất cả các tenant đều có khả năng truy cập vào mọi image.
    • Chạy một registry riêng tư có yêu cầu phân quyền.
    • Tạo thông tin xác thực registry cho mỗi tenant, lưu vào một Secret, và phân phối Secret đó tới namespace của mọi tenant.
    • Sau đó, tenant thêm Secret đó vào imagePullSecrets của mỗi namespace.

Nếu bạn cần truy cập nhiều registry, bạn có thể tạo một Secret cho mỗi registry.

Kubelet credential provider tích hợp sẵn kiểu cũ

Trong các phiên bản Kubernetes cũ hơn, kubelet được tích hợp trực tiếp với thông tin xác thực của nhà cung cấp đám mây. Điều này cho phép lấy thông tin xác thực cho các image registry một cách động.

Có ba bản triển khai tích hợp sẵn của kubelet credential provider: ACR (Azure Container Registry), ECR (Elastic Container Registry), và GCR (Google Container Registry).

Kể từ phiên bản 1.26 của Kubernetes, cơ chế cũ này đã bị loại bỏ, vì vậy bạn cần thực hiện một trong hai cách:

  • cấu hình kubelet image credential provider trên mỗi node; hoặc
  • chỉ định thông tin xác thực pull image bằng imagePullSecrets và ít nhất một Secret.

Tiếp theo là gì

2 - Các biến môi trường của Container

Trang này mô tả các tài nguyên có sẵn cho các Containers trong môi trường Container.

Môi trường container

Môi trường Container trong Kubernetes cung cấp một số tài nguyên quan trọng cho Container:

  • Một hệ thống tệp tin (filesystem), là sự kết hợp của một image và một hoặc nhiều volumes.
  • Thông tin về chính container đó.
  • Thông tin về các đối tượng (object) khác trong cluster.

Thông tin container

Hostname của một Container là tên của Pod mà Container đang chạy trong đó. Có thể lấy thông tin qua lệnh hostname hoặc lệnh gọi hàm gethostname trong libc.

Tên của Pod và namespace có thể lấy ở các biến môi trường thông qua downward API.

Các biến môi trường do người dùng định nghĩa từ định nghĩa của Pod cũng có trong thông tin của Container, như là mọi biến môi trường khác được xác định tĩnh trong Docker image.

Thông tin cluster

Một danh sách tất cả các services đang chạy khi một Container được tạo đều có trong Container dưới dạng các biến môi trường. Các biến môi trường này đều khớp với cú pháp của các Docker links.

Đối với một service có tên là foo ánh xạ với Container có tên là bar, các biến sau được xác định:

FOO_SERVICE_HOST=<host mà service đang chạy>
FOO_SERVICE_PORT=<port mà service đang chạy>

Các services có địa chỉ IP và có sẵn cho Container thông qua DNS nếu DNS addon được enable. 

Tiếp theo là gì

3 - Container Lifecycle Hooks

Trang này mô tả cách mà kubelet quản lý các Container có thể sử dụng framework Container lifecycle hook để chạy mã nguồn được kích hoạt bởi các sự kiện trong lifecycle của nó.

Tổng quan

Tương tự như nhiều framework ngôn ngữ lập trình có thành phần các lifecycle hooks, như là Angular, Kubernetes cung cấp các Container cùng với các lifecycle hook. Các hooks cho phép các Container nhận thức được các sự kiện trong lifecycle của chúng và chạy mã nguồn được triển khai trong một trình xử lý khi lifecycle hook tương ứng được thực thi.

Container hooks

Có 2 hooks được cung cấp cho các Containers:

PostStart

Hook này thực thi ngay sau khi một container được tạo mới. Tuy nhiên, không có gì đảm bảo rằng hook này sẽ thực thi trước container ENTRYPOINT. Không có tham số nào được truyền cho trình xử lý (handler).

PreStop

Hook này được gọi tức thì ngay trước khi một container bị chấm dứt bởi một API request hoặc sự kiện quản lý như liveness/startup probe failure, preemption, tranh chấp tài nguyên và các vấn đề khác. Một lời gọi tới PreStop hook thất bại nếu container ở trạng thái đã chấm dứt (terminated) hoặc đã hoàn thành (completed) và hook phải hoàn thành trước khi tín hiệu TERM được gửi tới để dừng container. Thời gian gia hạn chấm dứt của Pod bắt đầu trước khi hook PreStop được chạy, nên Container cuối cùng sẽ chấm dứt trong thời gian gia hạn chấm dứt của Pod bất kể kết quả của handler là gì. Không có tham số nào được truyền cho trình xử lý (handler).

Xem thêm chi tiết về hành vi chấm dứt (termination behavior) tại Termination of Pods.

Các cách thực hiện Hook handler (Hook handler implementations)

Các Containers có thể truy cập một hook bằng cách thực hiện và đăng ký một handler cho hook đó. Có 3 loại hook handler có thể được triển khai cho các Containers:

  • Exec - Thực thi một lệnh cụ thể, như là pre-stop.sh trong cgroups và namespaces của Container. Tài nguyên được sử dụng bởi lệnh được tính vào Container.
  • HTTP - Thực thi một HTTP request với một endpoint cụ thể trên Container.
  • Sleep - Dừng container trong một khoảng thời gian. Đây là tính năng đang ở beta-level, được tự động bật bởi PodLifecycleSleepAction feature gate.

Lưu ý:

Tính năng beta PodLifecycleSleepActionAllowZero được bật mặc định từ bản v1.33. Tính năng này cho phép bạn thiết lập thời gian sleep là 0 giây (hay không thực hiện hành động nào) cho các hooks Sleep lifecycle của bạn.

Thực thi hook handler (Hook handler execution)

Khi một hook quản lý Container lifecycle được gọi, hệ thống quản lý Kubernetes thực thi trình xử lý (handler) dựa trên hành động của hook. httpGet, tcpSocket (deprecated) và sleep được thực thi bởi tiến trình kubelet, còn exec được thực thi trong container.

Lời gọi hook PostStart handler được khởi tạo khi một container được tạo, nghĩa là container ENTRYPOINT và hook PostStart được kích hoạt đồng thời. Tuy nhiên, nếu hook PostStart mất quá nhiều thời gian để chạy hoặc bị treo, container không thể chuyển sang trạng thái running.

Các hooks PreStop không được thực thi bất đồng bộ với tín hiệu dừng Container; hook phải được hoàn thành thực thi trước khi tín hiệu TERM được gửi. Nếu hook PreStop bị treo khi thực thi, Pod phase ở trạng thái Terminating và tiếp tục cho tới khi bị chấm dứt sau terminationGracePeriodSeconds hết hạn. Khoảng thời gian gia hạn này bằng tổng thời gian mà cả hook PreStop thực thi và Container dừng lại một cách bình thường. Ví dụ, nếu terminationGracePeriodSeconds là 60, và hook mất 55 giây để hoàn thành, và Container mất thêm 10 giây để dừng lại sau khi nhận được tín hiệu, thì Container sẽ bị chấm dứt trước khi nó kịp dừng bình thường, vì terminationGracePeriodSeconds nhỏ hơn tổng thời gian cần thiết để thực hiện hai việc này (55+10).

Nếu hook PostStart hoặc PreStop thất bại, nó sẽ xóa Container.

Người dùng nên làm cho hook handlers nhẹ nhất có thể. Tuy nhiên, có những trường hợp khi những lệnh chạy dài có ý nghĩa, chẳng hạn như khi lưu trạng thái trước khi dừng một container.

Hook delivery guarantees

Hook delivery được trù định ít nhất một lần, điều đó có nghĩa là hook có thể được gọi nhiều lần cho bất kỳ sự kiện cho trước nào, chẳng hạn như PostStart hoặc PreStop. Tùy thuộc vào việc thực hiện hook để xử lý việc này một cách chính xác.

Nhìn chung, chỉ có các deliveries đơn được thực hiện. Ví dụ, nếu một HTTP hook receiver bị down và không thể nhận các traffic, sẽ không được gửi lại. Tuy nhiên, trong một số trường hợp hiếm hoi, delivery kép có thể xảy ra. Chẳng hạn, nếu một kubelet khởi động lại ở giữa quá trình gửi một hook, hook có thể được gửi lại sau khi kubelet quay trở lại.

Debugging Hook handlers

Log cho một Hook handler không được hiển thị trong các Pod events. Nếu một handler thất bại vì lí do nào đó, nó sẽ broadcast một event. Đối với PostStart, đây là event FailedPostStartHook, và đối với PreStop, đây là event FailedPreStopHook. Để tự tạo ra một event lỗi FailedPostStartHook, bạn có thể điều chỉnh file lifecycle-events.yaml để thay đổi lệnh postStart thành "badcommand" và áp dụng nó. Dưới đây là một số ví dụ output của events từ việc chạy lệnh kubectl describe pod lifecycle-demo:

Events:
  Type     Reason               Age              From               Message
  ----     ------               ----             ----               -------
  Normal   Scheduled            7s               default-scheduler  Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2...
  Normal   Pulled               6s               kubelet            Successfully pulled image "nginx" in 229.604315ms
  Normal   Pulling              4s (x2 over 6s)  kubelet            Pulling image "nginx"
  Normal   Created              4s (x2 over 5s)  kubelet            Created container lifecycle-demo-container
  Normal   Started              4s (x2 over 5s)  kubelet            Started container lifecycle-demo-container
  Warning  FailedPostStartHook  4s (x2 over 5s)  kubelet            Exec lifecycle hook ([badcommand]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(30229739-9651-4e5a-9a32-a8f1688862db)" failed - error: command 'badcommand' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: \"badcommand\": executable file not found in $PATH: unknown\r\n"
  Normal   Killing              4s (x2 over 5s)  kubelet            FailedPostStartHook
  Normal   Pulled               4s               kubelet            Successfully pulled image "nginx" in 215.66395ms
  Warning  BackOff              2s (x2 over 3s)  kubelet            Back-off restarting failed container

Tiếp theo là gì

4 - Runtime Class

TRẠNG THÁI TÍNH NĂNG: GA since Kubernetes v1.20

Trang này mô tả tài nguyên RuntimeClass và cơ chế lựa chọn runtime.

RuntimeClass là một tính năng dùng để chọn cấu hình container runtime. Cấu hình container runtime được dùng để chạy các container của một Pod.

Động lực

Bạn có thể đặt RuntimeClass khác nhau cho các Pod khác nhau để cân bằng giữa hiệu năng và bảo mật. Ví dụ, nếu một phần workload của bạn cần mức đảm bảo an toàn thông tin cao, bạn có thể chọn lập lịch các Pod đó sao cho chúng chạy trên một container runtime sử dụng ảo hóa phần cứng. Khi đó bạn sẽ có thêm khả năng cô lập từ runtime thay thế này, đổi lại là phát sinh thêm một số chi phí phụ trội (overhead).

Bạn cũng có thể dùng RuntimeClass để chạy các Pod khác nhau với cùng một container runtime nhưng với các thiết lập khác nhau.

Thiết lập

  1. Cấu hình bản triển khai CRI trên các node (tùy thuộc vào runtime)
  2. Tạo các tài nguyên RuntimeClass tương ứng

1. Cấu hình bản triển khai CRI trên các node

Các cấu hình có thể dùng thông qua RuntimeClass phụ thuộc vào bản triển khai Container Runtime Interface (CRI). Xem tài liệu tương ứng (bên dưới) của bản triển khai CRI mà bạn dùng để biết cách cấu hình.

Lưu ý:

Theo mặc định, RuntimeClass giả định rằng cấu hình node là đồng nhất trên toàn cluster (nghĩa là tất cả các node đều được cấu hình giống nhau về container runtime). Để hỗ trợ cấu hình node không đồng nhất, xem phần Lập lịch bên dưới.

Mỗi cấu hình có một tên handler tương ứng, được RuntimeClass tham chiếu tới. Handler phải là một tên DNS label hợp lệ.

2. Tạo các tài nguyên RuntimeClass tương ứng

Mỗi cấu hình được thiết lập ở bước 1 cần có một tên handler đi kèm để định danh cấu hình đó. Với mỗi handler, hãy tạo một đối tượng RuntimeClass tương ứng.

Tài nguyên RuntimeClass hiện chỉ có 2 trường quan trọng: tên của RuntimeClass (metadata.name) và handler (handler). Định nghĩa đối tượng trông như sau:

# RuntimeClass được định nghĩa trong API group node.k8s.io
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  # Tên dùng để tham chiếu tới RuntimeClass.
  # RuntimeClass là tài nguyên không thuộc namespace nào.
  name: myclass 
# Tên của cấu hình CRI tương ứng
handler: myconfiguration 

Tên của một đối tượng RuntimeClass phải là một tên DNS subdomain hợp lệ.

Lưu ý:

Bạn nên giới hạn các thao tác ghi đối với RuntimeClass (create/update/patch/delete) chỉ cho quản trị viên cluster. Thông thường đây là thiết lập mặc định. Xem Tổng quan về phân quyền để biết thêm chi tiết.

Cách sử dụng

Sau khi các RuntimeClass đã được cấu hình cho cluster, bạn có thể chỉ định runtimeClassName trong đặc tả của Pod để sử dụng. Ví dụ:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: myclass
  # ...

Điều này sẽ yêu cầu kubelet dùng RuntimeClass được chỉ định để chạy pod này. Nếu RuntimeClass được chỉ định không tồn tại, hoặc CRI không thể chạy handler tương ứng, pod sẽ chuyển sang pha (phase) kết thúc Failed. Hãy tìm sự kiện (event) tương ứng để xem thông báo lỗi.

Nếu không chỉ định runtimeClassName, RuntimeHandler mặc định sẽ được sử dụng, tương đương với hành vi khi tính năng RuntimeClass bị tắt.

Cấu hình CRI

Để biết thêm chi tiết về cách thiết lập các CRI runtime, xem Cài đặt CRI.

containerd

Các runtime handler được cấu hình thông qua file cấu hình của containerd tại /etc/containerd/config.toml. Các handler hợp lệ được cấu hình trong phần runtimes:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]

Xem tài liệu cấu hình của containerd để biết thêm chi tiết:

CRI-O

Các runtime handler được cấu hình thông qua file cấu hình của CRI-O tại /etc/crio/crio.conf. Các handler hợp lệ được cấu hình trong bảng crio.runtime:

[crio.runtime.runtimes.${HANDLER_NAME}]
  runtime_path = "${PATH_TO_BINARY}"

Xem tài liệu cấu hình của CRI-O để biết thêm chi tiết.

Lập lịch

TRẠNG THÁI TÍNH NĂNG: Beta since Kubernetes v1.16

Bằng cách chỉ định trường scheduling cho một RuntimeClass, bạn có thể đặt các ràng buộc để đảm bảo rằng các Pod chạy với RuntimeClass này được lập lịch lên những node hỗ trợ nó. Nếu không đặt scheduling, Kubernetes giả định rằng tất cả các node đều hỗ trợ RuntimeClass này.

Để đảm bảo các pod được đặt lên những node hỗ trợ một RuntimeClass cụ thể, nhóm node đó cần có một label chung để trường runtimeclass.scheduling.nodeSelector chọn ra. nodeSelector của RuntimeClass được hợp nhất với nodeSelector của pod trong bước admission, tức là lấy phần giao giữa các tập node mà mỗi bên chọn. Nếu có xung đột, pod sẽ bị từ chối.

Nếu các node được hỗ trợ đã bị gắn taint để ngăn pod của RuntimeClass khác chạy trên node đó, bạn có thể thêm tolerations vào RuntimeClass. Tương tự như nodeSelector, các toleration được hợp nhất với toleration của pod trong bước admission, tức là lấy phần hợp giữa các tập node mà mỗi bên chấp nhận (tolerate).

Để tìm hiểu thêm về cách cấu hình node selector và toleration, xem Gán Pod cho Node.

Chi phí phụ trội của Pod (Pod Overhead)

TRẠNG THÁI TÍNH NĂNG: GA since Kubernetes v1.24

Bạn có thể chỉ định các tài nguyên overhead gắn với việc chạy một Pod. Việc khai báo overhead cho phép cluster (bao gồm cả scheduler) tính đến phần này khi đưa ra quyết định về Pod và tài nguyên.

Pod overhead được định nghĩa trong RuntimeClass thông qua trường overhead. Bằng cách sử dụng trường này, bạn có thể chỉ định overhead khi chạy các pod sử dụng RuntimeClass này và đảm bảo các overhead này được Kubernetes tính đến.

Tiếp theo là gì

5 - Container Runtime Interface (CRI)

CRI là một giao diện plugin cho phép kubelet sử dụng nhiều loại container runtime khác nhau mà không cần biên dịch lại các thành phần của cluster.

Bạn cần có một container runtime hoạt động được trên mỗi Node trong cluster, để kubelet có thể khởi chạy các Pod cùng các container của chúng.

Container Runtime Interface (CRI) là giao thức chính cho việc giao tiếp giữa kubelet và Container Runtime.

Container Runtime Interface (CRI) của Kubernetes định nghĩa giao thức gRPC chính cho việc giao tiếp giữa các thành phần node là kubelet và container runtime.

API

TRẠNG THÁI TÍNH NĂNG: GA since Kubernetes v1.23

Kubelet đóng vai trò client khi kết nối tới container runtime thông qua gRPC. Các endpoint của runtime service và image service phải có sẵn trong container runtime; bạn có thể cấu hình riêng các endpoint này trong kubelet bằng cờ dòng lệnh --container-runtime-endpoint.

Với Kubernetes v1.26 trở lên, kubelet yêu cầu container runtime phải hỗ trợ CRI API v1. Nếu một container runtime không hỗ trợ API v1, kubelet sẽ không đăng ký node.

Nâng cấp

Khi nâng cấp phiên bản Kubernetes trên một node, kubelet sẽ khởi động lại. Nếu container runtime không hỗ trợ CRI API v1, kubelet sẽ không thể đăng ký và sẽ báo lỗi. Nếu cần kết nối lại (re-dial) gRPC vì container runtime đã được nâng cấp, runtime phải hỗ trợ CRI API v1 thì kết nối mới thành công. Có thể bạn sẽ cần khởi động lại kubelet sau khi container runtime đã được cấu hình đúng.

Truyền danh sách theo luồng (list streaming)

TRẠNG THÁI TÍNH NĂNG: Alpha since Kubernetes v1.36; disabled by default
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CRIListStreaming feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Các RPC liệt kê tiêu chuẩn của CRI (ListContainers, ListPodSandbox, ListImages) trả về toàn bộ kết quả trong một phản hồi unary duy nhất. Trên các node có số lượng container lớn (ví dụ, nhiều hơn khoảng 10,000 container, tính cả container đang chạy lẫn đã dừng), các phản hồi này có thể vượt quá giới hạn kích thước thông điệp mặc định 16 MiB của gRPC, khiến kubelet gặp lỗi khi đối chiếu (reconcile) trạng thái với container runtime.

Khi bật feature gate CRIListStreaming, kubelet sử dụng các RPC streaming phía server (chẳng hạn StreamContainers, StreamPodSandboxes, StreamImages), cho phép container runtime chia kết quả ra nhiều thông điệp phản hồi, nhờ đó vượt qua giới hạn kích thước của mỗi thông điệp. Điều này đặc biệt hữu ích cho:

  • Các môi trường mà container được tạo và hủy liên tục (các hệ thống CI/CD)
  • Các workload xử lý theo lô (batch) quy mô lớn

Nếu container runtime không hỗ trợ các RPC streaming, kubelet sẽ tự động quay về dùng các RPC unary tiêu chuẩn để đảm bảo tương thích ngược.

Tiếp theo là gì