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
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/imagesmy-registry.example/images/my-imagemy-registry.example/images/another-imagesub.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-imagea.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ư.
Đả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.
- 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.
- 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.
- 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.
- 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ì
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
- Cấu hình bản triển khai CRI trên các node (tùy thuộc vào runtime)
- Tạo các tài nguyên RuntimeClass tương ứng
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.
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:
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ì