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

Return to the regular view of this page.

Tài liệu

1 - Tài liệu Kubernetes

1.1 - Các phiên bản được hỗ trợ của tài liệu Kubernetes

Trang web này lưu tài liệu của phiên bản hiện tại và bốn phiên bản trước của Kubernetes.

2 - Bắt đầu với Kubernetes

Ở mục này chúng ta sẽ liệt kê ra những cách khác nhau để cài đặt và sử dụng Kubernetes. Khi cài đặt Kubernetes, bạn hãy lựa chọn cách thức dựa trên theo những yếu tố như: dễ dàng bảo trì, tính bảo mật, mức độ kiểm soát, tài nguyên sẵn có, cũng như trình độ chuyên môn cần thiết để vận hành và quản lý cluster.

Để triển khai (deploy) Kubernetes cluster ở máy local, trên dịch vụ điện toán đám mây (cloud) hay ở trung tâm dữ liệu của riêng bạn, hãy tải Kubernetes xuống ở đây.

Một số components của Kubernetes như kube-apiserver hoặc kube-proxy có thể được triển khai dưới dạng container images ở trong cluster.

Chúng tôi khuyến khích bạn thực thi components dưới dạng những container images, Kubernetes sẽ quản lý những components đó. Lưu ý, không bao gồm những components có sử dụng container (đặc biệt là kubelet).

Trong trường hợp bạn không muốn tự quản lý Kubernetes cluster, bạn có thể chọn một service quản lý, bao gồm certified platforms. Ngoài ra còn có các giải pháp tiêu chuẩn và tùy chỉnh khác trên nhiều môi trường điện toán đám mây (cloud), hay môi trường một máy chủ (bare metal environment) khác nhau.

Môi trường học tập

Nếu bạn đang ở trong giai đoạn học Kubernetes, bạn có thể sử dụng những công cụ (tools) được hỗ trợ bởi cộng đồng Kubernetes, hoặc những công cụ trong hệ sinh thái để cài đặt Kubernetes cluster trên máy của bạn. Xem thêm.

Môi trường production

Khi đánh giá một giải pháp dành cho môi trường production, bạn cần xem xét những khía cạnh về việc vận hành Kubernetes cluster (hoặc khái niệm trừu trượng của nó) mà bạn muốn tự quản lý, hoặc những phần nào bạn muốn để cho nhà cung cấp quản lý.

Với cluster bạn tự quản lý, công cụ hỗ trợ chính thức để triển khai (deploy) Kubernetes là kubeadm.

Tiếp theo là gì

2.1 - Môi trường học tập

2.2 - Môi trường Production

Tạo một cụm Kubernetes chất lượng production

Một cụm Kubernetes chất lượng production yêu cầu có sự lên kế hoạch và chuẩn bị. Nếu cụm Kubernetes của bạn dùng để chạy các workload quan trọng, nó phải được cấu hình để có khả năng phục hồi. Trang này giải thích các bước bạn có thể thực hiện để thiết lập một cụm sẵn sàng cho production, hoặc để thúc đẩy một cụm hiện có cho việc sử dụng production. Nếu bạn đã quen thuộc với thiết lập production và muốn những liên kết, hãy bỏ qua đến Tiếp theo là gì.

Những cân nhắc production

Thông thường, một môi trường cụm Kubernetes production có nhiều yêu cầu hơn một môi trường Kubernetes cho học tập, phát triển hoặc thử nghiệm cá nhân. Một môi trường production có thể yêu cầu truy cập an toàn bởi nhiều người dùng, tính khả dụng nhất quán, và các nguồn lực để thích ứng với nhu cầu thay đổi.

Khi bạn quyết định nơi bạn muốn triển khai môi trường Kubernetes production (on-premise hoặc trên cloud) và lượng công việc quản lý bạn muốn đảm nhận hoặc trao cho người khác, hãy xem xét các yêu cầu của bạn đối với cụm Kubernetes bị ảnh hưởng như thế nào bởi các vấn đề sau:

  • Tính sẵn sàng: Một môi trường học tập Kubernetes trên một máy có một điểm lỗi duy nhất. Tạo một cụm có tính sẵn sàng cao có nghĩa là phải cân nhắc:

    • Tách control plane khỏi các worker node.
    • Nhân bản các thành phần control plane trên nhiều node.
    • Cân bằng tải lưu lượng tới API server của cụm.
    • Có đủ các worker node sẵn sàng, hoặc có khả năng trở nên khả dụng một cách nhanh chóng khi workload thay đổi.
  • Quy mô: Nếu bạn mong muốn môi trường Kubernetes production của mình đáp ứng được một lượng yêu cầu ổn định, bạn có thể thiết lập khả năng đáp ứng bạn cần và hoàn thành. Tuy nhiên, nếu bạn mong muốn đáp ứng nhu cầu tăng theo thời gian hoặc thay đổi đáng kể dựa trên những yếu tố như mùa hoặc sự kiện đặc biệt, bạn cần lập kế hoạch về việc mở rộng quy mô để giảm bớt áp lực tăng lên từ nhiều yêu cầu hơn đối với control plane và các worker node hoặc thu hẹp quy mô để tối ưu tài nguyên không sử dụng.

  • Quản lý bảo mật và truy cập: Bạn có đầy đủ các đặc quyền admin trên cụm Kubernetes học tập của mình. Nhưng các cụm chia sẻ với nhiều workload quan trọng, và nhiều hơn một hoặc hai người dùng, yêu cầu một cách tiếp cận tinh tế hơn đối với những ai và những gì có thể truy cập vào các tài nguyên cụm. Bạn có thể sử dụng kiểm soát truy cập dựa trên vai trò (RBAC) và các kỹ thuật bảo mật khác để chắc chắn rằng người dùng và workloads có thể truy cập được tới tài nguyên họ cần trong khi vẫn đảm bảo bảo mật cho worload và cụm máy chủ. Bạn có thể đặt giới hạn lên tài nguyên mà người dùng và workload có thể truy cập bằng cách quản lý các chính sách và tài nguyên container.

Trước khi dựng một môi trường Kubernetes production, cân nhắc chuyển giao một phần hoặc toàn bộ công việc này cho các nhà cung cấp giải pháp Cloud Turnkey Cloud Solutions hoặc các đối tác Kubernetes Partners. Các tùy chọn gồm:

  • Serverless: Chỉ cần chạy workload trên thiết bị của bên thứ ba mà không cần quản lý toàn bộ cụm. Bạn sẽ bị tính phí cho những thứ như mức sử dụng CPU, bộ nhớ, và các yêu cầu ổ đĩa.
  • Control plane được quản lý: Hãy để nhà cung cấp quản lý quy mô và tính sẵn sàng của control plane trong cụm, cũng như xử lý các bản vá và cập nhật.
  • Worker node được quản lý: Cấu hình nhóm các node để đáp ứng nhu cầu của bạn, sau đó nhà cung cấp sẽ đảm bảo rằng những node đó khả dụng và sẵn sàng để thực hiện các cập nhật khi cần thiết.
  • Sự tích hợp: Có những nhà cung cấp tích hợp Kubernetes với các dịch vụ khác mà bạn có thể cần, ví dụ kho lưu trữ, container registries, các phương thức xác thực, và những công cụ phát triển.

Liệu bạn tự dựng một cụm Kubernetes production hay làm điều đó với các đối tác, xem những phần dưới đây để đánh giá nhu cầu liên quan tới control plane, các worker node, truy cập người dùng, và các tài nguyên workload cho cụm của bạn.

Thiết lập cụm production

Trong một cụm Kubernetes có chất lượng production, control plane quản lý cụm từ các dịch vụ có thể được trải đều trên nhiều máy tính theo những cách khác nhau. Tuy nhiên, mỗi worker node đại diện cho một thực thể duy nhất được cấu hình để chạy Kubernetes pod.

Control plane trên production

Cụm Kubernetes đơn giản nhất có toàn bộ dịch vụ control plane và worker node chạy trên cùng một máy. Bạn có thể phát triển môi trường đó bằng cách thêm các worker node, như được phản ánh trong sơ đồ được minh họa trong Các thành phần Kubernetes. Nếu cụm có nghĩa là có sẵn trong một khoảng thời gian ngắn hoặc có thể bị loại bỏ nếu có sự cố nghiêm trọng, điều này có thể đáp ứng nhu cầu của bạn.

Tuy nhiên, nếu bạn cần một cụm vĩnh viễn, có mức độ sẵn cao hơn, bạn nên xem xét các cách mở rộng control plane. Theo thiết kế, dịch vụ control plane chạy trên một máy tính đơn là không có tính sẵn sàng cao. Nếu việc giữ cụm được dựng lên và chạy và đảm bảo rằng nó có thể được sửa chữa nếu có sự cố xảy ra là điều quan trọng, Xem xét các bước sau:

  • Chọn các công cụ triển khai: Bạn có thể triển khai một control plane bằng các công cụ vi dụ như kubeadm, kops, và kubespray. Xem Cài đặt Kubernetes với những công cụ triển khai để tìm hiểu các mẹo triển khai chất lượng production bằng cách sử dụng từng phương pháp triển khai đó. Những Container Runtimes khác cũng có sẵn để bạn sử dụng cho việc triển khai của mình.
  • Quản lý chứng chỉ: Giao tiếp bảo mật giữa các dịch vụ control plane được thực hiện bằng chứng chỉ. Chứng chỉ được tự động tạo trong quá trình triển khai hoặc bạn có thể tạo chúng bằng cách sử dụng cơ quan cấp chứng chỉ của riêng bạn. Xem Chứng chỉ PKI và yêu cầu để biết thêm chi tiết.
  • Cấu hình bộ cân bằng tải cho apiserver: Cấu hình bộ cân bằng tải để phân phối các request API bên ngoài tới các instance của dịch vụ apiserver chạy trên các node khác nhau. Xem Tạo Bộ Cân bằng tải bên ngoài để biết thêm chi tiết.
  • Phân tách và sao lưu dịch vụ etcd: Các dịch vụ etcd có thể chạy trên cùng các máy với các dịch vụ control plane khác hoặc chạy trên các máy tách biệt, để tăng tính bảo mật và khả dụng. Bởi vì etcd lưu dữ liệu cấu hình của cụm, sao lưu cơ sở dữ liệu etcd nên được thực hiện thường xuyên để đảm bảo rằng bạn có thể sửa chữa cơ sở dữ liệu đó nếu cần. Xem thêm etcd FAQ để biết thêm chi tiết về việc cấu hình và sử dụng etcd. Xem Vận hành các cụm etcd cho Kubernetes và Thiết lập một cụm etcd có tính Sẵn sàng cao với kubeadm để biết thêm chi tiết.
  • Tạo nhiều hệ thống control plane: Để có tính sẵn sàng cao, control plane không nên giới hạn trong một máy. Nếu các dịch vụ control plane được chạy bởi một dịch vụ khởi tạo (ví dụ systemd), các dịch vụ nên chạy trên ít nhất ba máy. Tuy nhiên, chạy các dịch vụ control plane dạng pods trong Kubernetes đảm bảo rằng số lượng bản sao dịch vụ mà bạn yêu cầu sẽ luôn có sẵn. Scheduler phải có khả năng chịu lỗi, nhưng không sẵn sàng cao. Một số công cụ triển khai được thiết lập thuật toán đồng thuận Raft để bầu cử leader cho các dịch vụ Kubernetes. Nếu nếu leader biến mất, một dịch vụ khác tự bầu cử chính nó và tiếp quản.
  • Trải rộng nhiều zone: Nếu việc duy trì cụm khả dụng mọi lúc là quan trọng, cân nhắc việc tạo một cụm chạy trên nhiều trung tâm dữ liệu, được gọi là zone trên các môi trường đám mây. Nhóm các zone gọi là region. Bằng cách trải rộng một cụm trên nhiều zone trong cùng một region, nó có thể làm tăng cơ hội cho cụm của bạn được tiếp tục hoạt động ngay cả khi một zone trở nên không khả dụng. Xem Chạy trong nhiều zone để biết thêm chi tiết.
  • Quản lý các tính năng on-going: Nếu bạn có kế hoạch giữ cụm theo thời gian, có những nhiệm vụ bạn cần làm để duy trì sức khỏe và bảo mật của cụm. Ví dụ, nếu bạn đã cài đặt với kubeadm, có các hướng dẫn để giúp bạn Quản lý Chứng chỉ và Nâng cấp các cụm kubeadm. Xem Quản lý một cụm để biết thêm danh sách các tác vụ quản trị của Kubernetes.

Để tìm hiểu về các tùy chọn có sẵn khi bạn chạy các dịch vụ control plane, xem các trang kube-apiserver, kube-controller-manager, và kube-scheduler. Đối với các ví dụ về control plane có tính sẵn sàng cao, xem Các tùy chọn cho kiến trúc có tính Sẵn sàng cao, Tạo các cụm có tính Sẵn sàng cao với kubeadm, và Vận hành cụm etcd cho Kubernetes. Xem Sao lưu cụm etcd để biến cách tạo kế hoạch sao lưu cho etcd.

Worker node trên production

Workload chất lượng production cần phải có tính đàn hồi và bất kỳ thành phần nào mà chúng phụ thuộc vào cũng phải có tính đàn hồi (ví dụ CoreDNS). Cho dù bạn tự quản lý control plane hay có một nhà cung cấp cloud làm điều đó cho bạn, bạn vẫn cần phải xem xét cách bạn muốn quản lý các worker node (còn gọi một cách đơn giản là node).

  • Cấu hình các node: Các node có thể là máy vật lý hay máy ảo. Nếu bạn muốn tạo và quản lý node của riêng bạn, bạn có thể cài đặt một hệ điều hành được hỗ trợ, sau đó thêm và chạy các dịch vụ Node thích hợp. Xem xét:
    • Nhu cầu của workload khi bạn thiết lập các node bằng cách có sẵn bộ nhớ, CPU và tốc độ đĩa và dung lượng lưu trữ phù hợp.
    • Liệu các hệ thống máy tính chung sẽ làm hay bạn có workload cần bộ xử lý GPU, node Windows hoặc VM cô lập.
  • Xác nhận các node: Xem Thiết lập node hợp lệ để biết thông tin về cách đảm bảo một node đáp ứng các yêu cầu để tham gia cụm Kubernetes.
  • Thêm các node vào cụm: Nếu bạn đang quản lý cụm của riêng mình, bạn có thể thêm các node bằng cách thiết lập các máy của riêng bạn và thêm chúng theo cách thủ công hoặc để chúng tự đăng ký với apiserver của cụm. Xem phần Nodes để biết thông tin về cách thiết lập Kubernetes để thêm các nút theo những cách này.
  • Quy mô các node: Sau cùng bạn sẽ cần có một kế hoạch để mở rộng khả năng của cụm. Xem Các cân nhắc cho những cụm lớn để giúp xác định bạn cần bao nhiêu node, dựa trên số lượng pod và container bạn cần chạy. Nếu bạn đang tự quản lý các node, điều này có thể có nghĩa là mua và cài đặt thiết bị vật lý của riêng bạn.
  • Autoscale các node: Đọc Node Autoscaling để tìm hiểu về các công cụ có sẵn để tự động quản lý các node của bạn và khả năng chúng cung cấp.
  • Thiết lập kiểm tra sức khỏe node: Đối với những workload quan trọng, bạn muốn đảm bảo rằng các node và các pod chạy trên các node đó là khỏe mạnh. Sử dụng Trình phát hiện vấn đề node, bạn có thể đảm bảo các node của bạn khỏe mạnh.

Quản lý người dùng trên production

Trên production, bạn có thể chuyển từ một mô hình nơi bạn hoặc một nhóm nhỏ những người đang truy cập cụm đến nơi có khả năng có hàng tá hoặc hàng trăm người. Trong môi trường học tập hoặc nền tảng nguyên mẫu, bạn có thể có một tài khoản quản trị cho mọi thứ bạn làm. Trên production, bạn sẽ muốn nhiều tài khoản với các cấp độ truy cập khác nhau vào các namespace khác nhau.

Đảm nhận một cụm có chất lượng production nghĩa là quyết định việc bạn muốn làm thế nào để cho phép người dùng khác truy cập một cách chọn lọc. Đặc biệt, bạn cần chọn chiến lược để xác minh danh tính những người đang cố truy cập vào cụm của bạn (xác thực) và quyết định liệu họ có quyền làm những gì họ muốn (phân quyền):

  • Xác thực: Apiserver có thể xác thực người dùng bằng chứng chỉ khác, bearer tokens, một proxy xác thực, hoặc HTTP basic auth. Bạn có thể chọn phương pháp xác thực bạn muốn. Băng việc sử dụng plugin, apiserver có thể tận dụng phương thức xác thực hiện có của tổ chức của bạn, ví dụ LDAP hoặc Kerberos. Xem Xác thực dể biết mô tả về các phương pháp xác thực người dùng Kubernetes khác nhau.
  • Phân quyền: Khi bạn bắt đầu ủy quyền cho người dùng thường xuyên của mình, bạn có lẽ sẽ chọn giữa phân quyền RBAC và ABAC. Xem Tổng quan phân quyền để xem những chế độ phân quyền tài khoản người dùng khác nhau (cũng như quyền truy cập của service account tới cụm của bạn):
    • Kiểm soát truy cập dựa trên vai trò (RBAC): Cho phép bạn chỉ định quyền truy cập vào cụm bằng cách cho phép thiết lập một tập các quyền tới người dùng đã xác thực. Quyền có thể được chỉ định trong một namespace cụ thể (Role) hoặc trong cả cụm (ClusterRole). Sau đó sử dụng RoleBindings và ClusterRoleBindings, những quyền này có thể được gán tới những người dùng cụ thể.
    • Kiểm soát truy cập dựa trên thuộc tính (ABAC): Cho phép bạn tạo các chính sách dựa trên thuộc tính của tài nguyên trong cụm và sẽ cho phép hoặc hoặc từ chối truy cập dựa trên những thuộc tính đó. Mỗi dòng trong 1 file chính sách xác định phiên bản của thuộc tính (apiVersion and kind) và một ánh xạ các thuộc tính đặc trưng để gán tới một chủ thể (người dùng hoặc nhóm), thuộc tính tài nguyên, thuộc tính phi tài nguyên (/versions hoặc /apis), và chỉ đọc. Xem Các ví dụ để biết thêm chi tiết

Với tư cách là người thiết lập xác thực và phân quyền trên cụm Kubernetes production, dưới đây là một số điều cần cân nhắc:

  • Đặt chế độ phân quyền: Khi Kubernetes API server (kube-apiserver) khởi động, chế độ hỗ trợ phân quyền phải được thiết lập bằng cờ --authorization-config file hoặc --authorization-mode. Ví dụ, cờ đó trong kube-adminserver.yaml file (tại /etc/kubernetes/manifests) có thể được đặt là Node,RBAC. Điều này sẽ cho phép phân quyền Node và RBAC tới những yêu cầu đã xác thực.
  • Tạo chứng chỉ người dùng và role bindings (RBAC): Nếu bạn sử dụng phân quyền RBAC, người dùng có thể tạo một CertificateSigningRequest (CSR) và sẽ được ký bởi CA của cụm. Sau đó bạn có thể gán Roles và ClusterRoles tới từng người dùng. Xem Certificate Signing Requests để biết thêm chi tiết.
  • Tạo các chính sách kết hợp các thuộc tính (ABAC): Nếu bạn sử dụng phân quyền ABAC, bạn có thể gán sự kết hợp các thuộc tính thành các chính sách để phân quyền tới người dùng hoặc nhóm được chọn để họ có thể truy cập tới những tài nguyên cụ thể (ví dụ pod), namespace, hoặc apiGroup. Để biết thêm thông tin, xem Các ví dụ.
  • Cân nhắc Admission Controllers: Các hình thức phân quyền bổ sung cho các yêu cầu đến thông qua API server bao gồm Webhook Token Authentication. Webhooks và những loại phân quyền đặc biệt khác cần được kích hoạt bằng cách thêm Admission Controllers vào API server.

Đặt giới hạn tài nguyên cho workload

Những yêu cầu từ production workload có thể gây ra áp lực lên cả trong và ngoài Kubernetes control plane. Hãy cân nhắc những mục này khi thiết lập cho nhu cầu của workload trong cụm của bạn:

  • Đặt giới hạn namespace: Đặt từng namespace quotas lên những thứ như bộ nhớ và CPU. Xem Quản lý Bộ nhớ, CPU, và API Resources để biết thêm chi tiết.
  • Chuẩn bị cho yêu cầu DNS: Nếu bạn mong đợi workloads mở rộng một cách ồ ạt, dịch vụ DNS của bạn phải săn sàng để mở rộng quy mô. Xem Autoscale dịch vụ DNS trong cụm.
  • Tạo thêm các service account: Tài khoản người dùng (user account) xác định những gì người dùng có thể thực hiện trên một cụm, trong khi đó một tài khoản dịch vụ (service account) định nghĩa khả năng truy cập của pod trong một namespace cụ thể. Mặc định, một pod sẽ tiếp nhận service account default từ namespace của nó. Xem Quản lý Service Account để biết cách tạo một service account. Ví dụ, bạn có thể muốn:

Tiếp theo là gì

2.2.1 - Các Container Runtime

Lưu ý: Dockershim đã được loại bỏ khỏi dự án Kubernetes kể từ phiên bản 1.24. Đọc Dockershim Removal FAQ để biết thêm chi tiết.

Bạn cần cài đặt một container runtime vào mỗi node trong cluster để chạy Pod trên đó. Trang này mô tả những gì liên quan và các bước liên quan để thiết lập node.

Kubernetes 1.37 yêu cầu bạn sử dụng một runtime nào đó đáp ứng với Container Runtime Interface (CRI).

Xêm Các CRI phiên bản để biết thêm thông tin.

Trang này mô tả một cách sử dụng container runtime phổ biến với Kubernetes.

Lưu ý:

Kubernetes trước v1.24 tích hợp trực tiếp với Docker Engine bằng một thành phần gọi là dockershim. Tích hợp đó không còn là một phần của Kubernetes nữa (Xúa này được thông báo ở v1.20 release). Xem Kiểm tra xem xúa của Dockershim có ảnh hưởng đến bạn không.

Nếu bạn đang chạy một phiên bản Kubernetes khác với v1.37, hãy xem tài liệu của phiên bản đó.

Điều kiện tiên quyết của Cài đặt và cấu hình

Cấu hình mạng lưới

Trông khi tình hình mặc định, Linux kernel không cho phép các gói mạng IPv4 được chuyển đi giữa các giao diện. Hầu hết các tính năng mạng Kubernetes sẽ thay đổi cài đặt này (nếu cần thiết), nhưng một số có thể mong đợi rằng người quản trị sẽ làm cho nó. (Một số có thể cũng mong đợi các tham số sysctl khác được thiết lập, các module kernel được tải, v.v; hãy xem tài liệu cho từng tính năng mạng cụ thể của bạn.)

Bật chuyển tiếp gói mạng IPv4

Để bật chuyển tiếp gói mạng IPv4:

# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

Kiểm tra rằng net.ipv4.ip_forward đã được thiết lập thành 1 bằng cách:

sysctl net.ipv4.ip_forward

cgroup drivers

Linux sử dụng các control groups để giới hạn các tài nguyên được cấp phát cho các quy trình.

Cả kubelet và container runtime xuống nó cần giao tiếp với control groups để áp dụng quản lý tài nguyên cho pods và containers và thiết lập tài nguyên như cpu/memory requests và limits. Để giao tiếp với control groups, kubelet và container runtime cần sử dụng một cgroup drivers. Điều quan trọng là kubelet và container runtime phải sử dụng cùng một cgroup driver và cấu hình.

Tổng cộng có hai cgroup drivers có sẵn:

cgroupfs driver

cgroupfs driver là cgroup driver mặc định trong kubelet. Khi sử dụng cgroupfs driver, kubelet và container runtime giao tiếp trực tiếp với cgroup filesystem để cấu hình cgroups.

Khi systemd là hệ thống khởi tạo, cgroupfs driver không được khuyến nghị vì systemd mong đợi một cgroup manager duy nhất trên hệ thống. Bổ sung nữa, nếu bạn sử dụng cgroup v2, hãy sử dụng systemd cgroup driver thay vì cgroupfs.

systemd cgroup driver

Khi systemd được chọn làm hệ thống khởi tạo cho một phân phối Linux, quy trình khởi tạo sẽ tạo và tiêu thụ một control group gốc (cgroup) và trở thành cgroup manager.

Sự tích hợp của systemd và cgroups rất chặt chẽ. Mỗi cái systemd unit sẽ được cấp cho một cgroup. Vì vậy, nếu bạn sử dụng systemd làm hệ thống khởi tạo với cgroupfs driver, hệ thống sẽ có hai cgroup managers khác nhau.

Hai cgroup managers sẽ dẫn đến hai cái nhìn khác nhau về các tài nguyên có sẵn và đang được sử dụng trong hệ thống. Trong một số trường hợp, các node được cấu hình sử dụng cgroupfs cho kubelet và container runtime, nhưng sử dụng systemd cho các quy trình còn lại sẽ trở nên không ổn định trong trường hợp nặng tài nguyên.

Cách để giảm thiểu tình hình không ổn định là sử dụng systemd làm cgroup driver cho kubelet và container runtime khi systemd được chọn làm hệ thống khởi tạo.

Để thiết lập systemd làm cgroup driver, chỉnh sửa cấu hình KubeletConfiguration của cgroupDriver và đặt nó thành systemd. Ví dụ:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
...
cgroupDriver: systemd

Lưu ý:

Từ v1.22 trở đi, khi tạo một cluster với kubeadm, nếu bạn không thiết lập cgroupDriver trong KubeletConfiguration, kubeadm sẽ mặc định nó thành systemd.

Nếu bạn cấu hình systemd làm cgroup driver cho kubelet, bạn cũng phải cấu hình systemd làm cgroup driver cho container runtime. Hãy xem tài liệu của container runtime để biết hướng dẫn. Ví dụ:

Kubernetes được bật KubeletCgroupDriverFromCRI feature gate và một container runtime dùng được RuntimeConfig CRI RPC, kubelet sẽ tự động phát hiện được cgroup driver phù hợp từ runtime, và bỏ qua cài đặt cgroupDriver trong kubelet cấu hình.

Tuy nhiên, các phiên bản cũ hơn của container runtimes (đạc biệt là containerd 1.y và dưới) không dùng dược RuntimeConfig CRI RPC, và có thể không phản hồi chính xác đến yêu cầu này. Do đó kubelet sẽ sử dụng tham số --cgroup-driver của riêng nó.

Trong Kubernetes 1.36, hành vi này sẽ bị loại bỏ, và các containerd phiên bản cũ sẽ bị lỗi với các kubelet mới hơn.

Chú ý:

Thay đổi cgroup driver của một Node đã tham gia một cluster là một hoạt động quan trọng. Nếu kubelet đã tạo các Pod bằng cách sử dụng các khái niệm của một cgroup driver, thay đổi container runtime sang một cgroup driver khác có thể dẫn đến lỗi khi cố gắng tạo lại sandbox của Pod cho các Pod đó. Khởi động lại kubelet không giải quyết được các lỗi này.

Nếu bạn có một hệ thống tự động, thay thế node bằng một node mới bằng cấu hình đã cập nhật, hoặc cài đặt lại node bằng cách sử dụng hệ thống tự động.

Chuyển sang cgroup driver systemd trong các cluster được quản lý bởi kubeadm

Nếu bạn muốn chuyển sang cgroup driver systemd trong các cluster được quản lý bởi kubeadm, hãy theo cấu hình một cgroup driver.

Các CRI phiên bản #{cri-versions}

Container runtime của bạn phải tương thích với ít nhất v1alpha2 của container runtime interface.

Kubernetes bắt đầu từ v1.26 chỉ tác dụng với CRI API phiên bản v1. Nhưng nếu một container runtime không tác dụng với CRI API phiên bản v1, kubelet sẽ sử dụng (đã bị loại bỏ) CRI API phiên bản v1alpha2 thay vì đó.

Container runtimes

Lưu ý: Phần này liên kết đến các dự án bên thứ ba cung cấp chức năng được yêu cầu bởi Kubernetes. Tác giả dự án Kubernetes không chịu trách nhiệm về những dự án này, được liệt kê theo thứ tự chữ cái. Để thêm một dự án vào danh sách này, đọc hướng dẫn nội dung trước khi gửi thay đổi. Thêm thông tin.

containerd

Phần này mô tả các bước cần thiết để sử dụng containerd làm CRI runtime.

Để cài đặt containerd trên hệ thống của bạn, hãy theo các hướng dẫn trên bắt đầu với containerd. Trở lại bước này khi bạn đã tạo một file cấu hình config.toml hợp lệ.

Tìm được file này ở đường dẫn /etc/containerd/config.toml.

Tìm được file này ở đường dẫn C:\Program Files\containerd\config.toml.

Trên Linux, CRI socket mặc định của containerd là /run/containerd/containerd.sock. Trên Windows, CRI endpoint mặc định là npipe://./pipe/containerd-containerd.

Configuring the systemd cgroup driver

Để sử dụng systemd cgroup driver trong /etc/containerd/config.toml với runc, thiết lập cấu hình do phiên bản của bạn.

Containerd phiên bản 1.x:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true

Containerd phiên bản 2.x:

[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
  ...
  [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
    SystemdCgroup = true

systemd cgroup driver là khuyến nghị nếu bạn sử dụng cgroup v2

Lưu ý:

Nếu bạn cài đặt containerd tử một package (ví sự, RPM hoạc .deb), bạn có thể phát hiện rằng plugin CRI tích hợp đã bị tắt mặc định.

Bạn cần phải có hỗ trợ CRI để sử dụng containerd với Kubernetes. Hãy đảm bảo rằng cri không nằm trong danh sách disabled_plugins trong /etc/containerd/config.toml; nếu bạn đã thay đổi file này, hãy khởi động lại containerd.

Nếu bạn gặp container lặp tuần hoàn sau cài đặt cluster ban đầu hoặc sau khi cài đặt CNI, hãy cân nhắc việc thiết lập lại cấu hình containerdcontainerd config default > /etc/containerd/config.toml as specified in getting-started.md

Nếu bạn áp dụng thay đổi này, hãy đảm bảo khởi động lại containerd:

sudo systemctl restart containerd

Khi sử dụng kubeadm, xin cấu hình cgroup driver for kubelet.

Trong Kubernetes v1.28, bạn có thể bật tính năng alpha tự động phát hiện cgroup driver như một tính năng. Xem thêm chi tiết tại systemd cgroup driver.

Thay đổi image sandbox (pause)

Trong containerd config, bạn có thể thay đổi image sandbox bằng cách thiết lập cấu hình sau:

[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.10"

Bạn có thể cần khởi động lại containerd khi bạn đã cập nhật file config: systemctl restart containerd.

CRI-O

Phần này bao gồm các bước cần thiết để cài đặt CRI-O làm container runtime.

Để cài đặt CRI-O, hãy theo CRI-O Install Instructions.

cgroup driver

CRI-O sử dụng systemd cgroup driver mặc định, điều này hầu hết có hiệu quả. Để chuyển sang cgroup driver cgroupfs, chỉnh sửa /etc/crio/crio.conf hoặc đặt một drop-in configuration trong /etc/crio/crio.conf.d/02-cgroup-manager.conf, ví dụ:

[crio.runtime]
conmon_cgroup = "pod"
cgroup_manager = "cgroupfs"

Lưu ý cấu hình conmon_cgroup phải được thiết lập thành pod. Điều này thường cần thiết để đảm bảo cgroup driver của kubelet (thường được thực hiện bằng kubeadm) và CRI-O được đồng bộ.

Trong Kubernetes v1.28, bạn có thể bật tính năng alpha tự động phát hiện cgroup driver như một tính năng. Xem thêm chi tiết tại systemd cgroup driver.

CRI socket của CRI-O mặc định là /var/run/crio/crio.sock.

Thay đổi image sandbox (pause)

Bạn có thể thiết lập cấu hình sau trong CRI-O config

[crio.image]
pause_image="registry.k8s.io/pause:3.10"

Thay đổi của cấu hình này hỗ trợ tải lại cấu hình tự đọng bằng systemctl reload crio hoạc gửi SIGHUP đến quá trình crio.

Docker Engine

Lưu ý:

Hướng dẫn này giả định rằng bạn sử dụng cri-dockerd adapter để tích hợp Docker Engine với Kubernetes.
  1. Cài đặt Docker trong mỗi node, theo hướng dẫn tại Install Docker Engine.

  2. Cài đặt cri-dockerd, theo hướng dẫn trong phần cài đặt của tài liệu.

CRI socket của cri-dockerd mặc định là /run/cri-dockerd.sock.

Mirantis Container Runtime

Mirantis Container Runtime (MCR) là một container runtime trên thị trường, trước đây được biết đến là Docker Enterprise Edition.

Bạn có thể sử dụng Mirantis Container Runtime với Kubernetes bằng cấu hình nguồn mở cri-dockerd, được bao gồm trong MCR.

Để biết thêm thông tin về cách cài đặt Mirantis Container Runtime, hãy xem MCR Deployment Guide.

Kiểm tra systemd unit tên là cri-docker.socket để tìm ra đường dẫn đến CRI socket.

Thay đổi image sandbox (pause)

cri-dockerd chấp nhận một tham số --pod-infra-container-image dòng lệnh để xác nhận dụng image nào làm Pod infrastructure container ("pause image").

Tiếp theo là gì

Ngoài một container runtime, cluster của bạn cần một network plugin hoạt động.

2.2.2 - Cài đặt Kubernetes với các công cụ triển khai

Có nhiều phương pháp và công cụ cho việc cài đặt cụm Kubernetes production của bạn. Ví dụ:

  • kubeadm

  • Cluster API: Một dự án con Kubernetes tập trung vào việc cung cấp API và công cụ khai báo để đơn giản hóa việc cung cấp, nâng cấp và vận hành nhiều cụm Kubernetes.

  • kops: Một công cụ cung cấp cụm tự động. Đối với các hướng dẫn, thực hành tốt nhất, tùy chọn cấu hình và thông tin về tiếp cận với cộng đồng, vui lòng kiểm tra kOps website để biết chi tiết.

  • kubespray: Một sự phối hợp của Ansible playbooks, inventory, các công cụ cung cấp, và kiến ​​thức chuyên môn cho các tác vụ quản lý cấu hình Hệ điều hành/cụm Kubernetes chung. Bạn có thể tiếp cận tới cộng đồng trên kênh Slack #kubespray.

2.2.2.1 - Khởi tạo cụm với kubeadm

2.2.2.1.1 - Cài đặt kubeadm

Trang này hướng dẫn cách cài đặt hộp công cụ kubeadm. Để biết thông tin về cách tạo một cụm với Kubeadm sau khi bạn đã thực hiện quy trình cài đặt này, xem trang Tạo một cụm với kubeadm.

Trang installation guide này dành cho Kubernetes v1.37. Nếu bạn muốn sử dụng phiên bản Kubernetes khác, vui lòng tham khảo các trang sau đây thay vì:

Trước khi bạn bắt đầu

  • Một máy chủ Linux tương thích. Dự án Kubernetes cung cấp những hướng dẫn chung cho các bản phân phối Linux dựa trên Debian và Red Hat, và những bản phân phối không có trình quản lý gói.
  • 2 GB RAM hoặc nhiều hơn cho mỗi máy (nếu ít hơn sẽ không đủ tài nguyên cho các ứng dụng của bạn).
  • 2 CPU hoặc nhiều hơn cho các máy control plane.
  • Kết nối toàn mạng giữa tất cả các máy trong cụm (mạng public hoặc private đều được).
  • Mọi máy phải có hostname, địa chỉ MAC, và product_uuid duy nhất. Xem tại đây để biết thêm chi tiết.
  • Một số cổng được mở trên máy của bạn. Xem tại đây để biết thêm chi tiết.

Lưu ý:

Việc cài đặt kubeadm có thể được thực hiện thông qua các tệp nhị phân sử dụng liên kết động và giả sử hệ thống của bạn cung cấp glibc. Giả định này hợp lý trên nhiều bản phân phối Linux (bao gồm Debian, Ubuntu, Fedora, CentOS, v.v...) nhưng không phải luôn đúng đối với các bản phân phối nhẹ và tùy biến bởi mặc định chúng không có sẵn glibc, ví dụ Alpine Linux. Kỳ vọng là bản phân phối hoặc bao gồm glibc hoặc có một lớp tương thích cung cấp các đặc trưng mong muốn.

Kiểm tra phiên bản OS

Lưu ý: Phần này liên kết đến các dự án bên thứ ba cung cấp chức năng được yêu cầu bởi Kubernetes. Tác giả dự án Kubernetes không chịu trách nhiệm về những dự án này, được liệt kê theo thứ tự chữ cái. Để thêm một dự án vào danh sách này, đọc hướng dẫn nội dung trước khi gửi thay đổi. Thêm thông tin.
  • Dự án kubeadm hỗ trợ LTS kernel. Xem Danh sách LTS kernel.
  • Bạn có thể biết được phiên bản kernel bằng câu lệnh uname -r

Để biết thêm thông tin, xem Các yêu cầu về Linux Kernel.

  • Dự án kubeadm hỗ trợ các phiên bản kernel hiện tại. Xem danh sách kernel hiện tại Thông tin phát hành Windows Server.
  • Bạn có thể biết được phiên bản kernel (hay gọi là phiên bản OS) bằng câu lệnh systeminfo

Để biết thêm thông tin, xem Sự tương thích của các phiên bản Windows OS.

Một cụm Kubernetes được tạo bởi kubeadm phụ thuộc vào phần mềm mà chúng sử dụng các chức năng kernel. Phần mềm này bao gồm, nhưng không giới hạn ở container runtime, kubelet, và một plugin Container Network Interface.

Để giúp bạn tránh những lỗi không mong muốn khi sử dụng một phiên bản kernel không được hỗ trợ, kubeadm chạy kiểm tra pre-flight SystemVerification. Quá trình kiểm tra này sẽ lỗi nếu phiên bản kernel không được hỗ trợ.

Bạn có thể chọn bỏ qua kiểm tra, nếu bạn biết rằng kernel của bạn cung cấp các chức năng cần thiết, kể cả kubeadm không hỗ trợ phiên bản đó.

Xác nhận địa chỉ MAC và product_uuid là duy nhất cho từng node

  • Bạn có thể biết được địa chỉ MAC của network interfaces bằng câu lệnh ip link hoặc ifconfig -a
  • product_uuid có thể kiểm tra bằng câu lệnh sudo cat /sys/class/dmi/id/product_uuid

Rất có thể các thiết bị phần cứng sẽ có các địa chỉ duy nhất, mặc dù một vài máy ảo có thể có các giá trị giống hệt nhau. Kubernetes sử dụng những giá trị đó để định danh duy nhất cho các node trong cụm. Nếu các giá trị đó không là duy nhất cho từng node, quá trình cái đặt có thể thất bại.

Kiểm tra network adapter

Nếu bạn có nhiều hơn một network adapter, và các thành phần Kubernetes của bạn không thể truy cập trên route mặc định, chúng tôi khuyên bạn nên bổ sung (các) IP route để các địa chỉ cụm Kubernetes đi qua adpater thích hợp.

Kiểm tra các cổng cần thiết

Những cổng cần thiết cần phải được mở để các thành phần Kubernetes giao tiếp với nhau. Bạn có thể sử dụng công cụ như netcat để kiểm tra cổng có được mở hay không. Ví dụ:

nc 127.0.0.1 6443 -zv -w 2

Pod network plugin mà bạn sử dụng cũng có thể yêu cầu mở một số cổng nhất định. Vì điều này khác nhau đối với từng pod network plugin, vui lòng xem tài liệu của các plugin về (các) cổng cần thiết.

Cấu hình swap

Mặc định kubelet sẽ không thể khởi động nếu bộ nhớ swap được phát hiện trên một node. Điều này có nghĩa rằng swap nên hoặc là tắt đi hoặc là được chấp nhận bởi kubelet.

  • Để chấp nhận swap, thêm failSwapOn: false vào cấu hình kubelet hoặc thông qua tham số dòng lệnh. Lưu ý: thậm chí nếu failSwapOn: false được thêm, workload mặc định cũng không có quyền truy cập swap. Điều này có thể được thay đổi bằng cách đặt swapBehavior, một lần nữa trong file cấu hình kubelet. Để sử dụng swap, đặt một swapBehavior khác với giá trị mặc định NoSwap. Xem Quản lý bộ nhớ swap để biết thêm chi tiết.
  • Để tắt swap, sudo swapoff -a có thể được sử dụng để tắt tạm thời. Để làm cho thay đổi này duy trì mỗi khi tái khởi động, đảm bảo rằng swap được tắt trong các file cấu hình như /etc/fstab, systemd.swap, phụ thuộc vào việc nó được cấu hình như thế nào trên hệ thống của bạn.

Cài đặt một container runtime

Để chạy các container trong các Pod, Kubernetes sử dụng một container runtime.

Mặc định, Kubernetes sử dụng Container Runtime Interface (CRI) để giao tiếp với container runtime mà bạn chọn.

Nếu bạn không chỉ định một runtime, kubeadm tự động phát hiện một container runtime đã cài đặt bằng cách quét qua một danh sách những endpoint đã biết.

Nếu có nhiều hoặc không có container runtime nào được phát hiện, kubeadm sẽ ném ra một lỗi và sẽ yêu cầu bạn chỉ định một thứ bạn muốn sử dụng.

Xem container runtimes để biết thêm thông tin.

Lưu ý:

Docker Engine không triển khai CRI, một thứ bắt buộc của container runtime để hoạt động với Kubernetes. Vì lí do đó, một dịch vụ bổ sung cri-dockerd phải được cài đặt. cri-dockerd là một dự án dựa trên sự hỗ trợ legacy built-in của Docker Engine mà đã bị loại bỏ khỏi kubelet trong phiên bản 1.24.

Những bản bên dưới bao gồm những endpoint đã biết của những hệ điều hành được hỗ trợ:

Linux container runtimes
RuntimeĐường dẫn tới Unix domain socket
containerdunix:///var/run/containerd/containerd.sock
CRI-Ounix:///var/run/crio/crio.sock
Docker Engine (using cri-dockerd)unix:///var/run/cri-dockerd.sock
Windows container runtimes
RuntimeĐường dẫn tới Windows named pipe
containerdnpipe:////./pipe/containerd-containerd
Docker Engine (using cri-dockerd)npipe:////./pipe/cri-dockerd

Cài đặt kubeadm, kubelet và kubectl

Bạn sẽ cài đặt các package này trên toàn bộ máy chủ của bạn:

  • kubeadm: lệnh khởi tạo cụm.

  • kubelet: thành phần chạy trên toàn bộ các máy trong cụm của bạn và làm những việc như khởi chạy pod và container.

  • kubectl: tiện ích dòng lệnh để giao tiếp với cụm.

kubeadm sẽ không cài đặt hoặc quản lý kubelet và kubectl cho bạn, vì vậy bạn sẽ cần phải đảm bảo rằng phiên bản của chúng giống với Kubernetes control plane bạn muốn kubeadm cài cho bạn. Nếu bạn không làm vậu, rủi ro về sự chênh lệch phiên bản có thể xảy ra và dẫn tới những hành vi lỗi, không mong muốn. Tuy nhiên, chênh lệch một phiên bản minor giữa kubelet và control plane được chấp nhận, nhưng phiên bản kubelet không bao giờ vượt quá phiên bản API server. Ví dụ, kubelet đang chạy 1.7.0 có thể tương thích hoàn toàn với API server phiên bản 1.8.0, nhưng không có chiều ngược lại.

Để biết cách cài đặt kubectl, xem Cài đặt và thiết lập kubectl.

Cảnh báo:

Những hướng dẫn này loại trừ tất cả các package của Kubernetes khỏi mọi sự nâng cấp hệ thống. Bởi vì kubeadm và Kubernetes yêu cầu đặc biệt chú ý khi nâng cấp.

Để biết thêm thông tin về chênh lệch phiên bản, xem:

Lưu ý: Các kho lưu trữ gói cũ (apt.kubernetes.io và yum.kubernetes.io) đã bị lỗi thời và đóng băng từ ngày 13 tháng 9, 2023. Sử dụng các kho lưu trữ mới được đặt tại pkgs.k8s.io được khuyến nghị mạnh mẽ và yêu cầu để cài đặt các phiên bản Kubernetes phát hành sau ngày 13 tháng 9, 2023. Các kho cũ đã lỗi thời, và nội dung của chúng, có thể bị xóa bất kỳ lúc nào trong tương lai và mà không có thêm thông báo. Các kho lưu trữ mới cung cấp tải về cho các phiên bản Kubernetes bắt đầu từ v1.24.0.

Lưu ý:

Có một kho lưu trữ package chuyên dụng cho từng phiên bản minor của Kubernetes. Nếu bạn muốn cài đặt một phiên bản minor khác v1.37, vui lòng xem hướng dẫn cài đặt cho phiên bản minior bạn mong muốn.

Hướng dẫn này dành cho Kubernetes v1.37.

  1. Cập nhật apt package index và cài đặt các package cần thiết để sử dụng kho lưu trữ apt của Kubernetes:

    sudo apt-get update
    # apt-transport-https có thể là một package giả; nếu vậy, bạn có thể bỏ qua package này
    sudo apt-get install -y apt-transport-https ca-certificates curl gpg
    
  2. Tải xuống khóa ký công khai cho các kho lưu trữ package của Kubernetes. Toàn bộ các kho lưu trữ sử dụng chung khóa ký do vậy bạn có thể không cần quan tâm tới phiên bản trong URL:

    # Nếu thư mục `/etc/apt/keyrings` không tồn tại, nó nên được tạo trước lệnh curl, đọc chú thích bên dưới.
    # sudo mkdir -p -m 755 /etc/apt/keyrings
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.37/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    

Lưu ý:

Trong những bản phát hành cũ hơn Debian 12 và Ubuntu 22.04, thư mục /etc/apt/keyrings mặc định không tồn tại, và nó nên được tạo trước lệnh curl.
  1. Thêm kho lưu trữ apt Kubernetes thích hợp. Vui lòng chú ý rằng kho lưu trữ này chỉ chứa những package cho Kubernetes 1.37; đối với các phiên bản Kubernetes minor khác, bạn cần phải thay đổi phiên bản Kubernetes minor trong URL để trùng với phiên bản minor bạn mong muốn (bạn cũng nên kiểm tra lại rằng bạn đang đọc tài liệu cho phiên bản Kubernetes mà bạn dự định cài đặt).

    # Điều này sẽ ghi đè bất kỳ những cấu hình nào đang có trong /etc/apt/sources.list.d/kubernetes.list
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.37/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    
  2. Cập nhật apt package index, cài đặt kubelet, kubeadm và kubectl, và ghim lại phiên bản của chúng:

    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl
    
  3. (Tùy chọn) Bật dịch vụ kubelet trước khi chạy kubeadm:

    sudo systemctl enable --now kubelet
    
  1. Đặt SELinux thành chế độ permissive:

    Những hướng dẫn này dành cho Kubernetes 1.37.

    # Đặt SELinux trong chế độ permissive (vô hiệu hóa nó một cách hiệu quả)
    sudo setenforce 0
    sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
    

Chú ý:

  • Đặt SELinux trong chế độ permissive bằng cách chạy setenforce 0 và sed ... vô hiệu hóa nó một cách hiệu quả. Điều này là bắt buộc để cho phép các container truy cập vào hệ thống file của máy chủ; ví dụ, một vài network plugin của cụm yêu cầu điều này. Bạn phải làm điều này cho đến khi sự hỗ trợ SELinux được cải thiện trong kubelet.
  • Bạn có thể để SELinux bật nếu bạn biết cách cấu hình nó nhưng điều đó có thể yêu cầu các thiết lập không được hỗ trợ bởi kubeadm.
  1. Thêm kho lưu trữ yum của Kubernetes. Tham số exclude trong định nghĩa kho lưu trữ đảm bảo rằng các package liên quan tới Kubernetes không được nâng cấp bởi việc chạy yum update vì có một quy trình đặc biệt cần tuân theo để nâng cấp Kubernetes. Vui lòng chú ý rằng kho lưu trữ này chỉ có các package cho Kubernetes 1.37; đối với những phiên bản Kubernetes minor khác, bạn cần phải thay đổi phiên bản Kubernetes minor trong URL để trùng với phiên bản minor bạn mong muốn (bạn cũng nên kiểm tra lại rằng bạn đang đọc tài liệu cho phiên bản Kubernetes mà bạn dự định cài đặt).

    # Điều này sẽ ghi đè bất kỳ những cấu hình nào đang có trong /etc/yum.repos.d/kubernetes.repo
    cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://pkgs.k8s.io/core:/stable:/v1.37/rpm/
    enabled=1
    gpgcheck=1
    gpgkey=https://pkgs.k8s.io/core:/stable:/v1.37/rpm/repodata/repomd.xml.key
    exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
    EOF
    
  2. Cài đặt kubelet, kubeadm và kubectl:

    sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
    
  3. (Tùy chọn) Bật dịch vụ kubelet trước khi chạy kubeadm:

    sudo systemctl enable --now kubelet
    

Cài đặt CNI plugin (yêu cầu đối với hầu hết pod network):

CNI_PLUGINS_VERSION="v1.3.0"
ARCH="amd64"
DEST="/opt/cni/bin"
sudo mkdir -p "$DEST"
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${ARCH}-${CNI_PLUGINS_VERSION}.tgz" | sudo tar -C "$DEST" -xz

Tạo thư mục để tải xuống file lệnh:

Lưu ý:

Biến DOWNLOAD_DIR phải được đặt tới một thư mục có thể ghi. Nếu bạn đang chạy Flatcar Container Linux, đặt DOWNLOAD_DIR="/opt/bin".
DOWNLOAD_DIR="/usr/local/bin"
sudo mkdir -p "$DOWNLOAD_DIR"

Tùy chọn cài đặt crictl (yêu cầu khi tương tác với Container Runtime Interface (CRI), không bắt buộc cho kubeadm):

CRICTL_VERSION="v1.31.0"
ARCH="amd64"
curl -L "https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-${ARCH}.tar.gz" | sudo tar -C $DOWNLOAD_DIR -xz

Cài đặt kubeadm, kubelet và thêm systemd service cho kubelet:

RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
ARCH="amd64"
cd $DOWNLOAD_DIR
sudo curl -L --remote-name-all https://dl.k8s.io/release/${RELEASE}/bin/linux/${ARCH}/{kubeadm,kubelet}
sudo chmod +x {kubeadm,kubelet}

RELEASE_VERSION="v0.16.2"
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubelet/kubelet.service" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /usr/lib/systemd/system/kubelet.service
sudo mkdir -p /usr/lib/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/krel/templates/latest/kubeadm/10-kubeadm.conf" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

Lưu ý:

Vui lòng tham khảo ghi chú trong phần Trước khi bạn bắt đầu cho các bản phân phối Linux mà mặc định không có glibc.

Cài đặt kubectl bằng cách làm theo các hướng dẫn trên trang Cài đặt các công cụ.

Một cách tùy chọn, bật dịch vụ kubelet trước khi chạy kubeadm:

sudo systemctl enable --now kubelet

Lưu ý:

Bản phân phối Linux Flatcar Container gắn thư mục /usr thành một hệ thống file chỉ đọc. Xem hướng dẫn Khắc phục sự cố Kubeadm để biết cách thiết lập một thư mục có thể ghi.

Bây giờ kubelet khởi động sau mỗi vài giây, vì nó đợi trong vòng lặp crashloop chờ kubeadm bảo nó phải làm gì.

Cấu hình cgroup driver

Cả container runtime và kubelet có một thuộc tính gọi là "cgroup driver", cái mà quan trọng cho việc quản lý các cgroup trên các máy Linux.

Cảnh báo:

Làm cho khớp các cgroup driver của container runtime và kubelet là bắt buộc hoặc nếu không thì tiến trình kubelet sẽ lỗi.

Xem Cấu hình cgroup driver để biết thêm chi tiết.

Khắc phục sự cố

Nếu bạn đang gặp các khó khăn với kubeadm, vui lòng tham khảo tài liệu khắc phục sự cố của chúng tôi.

Tiếp theo là gì

2.2.2.1.2 - Các tùy chọn cho kiến trúc có tính Sẵn sàng cao

Trang này giải thích hai lựa chọn cho việc cấu hình kiến trúc cho các cụm Kubernetes có tính sẵn sàng cao (HA) của bạn.

Bạn có thể thiết lập một cụm HA:

  • Với các control plane node xếp chồng, nơi các etcd node được đặt cùng vị trí với các control plane node
  • Với các etcd node bên ngoài, nơi etcd chạy trên từng node riêng biệt so với các control plane node

Bạn nên cân nhắc kỹ lưỡng những ưu điểm và nhược điểm của từng kiến trúc trước khi thiết lập một cụm HA.

Lưu ý:

kubeadm khởi tạo cụm etcd một cách tĩnh. Đọc Hướng dẫn Phân cụm etcd để biết thêm chi tiết.

Kiến trúc etcd xếp chồng

Một cụm HA xếp chồng là một kiến trúc nơi cụm lưu trữ dữ liệu phân tán được cung cấp bởi etcd được xếp chồng lên đầu cụm được hình thành bởi các node được quản lý bởi kubeadm chạy các thành phần control plane.

Mỗi control plane node chạy một instance kube-apiserver, kube-scheduler, và kube-controller-manager. kube-apiserver được expose tới các worker node bằng một bộ cân bằng tải.

Mỗi control plane node tạo một etcd member cục bộ và etcd member này chỉ giao tiếp với kube-apiserver của node đó. Tương tự áp dụng cho các instance kube-controller-manager và kube-scheduler cục bộ.

Cấu trúc liên kết này kết hợp các control plane và các etcd member trên cùng một node. Điều này đơn giản hơn việc thiết lập một cụm với các etcd node bên ngoài, và đơn giản hơn để quản lý replication.

Tuy nhiên, một cụm xếp chồng có nguy cơ lỗi hàng loạt. Nếu một node bị lỗi, cả một etcd member và một instance control plane bị lỗi, và khả năng dự phòng bị ảnh hưởng. Bạn có thể giảm thiểu rủi ro này bằng cách bổ sung thêm control plane node.

Do đó, bạn nên chạy tối thiểu ba node control plane xếp chồng cho cụm HA.

Đây là kiến trúc mặc định trong kubeadm. Một etcd member cục bộ được tạo tự động trên control plane node khi sử dụng kubeadm init và kubeadm join --control-plane.

Kiến trúc etcd xếp chồng

Kiến trúc etcd bên ngoài

Một cụm HA với etcd bên ngoài là một kiến trúc nơi cụm lưu trữ dữ liệu phân tán được cung cấp bởi etcd nằm ngoài cụm được hình thành bởi các node chạy các thành phần control plane.

Giống như kiến trúc etcd xếp chồng, mỗi control plane node trong một kiến trúc etcd bên ngoài chạy một instance kube-apiserver, kube-scheduler, và kube-controller-manager. Và kube-apiserver được expose tới các worker node bằng một bộ cân bằng tải. Tuy nhiên, các etcd member chạy trên từng host riêng biệt, và từng etcd host giao tiếp với kube-apiserver của từng control plane node.

Kiến trúc này tách rời control plane và etcd member. Vì thế nó cung cấp một thiết lập HA trong đó việc mất một control plane instance hoặc một etcd member có ít tác động hơn và không ảnh hưởng tới khả năng dự phòng của cụm như kiến trúc HA xếp chồng.

Tuy nhiên, kiến trúc này yêu cầu gấp đôi số lượng host so với kiến trúc HA xếp chồng. Yêu cầu tối thiểu ba host cho các control plane node và ba host cho các etcd node cho một cụm HA với kiến trúc này.

Kiến trúc etcd bên ngoài

Tiếp theo là gì

2.2.2.1.3 - Tạo các cụm có tính Sẵn sàng cao với kubeadm

Trang này giải thích hai cách tiếp cận khác nhau để thiết lập một cụm Kubernetes sẵn sàng cao sử dụng kubeadm:

  • Với các control plane node xếp chồng. Cách tiếp cận này yêu cầu ít cơ sở hạ tầng. Các etcd member và control plane node nằm cùng vị trí.
  • Với một cụm etcd bên ngoài. Cách tiếp cận này yêu cầu nhiều cơ sở hạ tầng hơn. Các control plane node và etcd member được tách biệt.

Trước khi tiến hành, bạn nên cân nhắc kỹ lưỡng cách tiếp cận nào đáp ứng tốt nhất nhu cầu của các ứng dụng và môi trường của bạn. Các tùy chọn cho kiến trúc có tính Sẵn sàng cao chỉ ra các ưu điểm và nhược điểm của từng cách đó.

Nếu bạn gặp phải các vấn đề khi thiết lập cụm HA, vui lòng phản ánh chúng trong trình theo dõi vấn đề kubeadm.

Xem thêm tài liệu nâng cấp.

Chú ý:

Trang này không giải quyết việc chạy cụm của bạn trên một nhà cung cấp cloud. Trong một môi trường cloud, không có cách tiếp cận nào được đề cập ở đây hoạt động với các đối tượng Service loại LoadBalancer, hoặc với PersistentVolumes động.

Trước khi bạn bắt đầu

Những điều kiện tiên quyết dựa trên kiến trúc bạn chọn cho control plane của cụm:

Bạn cần:

  • Ba hoặc nhiều hơn các máy đáp ứng các yêu cầu tối thiểu của kubeadm cho các control plane node. Có một số lượng lẻ các control plane node có thể giúp cho việc chọn leader trong trường hợp máy hoặc zone gặp lỗi.
  • Ba hoặc nhiều hơn các máy đáp ứng các yêu cầu tối thiểu của kubeadm cho các worker node.
    • bao gồm một container runtime, đã được thiết lập và hoạt động.
  • Kết nối toàn mạng giữa các máy trong cụm (mạng public hoặc private).
  • Đặc quyền superuser trên tất cả các máy sử dụng sudo.
    • Bạn có thể sử dụng một công cụ khác; hướng dẫn này sử dụng sudo trong các ví dụ.
  • Quyền truy cập SSH từ một thiết bị tới toàn bộ các node trong hệ thống.
  • kubeadm và kubelet đã được cài đặt trên toàn bộ các máy.

Xem thêm Kiến trúc etcd xếp chồng.

Bạn cần:

  • Ba hoặc nhiều hơn các máy đáp ứng các yêu cầu tối thiểu của kubeadm cho các control plane node. Có một số lượng lẻ các control plane node có thể giúp cho việc chọn leader trong trường hợp máy hoặc zone gặp lỗi.
  • Ba hoặc nhiều hơn các máy đáp ứng các yêu cầu tối thiểu của kubeadm cho các worker node.
    • bao gồm một container runtime, đã được thiết lập và hoạt động.
  • Kết nối toàn mạng giữa các máy trong cụm (mạng public hoặc private).
  • Đặc quyền superuser trên tất cả các máy sử dụng sudo.
    • Bạn có thể sử dụng một công cụ khác; hướng dẫn này sử dụng sudo trong các ví dụ.
  • Quyền truy cập SSH từ một thiết bị tới toàn bộ các node trong hệ thống.
  • kubeadm và kubelet đã được cài đặt trên toàn bộ các máy.

Và bạn cũng cần:

  • Ba hoặc nhiều các máy bổ sung, chúng sẽ trở thành các etcd member của cụm. Yêu cầu một số lượng lẻ các member trong cụm etcd để đạt được ngưỡng bầu cử tối ưu.
    • Những máy này cũng cần được cài đặt kubeadm và kubelet.
    • Những máy này cũng yêu cầu một container runtime đã được thiết lập và hoạt động.

Xem thêm Kiến trúc etcd bên ngoài.

Container image

Từng host cần có quyền read và fetch các image từ Kubernetes container image registry, registry.k8s.io. Nếu bạn muốn triển khai một cụm HA trong đó các host không có quyền pull image, điều này khả thi. Bạn cần phải đảm bảo rằng các container image cần thiết có sẵn trên các host liên quan bằng một vài phương pháp khác.

Giao diện dòng lệnh

Để quản lý Kubernetes một khi cụm của bạn được thiết lập, bạn nên cài đặt kubectl trên PC của bạn. Cài đặt công cụ kubectl trên từng control plane node cũng hữu ích, vì nó có thể giúp trong việc xử lý sự cố.

Những bước đầu tiên cho cả hai phương pháp

Tạo bộ cân bằng tải cho kube-apiserver

Lưu ý:

Có nhiều kiểu cấu hình cho các bộ cân bằng tải. Ví dụ dưới đây là một lựa chọn. Những yêu cầu đối với cụm của bạn có thể cần một cấu hình khác.
  1. Tạo một bộ cân bằng tải kube-apiserver với tên được phân giải tới DNS.

    • Trong một môi trường cloud bạn nên đặt các control plane node của bạn phía sau một bộ cân bằng tải chuyển tiếp TCP. Bộ cân bằng tải này phân bổ lưu lượng tới toàn bộ các control plane node khỏe mạnh trong danh sách target của nó. Kiểm tra sức khỏe cho một apiserver là một kiểm tra TCP trên port mà kube-apiserver lắng nghe (giá trị mặc định :6443).

    • Không nên sử dụng một địa chỉ IP một cách trực tiếp trong môi trường cloud.

    • Bộ cân bằng tải phải có khả năng giao tiếp với toàn bộ control plane node trên port của apiserver. Nó cũng phải cho phép lưu lượng truy cập đến trên port được nó lắng nghe.

    • Đảm bảo rằng địa chỉ của bộ cân bằng tải luôn khớp với địa chỉ ControlPlaneEndpoint của kubeadm.

    • Đọc hướng dẫn Các tùy chọn cho Cân bằng tải Phần mềm để biết thêm thông tin chi tiết.

  2. Thêm control plane node đầu tiên vào bộ cân bằng tải, và kiểm tra kết nối:

    nc -zv -w 2 <LOAD_BALANCER_IP> <PORT>
    

    Một lỗi từ chối kết nối có thể xảy ra bởi vì API server vẫn chưa chạy. Tuy nhiên, timeout có nghĩa là bộ cân bằng tải không thể giao tiếp với control plane node. Nếu một timeout xảy ra, cấu hình lại bộ cân bằng tải để có thể giao tiếp với control plane node.

  3. Thêm các control plane node còn lại vào target group của bộ cân bằng tải.

Các control plane và etcd node xếp chồng

Các bước cho control plane node đầu tiên

  1. Khởi tạo control plane:

    sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
    
    • Bạn có thể sử dụng cờ --kubernetes-version để chỉ định phiên bản Kubernetes mong muốn. Khuyến nghị rằng các phiên bản của kubeadm, kubelet, kubectl và Kubernetes khớp với nhau.

    • Cờ --control-plane-endpoint nên được đặt thành địa chỉ hoặc DNS và port của bộ cân bằng tải.

    • Cờ --upload-certs được sử dụng để upload các chứng chỉ mà sẽ được chia sẻ tới toàn bộ control-plane instance trong cụm. Nếu thay vào đó, bạn muốn copy các chứng chỉ tới toàn bộ control-plane node một cách thủ công hoặc sử dụng các công cụ tự động, vui lòng bỏ qua cờ này và xem phần Phân bổ chứng chỉ thủ công bên dưới.

    Lưu ý:

    Trong kubeadm init, các cờ --config và --certificate-key không thể kết hợp, vì nếu bạn muốn sử dụng cấu hình kubeadm bạn phải thêm trường certificateKey trong các vị trí cấu hình thích hợp (dưới InitConfiguration và JoinConfiguration: controlPlane).

    Lưu ý:

    Một vài CNI network plugin yêu cầu cấu hình bổ sung, ví dụ chỉ định pod IP CIDR, trong khi những cái khác thì không. Xem tài liệu CNI network. Để thêm một pod CIDR sử dụng cờ --pod-network-cidr, hoặc nếu bạn đang sử dụng file cấu hình kubeadm đặt trường podSubnet bên dưới đối tượng networking của ClusterConfiguration.

    Output sẽ trông giống như dưới đây:

    ...
    You can now join any number of control-plane node by running the following command on each as a root:
        kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
    
    Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
    As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.
    
    Then you can join any number of worker nodes by running the following on each as root:
        kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
    
    • Copy output này ra một file text. Bạn sẽ cần nó sau này để join các node control plane và worker vào cụm.

    • Khi cờ --upload-certs được sử dụng cùng kubeadm init, các chứng chỉ của control plane chính được mã hóa và upload trong kubeadm-certs Secret.

    • Để upload lại các chứng chỉ và tạo ra một khóa giải mã mới, sử dụng lệnh sau đây trên một control plane node mà đã join vào cụm:

      sudo kubeadm init phase upload-certs --upload-certs
      
    • Bạn cũng có thể chỉ định một --certificate-key tùy chỉnh trong lúc init mà sau này có thể được sử dụng để join. Để tạo ra một khóa như vậy bạn có thể sử dụng lệnh sau đây:

      kubeadm certs certificate-key
      

    Khóa của chứng chỉ là một chuỗi mã hóa hex, đó là một khóa AES có kích thước 32 byte.

    Lưu ý:

    kubeadm-certs Secret và khóa giải mã sẽ hết hạn sau hai giờ.

    Chú ý:

    Như đã nêu trong output của câu lệnh, khóa chứng chỉ cung cấp quyền truy cập tới dữ liệu nhạy cảm của cụm, hãy giữ nó bí mật!
  2. Áp dụng CNI plugin mà bạn chọn: Theo dõi các hướng dẫn để cài đặt nhà cung cấp CNI. Chắc chắn rằng cấu hình tương ứng với Pod CIDR đã được chỉ định trong file cấu hình kubeadm (nếu có).

    Lưu ý:

    Bạn phải chọn một network plugin phù hợp với trường hợp sử dụng của bạn và triển khai nó trước khi bạn chuyển sang bước tiếp theo. Nếu bạn không làm điều đó, bạn sẽ không thể khởi chạy cụm của bạn đúng cách.
  3. Nhập câu lệnh sau và xem các pod của các thành phần control plane bắt đầu chạy:

    kubectl get pod -n kube-system -w
    

Các bước cho các control plane node còn lại

Đối với từng control plane node bổ sung bạn nên:

  1. Thực thi lệnh join bạn nhận được bởi kubeadm init output trước đây trên node đầu tiên. Nó sẽ trông giống như này:

    sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
    
    • Cờ --control-plane báo cho kubeadm join tạo một control plane mới.
    • Cờ --certificate-key ... sẽ download các chứng chỉ cho control plane từ kubeadm-certs Secret trong cụm và được giải mã bằng khóa được cung cấp.

Bạn có thể join nhiều control-plane node đồng thời.

Các etcd node bên ngoài

Thiết lập một cụm với các etcd node bên ngoài giống như các thủ tục được sử dụng cho etcd xếp chồng với ngoại lệ là bạn phải thiết lập etcd trước, và bạn sẽ thêm thông tin etcd trong file cấu hình kubeadm.

Khởi tạo cụm etcd

  1. Theo dõi những hướng dẫn này để khởi tạo cụm etcd.

  2. Thiết lập SSH như mô tả tại đây.

  3. Copy các file sau đây từ bất kỳ etcd node nào trong cụm tới control plane node đầu tiên:

    export CONTROL_PLANE="ubuntu@10.0.0.7"
    scp /etc/kubernetes/pki/etcd/ca.crt "${CONTROL_PLANE}":
    scp /etc/kubernetes/pki/apiserver-etcd-client.crt "${CONTROL_PLANE}":
    scp /etc/kubernetes/pki/apiserver-etcd-client.key "${CONTROL_PLANE}":
    
    • Thay giá trị của CONTROL_PLANE bằng user@host của control-plane node đầu tiên.

Thiết lập control plane node đầu tiên

  1. Tạo một file với tên kubeadm-config.yaml cùng với những nội dung sau đây:

    ---
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: ClusterConfiguration
    kubernetesVersion: stable
    controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" # thay đổi cái này (xem bên dưới)
    etcd:
      external:
        endpoints:
          - https://ETCD_0_IP:2379 # thay ETCD_0_IP thích hợp
          - https://ETCD_1_IP:2379 # thay ETCD_1_IP thích hợp
          - https://ETCD_2_IP:2379 # thay ETCD_2_IP thích hợp
        caFile: /etc/kubernetes/pki/etcd/ca.crt
        certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
        keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
    

    Lưu ý:

    Sự khác nhau giữa etcd xếp chồng và etcd bên ngoài là thiết lập etcd bên ngoài yêu cầu một file cấu hình với các etcd endpoint bên dưới đối tượng external của etcd. Trong trường hợp của kiến trúc etcd xếp chồng, nó được quản lý tự động.
    • Thay các biến sau đây trong mẫu cấu hình bằng các giá trị thích hợp cho cụm của bạn:

      • LOAD_BALANCER_DNS
      • LOAD_BALANCER_PORT
      • ETCD_0_IP
      • ETCD_1_IP
      • ETCD_2_IP

Những bước sau đây tương tự với thiết lập etcd xếp chồng:

  1. Chạy sudo kubeadm init --config kubeadm-config.yaml --upload-certs trên node này.

  2. Viết output của các lệnh join được trả về vào một file text để sử dụng sau này.

  3. Áp dụng CNI plugin mà bạn chọn.

    Lưu ý:

    Bạn phải chọn một network plugin phù hợp với trường hợp sử dụng của bạn và triển khai nó trước khi bạn chuyển sang bước tiếp theo. Nếu bạn không làm điều đó, bạn sẽ không thể khởi chạy cụm của bạn đúng cách.

Các bước cho các control plane node còn lại

Các bước giống với thiết lập etcd xếp chồng:

  • Đảm bảo rằng control plane node đầu tiên được khởi tạo hoàn tất.
  • Join từng control plane node với lệnh join bạn lưu trong một file text. Bạn nên join các control plane node lần lượt.
  • Đừng quên rằng khóa giải mã từ --certificate-key mặc định sẽ hết hạn sau hai giờ.

Những task phổ biến sau khi khởi tạo control plane

Cài đặt các worker

Các worker node có thể được join vào cụm với lệnh bạn lưu trước đó từ output của lệnh kubeadm init:

sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

Phân bổ chứng chỉ thủ công

Nếu bạn chọn không sử dụng kubeadm init với cờ --upload-certs điều đó có nghĩa là bạn sẽ phải copy thủ công các chứng chỉ từ control plane node chính tới các control plane node sắp join.

Có nhiều cách để làm điều đó. Cách dưới đây sử dụng ssh và scp:

SSH là cần thiết nếu bạn muốn điều khiển toàn bộ các node từ một máy đơn.

  1. Cho phép ssh-agent trên thiết bị chính của bạn có quyền truy cập tới toàn bộ các node khác trong hệ thống:

    eval $(ssh-agent)
    
  2. Thêm định danh SSH vào phiên:

    ssh-add ~/.ssh/path_to_private_key
    
  3. SSH giữa các node để kiểm tra kết nối hoạt động tốt.

    • Khi bạn SSH tới bất kỳ node nào, thêm cờ -A. Cờ này cho phép node mà bạn đăng nhập qua SSH có quyền truy cập tới SSH agent trên PC của bạn. Cân nhắc các phương pháp thay thế nếu bạn không hoàn toàn tin tưởng vào bảo mật của phiên người dùng của bạn trên node.

      ssh -A 10.0.0.7
      
    • Khi bạn sử dụng sudo trên bất kỳ node nào, đảm bảo duy trì môi trường để SSH chuyển tiếp các hoạt động:

      sudo -E -s
      
  4. Sau khi cấu hình SSH trên toàn bộ các node bạn nên chạy tập lệnh sau đây trên control plane node đầu tiên sau khi chạy kubeadm init. Tập lệnh này sẽ copy các chứng chỉ từ control plane node đầu tiên tới các control plane node khác:

    Trong ví dụ dưới đây, thay CONTROL_PLANE_IPS với các địa chỉ IP của các control plane node khác.

    USER=ubuntu # có thể tùy chỉnh
    CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"
    for host in ${CONTROL_PLANE_IPS}; do
        scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
        scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
        scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
        scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
        scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
        scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
        scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
        # Bỏ qua dòng tiếp theo nếu bạn đang sử dụng etcd bên ngoài
        scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
    done
    

    Chú ý:

    Chỉ copy các chứng chỉ trong danh sách trên. kubeadm sẽ phụ trách việc sinh ra các chứng chỉ còn lại cùng với các SAN cần thiết cho các control-plane instance sắp join. Nếu bạn copy toàn bộ các chứng chỉ do nhầm lẫn, quá trình tạo các node bổ sung có thể thất bại do thiếu các SAN cần thiết.
  5. Sau đó trên từng control plane node sắp join bạn phải chạy tập lệnh sau đây trước khi chạy kubeadm join. Tập lệnh này sẽ di chuyển các chứng chỉ đã được copy trước đây từ thư mục home tới /etc/kubernetes/pki:

    USER=ubuntu # có thể tùy chỉnh
    mkdir -p /etc/kubernetes/pki/etcd
    mv /home/${USER}/ca.crt /etc/kubernetes/pki/
    mv /home/${USER}/ca.key /etc/kubernetes/pki/
    mv /home/${USER}/sa.pub /etc/kubernetes/pki/
    mv /home/${USER}/sa.key /etc/kubernetes/pki/
    mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
    mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
    mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
    # Bỏ qua dòng tiếp theo nếu bạn đang sử dụng etcd bên ngoài
    mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
    

2.2.2.1.4 - Thiết lập một cụm etcd có tính Sẵn sàng cao (High Availability) với kubeadm

Mặc định, kubeadm chạy một instance etcd cục bộ trên từng node control plane. Bạn cũng có thể thiết lập cụm etcd bên ngoài và cung cấp các etcd instance trên các máy chủ riêng biệt. Những sự khác biệt giữa hai cách tiếp cận này được trình bày trong trang Các tùy chọn cho kiến trúc có tính Sẵn sàng cao.

Tác vụ này hướng dẫn quy trình tạo một cụm etcd bên ngoài có tính sẵn sàng cao gồm ba member mà kubeadm có thể sử dụng trong quá trình tạo cụm.

Trước khi bạn bắt đầu

  • Ba máy chủ có thể giao tiếp với nhau qua cổng TCP 2379 và 2380. Tài liệu này giả định các cổng mặc định này. Tuy nhiên, chúng có thể được cấu hình thông qua tệp cấu hình kubeadm.
  • Mỗi máy chủ phải có systemd và đã cài đặt một shell tương thích với bash.
  • Mỗi máy chủ phải đã cài đặt một container runtime, kubelet, và kubeadm.
  • Mỗi máy chủ phải có quyền truy cập vào Kubernetes container image registry (registry.k8s.io) hoặc list/pull image etcd cần thiết bằng lệnh kubeadm config images list/pull. Hướng dẫn này sẽ cài đặt các etcd instance dạng static pods được quản lý bởi kubelet.
  • Một số công cụ để sao chép các file giữa các máy chủ. Ví dụ ssh và scp có thể đáp ứng yêu cầu này.

Thiết lập cụm

Cách tiếp cận thông thường là tạo ra toàn bộ chứng chỉ trên một node và chỉ phân bổ những file quan trọng tới các node khác.

Lưu ý:

kubeadm chứa tất cả các công cụ mã hóa cần thiết để tạo ra các chứng chỉ được đề cập bên dưới; không cần các công cụ mã hóa nào khác cho ví dụ này.

Lưu ý:

Ví dụ bên dưới sử dụng dịa chỉ IPv4 nhưng bạn cũng có thể cấu hình kubeadm, kubelet và etcd sử dụng địa chỉ IPv6. Dual-stack được hỗ trợ bởi một vài tùy chọn của Kubernetes, nhưng không được etcd hỗ trợ. Xem thêm chi tiết về Kubernetes hỗ trợ dual-stack tại Hỗ trợ Dual-stack với kubeadm.
  1. Cấu hình kubelet để trở thành trình quản lý dịch vụ cho etcd.

    Lưu ý:

    Bạn phải thực hiện điều này trên toàn bộ các máy chủ chạy etcd.
    Vì etcd sẽ được tạo ra trước tiên, bạn phải ghi đè độ ưu tiên dịch vụ bằng cách tạo ra một unit file mới có độ ưu tiên cao hơn kubelet unit file mà kubeadm cung cấp.

    cat << EOF > /etc/systemd/system/kubelet.service.d/kubelet.conf
    # Thay thế "systemd" bằng giá trị cgroup driver của container runtime của bạn. Giá trị mặc định trong kubelet là "cgroupfs".
    # Thay thế giá trị của "containerRuntimeEndpoint" bằng một container runtime khác nếu cần.
    #
    apiVersion: kubelet.config.k8s.io/v1beta1
    kind: KubeletConfiguration
    authentication:
      anonymous:
        enabled: false
      webhook:
        enabled: false
    authorization:
      mode: AlwaysAllow
    cgroupDriver: systemd
    address: 127.0.0.1
    containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
    staticPodPath: /etc/kubernetes/manifests
    EOF
    
    cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
    [Service]
    ExecStart=
    ExecStart=/usr/bin/kubelet --config=/etc/systemd/system/kubelet.service.d/kubelet.conf
    Restart=always
    EOF
    
    systemctl daemon-reload
    systemctl restart kubelet
    

    Kiểm tra trạng thái kubelet để chắc chắn rằng nó đang chạy.

    systemctl status kubelet
    
  2. Tạo các file cấu hình cho kubeadm.

    Tạo một file cấu hình kubeadm cho từng máy chủ mà có etcd member chạy trên đó sử dụng tập lệnh dưới đây.

    # Thay đổi HOST0, HOST1 và HOST2 với các IP của các máy của bạn
    export HOST0=10.0.0.6
    export HOST1=10.0.0.7
    export HOST2=10.0.0.8
    
    # Thay đổi NAME0, NAME1 và NAME2 bằng hostnames của các máy của bạn
    export NAME0="infra0"
    export NAME1="infra1"
    export NAME2="infra2"
    
    # Tạo các thư mục tạm thời để lưu các file sẽ xuất hỉện trên các máy khác
    mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/
    
    HOSTS=(${HOST0} ${HOST1} ${HOST2})
    NAMES=(${NAME0} ${NAME1} ${NAME2})
    
    for i in "${!HOSTS[@]}"; do
    HOST=${HOSTS[$i]}
    NAME=${NAMES[$i]}
    cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
    ---
    apiVersion: "kubeadm.k8s.io/v1beta4"
    kind: InitConfiguration
    nodeRegistration:
        name: ${NAME}
    localAPIEndpoint:
        advertiseAddress: ${HOST}
    ---
    apiVersion: "kubeadm.k8s.io/v1beta4"
    kind: ClusterConfiguration
    etcd:
        local:
            serverCertSANs:
            - "${HOST}"
            peerCertSANs:
            - "${HOST}"
            extraArgs:
            - name: initial-cluster
              value: ${NAMES[0]}=https://${HOSTS[0]}:2380,${NAMES[1]}=https://${HOSTS[1]}:2380,${NAMES[2]}=https://${HOSTS[2]}:2380
            - name: initial-cluster-state
              value: new
            - name: name
              value: ${NAME}
            - name: listen-peer-urls
              value: https://${HOST}:2380
            - name: listen-client-urls
              value: https://${HOST}:2379
            - name: advertise-client-urls
              value: https://${HOST}:2379
            - name: initial-advertise-peer-urls
              value: https://${HOST}:2380
    EOF
    done
    
  3. Tạo cơ quan cấp chứng chỉ (CA).

    Nếu bạn đã có một CA, việc tiếp theo chỉ cần sao chép các file crt và key của CA tới /etc/kubernetes/pki/etcd/ca.crt và /etc/kubernetes/pki/etcd/ca.key. Sau khi các file đó được sao chép, tiến hành các bước tiếp theo, "Tạo các chứng chỉ cho từng member member".

    Nếu bạn chưa có CA nào, hãy chạy câu lệnh này trên $HOST0 (nơi bạn tạo các file cấu hình cho kubeadm).

    kubeadm init phase certs etcd-ca
    

    Nó sẽ tạo ra hai file:

    • /etc/kubernetes/pki/etcd/ca.crt
    • /etc/kubernetes/pki/etcd/ca.key
  4. Tạo các chứng chỉ cho từng member member.

    kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
    kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
    cp -R /etc/kubernetes/pki /tmp/${HOST2}/
    # Dọn dẹp các chứng chỉ không sử dụng
    find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
    
    kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
    kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
    cp -R /etc/kubernetes/pki /tmp/${HOST1}/
    find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
    
    kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
    kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
    kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
    # Không cần phải di chuyển các chứng chỉ vì chúng dành cho HOST0
    
    # Dọn dẹp các chứng chỉ không nên sao chép khỏi máy chủ này
    find /tmp/${HOST2} -name ca.key -type f -delete
    find /tmp/${HOST1} -name ca.key -type f -delete
    
  5. Sao chép các chứng chỉ và các cấu hình kubeadm.

    Các chứng chỉ này đã được tạo ra và bây giờ chúng cần được đưa tới từng máy chủ tương ứng.

    USER=ubuntu
    HOST=${HOST1}
    scp -r /tmp/${HOST}/* ${USER}@${HOST}:
    ssh ${USER}@${HOST}
    USER@HOST $ sudo -Es
    root@HOST $ chown -R root:root pki
    root@HOST $ mv pki /etc/kubernetes/
    
  6. Đảm bảo đã có đủ toàn bộ các file cần thiết.

    Danh sách đầy đủ các file cần thiết trên $HOST0 gồm:

    /tmp/${HOST0}
    └── kubeadmcfg.yaml
    ---
    /etc/kubernetes/pki
    ├── apiserver-etcd-client.crt
    ├── apiserver-etcd-client.keyt
    └── etcd
        ├── ca.crt
        ├── ca.key
        ├── healthcheck-client.crt
        ├── healthcheck-client.key
        ├── peer.crt
        ├── peer.key
        ├── server.crt
        └── server.key
    

    Trên $HOST1:

    $HOME
    └── kubeadmcfg.yaml
    ---
    /etc/kubernetes/pki
    ├── apiserver-etcd-client.crt
    ├── apiserver-etcd-client.key
    └── etcd
        ├── ca.crt
        ├── healthcheck-client.crt
        ├── healthcheck-client.key
        ├── peer.crt
        ├── peer.key
        ├── server.crt
        └── server.key
    

    Trên $HOST2:

    $HOME
    └── kubeadmcfg.yaml
    ---
    /etc/kubernetes/pki
    ├── apiserver-etcd-client.crt
    ├── apiserver-etcd-client.key
    └── etcd
        ├── ca.crt
        ├── healthcheck-client.crt
        ├── healthcheck-client.key
        ├── peer.crt
        ├── peer.key
        ├── server.crt
        └── server.key
    
  7. Tạo các manifest cho static pod.

    Bây giờ các chứng chỉ và cấu hình đã có, đã đến lúc tạo các manifest. Trên mỗi máy chủ, hãy chạy lệnh kubeadm để tạo static manifest cho etcd.

    root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml
    root@HOST1 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml
    root@HOST2 $ kubeadm init phase etcd local --config=$HOME/kubeadmcfg.yaml
    
  8. Tùy chọn: Kiểm tra sức khỏe cụm.

    Nếu etcdctl không có sẵn, bạn có thể chạy công cụ này trong một container image. Bạn sẽ thực hiện điều đó trực tiếp với container runtime của mình bằng cách sử dụng một công cụ như crictl run và không thông qua Kubernetes.

    ETCDCTL_API=3 etcdctl \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --endpoints https://${HOST0}:2379 endpoint health
    ...
    https://[HOST0 IP]:2379 is healthy: successfully committed proposal: took = 16.283339ms
    https://[HOST1 IP]:2379 is healthy: successfully committed proposal: took = 19.44402ms
    https://[HOST2 IP]:2379 is healthy: successfully committed proposal: took = 35.926451ms
    
    • Đặt ${HOST0} bằng địa chỉ IP của máy chủ bạn đang kiểm tra.

Tiếp theo là gì

Một khi bạn đã có một cụm etcd với 3 member đang chạy, bạn có thể tiếp tục thiết lập một control plane có tính sẵn sàng cao bằng phương pháp etcd bên ngoài với kubeadm.

2.3 - Một số cách thức cài đặt tốt

3 - Các khái niệm

Phần Khái niệm giúp bạn tìm hiểu về các bộ phận của hệ thống Kubernetes và các khái niệm mà Kubernetes sử dụng để biểu diễn cụm cluster của bạn, đồng thời giúp bạn hiểu sâu hơn về cách thức hoạt động của Kubernetes.

3.1 - Deployments

Deployment quản lý một tập hợp các Pod để chạy một workload ứng dụng, thường là các ứng dụng không duy trì trạng thái.

Deployment cung cấp khả năng cập nhật dạng khai báo (declarative) cho các Pod và ReplicaSet.

Bạn mô tả trạng thái mong muốn (desired state) trong một Deployment, và Vòng điều khiển (Controller) của Deployment sẽ thay đổi trạng thái thực tế sang trạng thái mong muốn với tốc độ được kiểm soát. Bạn có thể định nghĩa các Deployment để tạo ReplicaSet mới, hoặc để xóa các Deployment hiện có và tiếp nhận toàn bộ tài nguyên của chúng bằng các Deployment mới.

Lưu ý:

Không quản lý trực tiếp các ReplicaSet thuộc sở hữu của một Deployment. Hãy cân nhắc mở một issue trong repository chính của Kubernetes nếu trường hợp sử dụng của bạn không được đề cập bên dưới.

Trường hợp sử dụng

Sau đây là các trường hợp sử dụng điển hình của Deployment:

Tạo một Deployment

Dưới đây là một ví dụ về Deployment. Nó tạo một ReplicaSet để khởi chạy ba Pod nginx:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Trong ví dụ này:

  • Một Deployment tên là nginx-deployment được tạo, được chỉ định bởi trường .metadata.name. Tên này sẽ trở thành cơ sở để đặt tên cho các ReplicaSet và Pod được tạo sau đó. Xem Viết spec cho Deployment để biết thêm chi tiết.

  • Deployment tạo một ReplicaSet, ReplicaSet này tạo ba Pod replica, được chỉ định bởi trường .spec.replicas.

  • Trường .spec.selector định nghĩa cách ReplicaSet được tạo ra tìm các Pod mà nó cần quản lý. Trong trường hợp này, bạn chọn một label được định nghĩa trong Pod template (app: nginx). Tuy nhiên, có thể sử dụng các quy tắc lựa chọn phức tạp hơn, miễn là bản thân Pod template thỏa mãn quy tắc đó.

    Lưu ý:

    Trường .spec.selector.matchLabels là một map gồm các cặp {key,value}. Một cặp {key,value} trong map matchLabels tương đương với một phần tử của matchExpressions, có trường key là "key", operator là "In", và mảng values chỉ chứa "value". Tất cả các yêu cầu, từ cả matchLabels và matchExpressions, đều phải được thỏa mãn thì mới khớp.
  • Trường .spec.template chứa các trường con sau:

    • Các Pod được gắn label app: nginx thông qua trường .metadata.labels.
    • Đặc tả của Pod template, hay trường .spec, chỉ ra rằng các Pod chạy một container, nginx, container này chạy image nginx trên Docker Hub ở phiên bản 1.14.2.
    • Tạo một container và đặt tên là nginx thông qua trường .spec.containers[0].name.

Trước khi bắt đầu, hãy đảm bảo cluster Kubernetes của bạn đang hoạt động. Làm theo các bước dưới đây để tạo Deployment ở trên:

  1. Tạo Deployment bằng cách chạy lệnh sau:

    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
    
  2. Chạy kubectl get deployments để kiểm tra xem Deployment đã được tạo hay chưa.

    Nếu Deployment vẫn đang được tạo, kết quả sẽ tương tự như sau:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   0/3     0            0           1s
    

    Khi bạn kiểm tra các Deployment trong cluster, các trường sau được hiển thị:

    • NAME liệt kê tên của các Deployment trong namespace.
    • READY hiển thị số replica của ứng dụng đang sẵn sàng phục vụ người dùng. Giá trị có dạng ready/desired.
    • UP-TO-DATE hiển thị số replica đã được cập nhật để đạt trạng thái mong muốn.
    • AVAILABLE hiển thị số replica của ứng dụng đang khả dụng cho người dùng.
    • AGE hiển thị khoảng thời gian ứng dụng đã chạy.

    Lưu ý rằng số replica mong muốn là 3, theo trường .spec.replicas.

  3. Để xem trạng thái rollout của Deployment, chạy kubectl rollout status deployment/nginx-deployment.

    Kết quả tương tự như sau:

    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    deployment "nginx-deployment" successfully rolled out
    
  4. Chạy lại kubectl get deployments sau vài giây. Kết quả tương tự như sau:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           18s
    

    Lưu ý rằng Deployment đã tạo cả ba replica, và tất cả các replica đều đã được cập nhật (chứa Pod template mới nhất) và khả dụng.

  5. Để xem ReplicaSet (rs) được tạo bởi Deployment, chạy kubectl get rs. Kết quả tương tự như sau:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-75675f5897   3         3         3       18s
    

    Kết quả của ReplicaSet hiển thị các trường sau:

    • NAME liệt kê tên của các ReplicaSet trong namespace.
    • DESIRED hiển thị số replica mong muốn của ứng dụng, được bạn định nghĩa khi tạo Deployment. Đây là trạng thái mong muốn.
    • CURRENT hiển thị số replica đang chạy.
    • READY hiển thị số replica của ứng dụng đang sẵn sàng phục vụ người dùng.
    • AGE hiển thị khoảng thời gian ứng dụng đã chạy.

    Lưu ý rằng tên của ReplicaSet luôn có định dạng [DEPLOYMENT-NAME]-[HASH]. Tên này sẽ trở thành cơ sở để đặt tên cho các Pod được tạo ra.

    Chuỗi HASH giống với label pod-template-hash trên ReplicaSet.

  6. Để xem các label được tự động sinh ra cho mỗi Pod, chạy kubectl get pods --show-labels. Kết quả tương tự như sau:

    NAME                                READY     STATUS    RESTARTS   AGE       LABELS
    nginx-deployment-75675f5897-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    

    ReplicaSet được tạo đảm bảo rằng luôn có ba Pod nginx.

Lưu ý:

Bạn phải chỉ định một selector và label của Pod template phù hợp trong Deployment (trong trường hợp này là app: nginx).

Không để label hoặc selector trùng lặp với các controller khác (bao gồm các Deployment và StatefulSet khác). Kubernetes không ngăn bạn làm điều đó, và nếu nhiều controller có selector trùng lặp, các controller đó có thể xung đột và hoạt động không như mong đợi.

Label pod-template-hash

Chú ý:

Không được thay đổi label này.

Label pod-template-hash được Deployment controller thêm vào mỗi ReplicaSet mà một Deployment tạo ra hoặc tiếp nhận (adopt).

Label này đảm bảo rằng các ReplicaSet con của một Deployment không bị trùng lặp. Nó được sinh ra bằng cách băm PodTemplate của ReplicaSet và sử dụng giá trị băm thu được làm giá trị label, được thêm vào selector của ReplicaSet, label của Pod template, và vào mọi Pod hiện có mà ReplicaSet có thể đang quản lý.

Cập nhật một Deployment

Lưu ý:

Rollout của một Deployment được kích hoạt khi và chỉ khi Pod template của Deployment (tức là .spec.template) bị thay đổi, ví dụ khi label hoặc image container của template được cập nhật. Các cập nhật khác, chẳng hạn như scale Deployment, sẽ không kích hoạt rollout.

Làm theo các bước dưới đây để cập nhật Deployment của bạn:

  1. Hãy cập nhật các Pod nginx để sử dụng image nginx:1.16.1 thay cho image nginx:1.14.2.

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
    

    hoặc sử dụng lệnh sau:

    kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    

    trong đó deployment/nginx-deployment chỉ định Deployment, nginx chỉ định container sẽ được cập nhật và nginx:1.16.1 chỉ định image mới cùng tag của nó.

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment image updated
    

    Ngoài ra, bạn có thể edit Deployment và thay đổi .spec.template.spec.containers[0].image từ nginx:1.14.2 thành nginx:1.16.1:

    kubectl edit deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment edited
    
  2. Để xem trạng thái rollout, chạy:

    kubectl rollout status deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    

    hoặc

    deployment "nginx-deployment" successfully rolled out
    

Xem thêm chi tiết về Deployment đã được cập nhật:

  • Sau khi rollout thành công, bạn có thể xem Deployment bằng cách chạy kubectl get deployments. Kết quả tương tự như sau:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           36s
    
  • Chạy kubectl get rs để thấy rằng Deployment đã cập nhật các Pod bằng cách tạo một ReplicaSet mới và scale nó lên 3 replica, đồng thời scale ReplicaSet cũ xuống 0 replica.

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       6s
    nginx-deployment-2035384211   0         0         0       36s
    
  • Lúc này, chạy get pods sẽ chỉ hiển thị các Pod mới:

    kubectl get pods
    

    Kết quả tương tự như sau:

    NAME                                READY     STATUS    RESTARTS   AGE
    nginx-deployment-1564180365-khku8   1/1       Running   0          14s
    nginx-deployment-1564180365-nacti   1/1       Running   0          14s
    nginx-deployment-1564180365-z9gth   1/1       Running   0          14s
    

    Lần tiếp theo khi muốn cập nhật các Pod này, bạn chỉ cần cập nhật lại Pod template của Deployment.

    Deployment đảm bảo rằng chỉ một số lượng nhất định Pod bị ngừng hoạt động trong khi chúng đang được cập nhật. Theo mặc định, nó đảm bảo rằng ít nhất 75% số Pod mong muốn đang chạy (tối đa 25% không khả dụng - max unavailable).

    Deployment cũng đảm bảo rằng chỉ một số lượng nhất định Pod được tạo vượt quá số Pod mong muốn. Theo mặc định, nó đảm bảo rằng tối đa 125% số Pod mong muốn đang chạy (vượt tối đa 25% - max surge).

    Ví dụ, nếu quan sát kỹ Deployment ở trên, bạn sẽ thấy nó tạo một Pod mới trước, sau đó xóa một Pod cũ, rồi tạo thêm một Pod mới khác. Nó không dừng các Pod cũ cho đến khi có đủ số lượng Pod mới đã chạy, và không tạo Pod mới cho đến khi đủ số lượng Pod cũ đã bị dừng. Nó đảm bảo rằng ít nhất 3 Pod khả dụng và tổng cộng tối đa 4 Pod khả dụng. Với một Deployment có 4 replica, số lượng Pod sẽ nằm trong khoảng từ 3 đến 5.

  • Lấy thông tin chi tiết về Deployment của bạn:

    kubectl describe deployments
    

    Kết quả tương tự như sau:

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 30 Nov 2017 10:56:25 +0000
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=2
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
       Containers:
        nginx:
          Image:        nginx:1.16.1
          Port:         80/TCP
          Environment:  <none>
          Mounts:       <none>
        Volumes:        <none>
      Conditions:
        Type           Status  Reason
        ----           ------  ------
        Available      True    MinimumReplicasAvailable
        Progressing    True    NewReplicaSetAvailable
      OldReplicaSets:  <none>
      NewReplicaSet:   nginx-deployment-1564180365 (3/3 replicas created)
      Events:
        Type    Reason             Age   From                   Message
        ----    ------             ----  ----                   -------
        Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3
        Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
        Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0
    

    Ở đây bạn thấy rằng khi tạo Deployment lần đầu, nó đã tạo một ReplicaSet (nginx-deployment-2035384211) và scale trực tiếp lên 3 replica. Khi bạn cập nhật Deployment, nó tạo một ReplicaSet mới (nginx-deployment-1564180365), scale lên 1 và chờ Pod đó chạy. Sau đó nó scale ReplicaSet cũ xuống 2 và scale ReplicaSet mới lên 2, sao cho luôn có ít nhất 3 Pod khả dụng và tối đa 4 Pod được tạo tại mọi thời điểm. Sau đó nó tiếp tục scale up ReplicaSet mới và scale down ReplicaSet cũ, với cùng chiến lược rolling update. Cuối cùng, bạn sẽ có 3 replica khả dụng trong ReplicaSet mới, và ReplicaSet cũ được scale xuống 0.

Lưu ý:

Kubernetes không tính các Pod đang dừng khi tính số lượng availableReplicas, giá trị này phải nằm trong khoảng replicas - maxUnavailable đến replicas + maxSurge. Do đó, bạn có thể thấy có nhiều Pod hơn dự kiến trong quá trình rollout, và tổng tài nguyên mà Deployment tiêu thụ lớn hơn replicas + maxSurge cho đến khi terminationGracePeriodSeconds của các Pod đang dừng hết hạn.

Rollover (hay còn gọi là nhiều cập nhật diễn ra đồng thời)

Mỗi khi Deployment controller phát hiện một Deployment mới, một ReplicaSet sẽ được tạo để khởi chạy các Pod mong muốn. Nếu Deployment được cập nhật, ReplicaSet hiện có đang kiểm soát các Pod có label khớp với .spec.selector nhưng có template không khớp với .spec.template sẽ bị scale down. Cuối cùng, ReplicaSet mới được scale lên .spec.replicas và tất cả các ReplicaSet cũ được scale xuống 0.

Nếu bạn cập nhật một Deployment trong khi một rollout đang diễn ra, Deployment sẽ tạo một ReplicaSet mới theo bản cập nhật và bắt đầu scale up ReplicaSet đó, đồng thời rollover ReplicaSet mà nó đang scale up trước đó -- nó sẽ thêm ReplicaSet đó vào danh sách các ReplicaSet cũ và bắt đầu scale down nó.

Ví dụ, giả sử bạn tạo một Deployment để tạo 5 replica của nginx:1.14.2, nhưng sau đó cập nhật Deployment để tạo 5 replica của nginx:1.16.1, khi mới chỉ có 3 replica của nginx:1.14.2 được tạo. Trong trường hợp đó, Deployment ngay lập tức bắt đầu dừng 3 Pod nginx:1.14.2 mà nó đã tạo, và bắt đầu tạo các Pod nginx:1.16.1. Nó không đợi 5 replica của nginx:1.14.2 được tạo xong rồi mới chuyển hướng.

Cập nhật label selector

Nhìn chung, việc cập nhật label selector không được khuyến khích, và bạn nên lên kế hoạch cho các selector từ trước. Label selector của một Deployment là bất biến sau khi được tạo; không thể cập nhật nó bằng kubectl patch, kubectl edit, kubectl apply, hay các công cụ như helm upgrade.

Nếu buộc phải thay đổi selector, bạn cần xóa Deployment rồi tạo lại. Theo mặc định, việc xóa Deployment cũng xóa các Pod đang chạy của nó, gây ra downtime; hãy dùng --cascade=orphan nếu bạn cần các Pod đó tiếp tục chạy trong khi tạo lại Deployment (xem các hệ quả bên dưới). Hãy hết sức thận trọng và đảm bảo bạn hiểu rõ các hệ quả sau:

  • Thêm: Khi bạn tạo một Deployment mới với selector hẹp hơn, Deployment mới bắt buộc phải có Pod template phù hợp. Nếu bạn có một manifest sẵn có và sửa manifest đó để thu hẹp selector, bạn cần sửa metadata của Pod template bên trong Deployment đó, thêm các label mới cho khớp, nếu không API server sẽ trả về lỗi xác thực (validation error). Đây là một thay đổi không chồng lấn (non-overlapping): Deployment mới sẽ không "thấy" các Pod cũ (vốn không có label mới), khiến ReplicaSet cũ bị mồ côi (orphaned) và một ReplicaSet hoàn toàn mới được tạo ra.
  • Thay đổi giá trị: Thay đổi giá trị hiện có của một key trong selector (ví dụ, từ v1 thành v2) dẫn đến hành vi giống như khi thêm (ReplicaSet cũ bị mồ côi và được tạo lại).
  • Xóa: Xóa một key hiện có khỏi selector của Deployment không yêu cầu bất kỳ thay đổi nào đối với label của Pod template. Đây là một thay đổi chồng lấn (overlapping): selector mới, rộng hơn sẽ khớp với các Pod cũ. Các ReplicaSet hiện có không bị mồ côi, và không có ReplicaSet mới nào được tạo, nhưng lưu ý rằng label đã xóa vẫn tồn tại trong các Pod và ReplicaSet hiện có. Bạn có thể dọn dẹp điều đó bằng cách kích hoạt một rollout cho Deployment.

Rollback một Deployment

Đôi khi, bạn có thể muốn rollback một Deployment; ví dụ, khi Deployment không ổn định, chẳng hạn như bị crash liên tục (crash looping). Theo mặc định, toàn bộ lịch sử rollout của Deployment được lưu giữ trong hệ thống để bạn có thể rollback bất cứ lúc nào (bạn có thể thay đổi điều này bằng cách sửa giới hạn lịch sử revision - revision history limit).

Lưu ý:

Revision của một Deployment được tạo khi rollout của Deployment được kích hoạt. Điều này có nghĩa là revision mới được tạo khi và chỉ khi Pod template (.spec.template) của Deployment bị thay đổi, ví dụ khi bạn cập nhật label hoặc image container của template. Các cập nhật khác, chẳng hạn như scale Deployment, không tạo ra revision mới của Deployment, nhờ đó bạn có thể thực hiện đồng thời việc scale thủ công hoặc tự động. Điều này có nghĩa là khi bạn rollback về một revision trước đó, chỉ phần Pod template của Deployment được rollback.
  • Giả sử bạn gõ nhầm khi cập nhật Deployment, đặt tên image là nginx:1.161 thay vì nginx:1.16.1:

    kubectl set image deployment/nginx-deployment nginx=nginx:1.161
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment image updated
    
  • Rollout bị kẹt. Bạn có thể xác minh điều này bằng cách kiểm tra trạng thái rollout:

    kubectl rollout status deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
    
  • Nhấn Ctrl-C để dừng theo dõi trạng thái rollout ở trên. Để biết thêm thông tin về các rollout bị kẹt, đọc thêm tại đây.

  • Bạn thấy rằng số replica cũ (cộng số replica từ nginx-deployment-1564180365 và nginx-deployment-2035384211) là 3, và số replica mới (từ nginx-deployment-3066724191) là 1.

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       25s
    nginx-deployment-2035384211   0         0         0       36s
    nginx-deployment-3066724191   1         1         0       6s
    
  • Xem các Pod đã được tạo, bạn sẽ thấy 1 Pod được tạo bởi ReplicaSet mới bị kẹt trong vòng lặp kéo image (image pull loop).

    kubectl get pods
    

    Kết quả tương tự như sau:

    NAME                                READY     STATUS             RESTARTS   AGE
    nginx-deployment-1564180365-70iae   1/1       Running            0          25s
    nginx-deployment-1564180365-jbqqo   1/1       Running            0          25s
    nginx-deployment-1564180365-hysrc   1/1       Running            0          25s
    nginx-deployment-3066724191-08mng   0/1       ImagePullBackOff   0          6s
    

    Lưu ý:

    Deployment controller tự động dừng rollout lỗi và ngừng scale up ReplicaSet mới. Điều này phụ thuộc vào các tham số rollingUpdate (cụ thể là maxUnavailable) mà bạn đã chỉ định. Theo mặc định, Kubernetes đặt giá trị này là 25%.
  • Lấy mô tả của Deployment:

    kubectl describe deployment
    

    Kết quả tương tự như sau:

    Name:           nginx-deployment
    Namespace:      default
    CreationTimestamp:  Tue, 15 Mar 2016 14:48:04 -0700
    Labels:         app=nginx
    Selector:       app=nginx
    Replicas:       3 desired | 1 updated | 4 total | 3 available | 1 unavailable
    StrategyType:       RollingUpdate
    MinReadySeconds:    0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.161
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    ReplicaSetUpdated
    OldReplicaSets:     nginx-deployment-1564180365 (3/3 replicas created)
    NewReplicaSet:      nginx-deployment-3066724191 (1/1 replicas created)
    Events:
      FirstSeen LastSeen    Count   From                    SubObjectPath   Type        Reason              Message
      --------- --------    -----   ----                    -------------   --------    ------              -------
      1m        1m          1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
      21s       21s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 1
      21s       21s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 1
    

    Để khắc phục điều này, bạn cần rollback về một revision ổn định trước đó của Deployment.

Kiểm tra lịch sử rollout của một Deployment

Làm theo các bước dưới đây để kiểm tra lịch sử rollout:

  1. Đầu tiên, kiểm tra các revision của Deployment này:

    kubectl rollout history deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployments "nginx-deployment"
    REVISION    CHANGE-CAUSE
    1           <none>
    2           <none>
    3           <none>
    

    CHANGE-CAUSE được sao chép từ annotation kubernetes.io/change-cause của Deployment sang các revision của nó khi chúng được tạo. Bạn có thể chỉ định thông điệp CHANGE-CAUSE bằng cách:

    • Gắn annotation cho Deployment bằng kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"
    • Sửa manifest của tài nguyên một cách thủ công.
    • Sử dụng công cụ tự động đặt annotation.

    Lưu ý:

    Trong các phiên bản Kubernetes cũ hơn, bạn có thể dùng cờ --record với các lệnh kubectl để tự động điền trường CHANGE-CAUSE. Cờ này không còn được hỗ trợ (deprecated) và sẽ bị loại bỏ trong một bản phát hành tương lai.
  2. Để xem chi tiết của từng revision, chạy:

    kubectl rollout history deployment/nginx-deployment --revision=2
    

    Kết quả tương tự như sau:

    deployments "nginx-deployment" revision 2
      Labels:       app=nginx
              pod-template-hash=1159050644
      Containers:
       nginx:
        Image:      nginx:1.16.1
        Port:       80/TCP
         QoS Tier:
            cpu:      BestEffort
            memory:   BestEffort
        Environment Variables:      <none>
      No volumes.
    

Rollback về revision trước đó

Làm theo các bước dưới đây để rollback Deployment từ phiên bản hiện tại về phiên bản trước đó, tức là phiên bản 2.

  1. Giả sử bây giờ bạn quyết định hoàn tác rollout hiện tại và rollback về revision trước đó:

    kubectl rollout undo deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment rolled back
    

    Ngoài ra, bạn có thể rollback về một revision cụ thể bằng cách chỉ định nó với --to-revision:

    kubectl rollout undo deployment/nginx-deployment --to-revision=2
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment rolled back
    

    Để biết thêm chi tiết về các lệnh liên quan đến rollout, đọc kubectl rollout.

    Deployment giờ đã được rollback về một revision ổn định trước đó. Như bạn thấy, một sự kiện DeploymentRollback cho việc rollback về revision 2 được tạo ra từ Deployment controller.

  2. Để kiểm tra xem việc rollback đã thành công và Deployment đang chạy như mong đợi hay chưa, chạy:

    kubectl get deployment nginx-deployment
    

    Kết quả tương tự như sau:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           30m
    
  3. Lấy mô tả của Deployment:

    kubectl describe deployment nginx-deployment
    

    Kết quả tương tự như sau:

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Sun, 02 Sep 2018 18:17:55 -0500
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=4
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.16.1
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   nginx-deployment-c4747d96c (3/3 replicas created)
    Events:
      Type    Reason              Age   From                   Message
      ----    ------              ----  ----                   -------
      Normal  ScalingReplicaSet   12m   deployment-controller  Scaled up replica set nginx-deployment-75675f5897 to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 0
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-595696685f to 1
      Normal  DeploymentRollback  15s   deployment-controller  Rolled back deployment "nginx-deployment" to revision 2
      Normal  ScalingReplicaSet   15s   deployment-controller  Scaled down replica set nginx-deployment-595696685f to 0
    

Scale một Deployment

Bạn có thể scale một Deployment bằng lệnh sau:

kubectl scale deployment/nginx-deployment --replicas=10

Kết quả tương tự như sau:

deployment.apps/nginx-deployment scaled

Giả sử horizontal Pod autoscaling đã được bật trong cluster của bạn, bạn có thể thiết lập một autoscaler cho Deployment và chọn số lượng Pod tối thiểu và tối đa mà bạn muốn chạy dựa trên mức sử dụng CPU của các Pod hiện có.

kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80%

Kết quả tương tự như sau:

deployment.apps/nginx-deployment scaled

Scale theo tỷ lệ

Các Deployment kiểu RollingUpdate hỗ trợ chạy nhiều phiên bản của một ứng dụng cùng một lúc. Khi bạn hoặc một autoscaler scale một Deployment RollingUpdate đang ở giữa quá trình rollout (đang diễn ra hoặc đang tạm dừng), Deployment controller sẽ phân bổ cân đối các replica bổ sung vào các ReplicaSet đang hoạt động (các ReplicaSet có Pod) để giảm thiểu rủi ro. Điều này được gọi là scale theo tỷ lệ (proportional scaling).

Ví dụ, bạn đang chạy một Deployment với 10 replica, maxSurge=3, và maxUnavailable=2.

  • Đảm bảo rằng 10 replica trong Deployment của bạn đang chạy.

    kubectl get deploy
    

    Kết quả tương tự như sau:

    NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment     10        10        10           10          50s
    
  • Bạn cập nhật sang một image mới mà không thể phân giải được từ bên trong cluster.

    kubectl set image deployment/nginx-deployment nginx=nginx:sometag
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment image updated
    
  • Việc cập nhật image khởi động một rollout mới với ReplicaSet nginx-deployment-1989198191, nhưng rollout này bị chặn do yêu cầu maxUnavailable mà bạn đã đề cập ở trên. Kiểm tra trạng thái rollout:

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME                          DESIRED   CURRENT   READY     AGE
    nginx-deployment-1989198191   5         5         0         9s
    nginx-deployment-618515232    8         8         8         1m
    
  • Sau đó, một yêu cầu scale mới cho Deployment xuất hiện. Autoscaler tăng số replica của Deployment lên 15. Deployment controller cần quyết định nơi để thêm 5 replica mới này. Nếu bạn không sử dụng scale theo tỷ lệ, cả 5 replica sẽ được thêm vào ReplicaSet mới. Với scale theo tỷ lệ, bạn phân bổ các replica bổ sung cho tất cả các ReplicaSet. Phần lớn hơn được chia cho các ReplicaSet có nhiều replica nhất và phần nhỏ hơn được chia cho các ReplicaSet có ít replica hơn. Phần dư sẽ được thêm vào ReplicaSet có nhiều replica nhất. Các ReplicaSet có 0 replica sẽ không được scale up.

Trong ví dụ trên, 3 replica được thêm vào ReplicaSet cũ và 2 replica được thêm vào ReplicaSet mới. Quá trình rollout cuối cùng sẽ chuyển tất cả các replica sang ReplicaSet mới, với giả định các replica mới hoạt động bình thường (healthy). Để xác nhận điều này, chạy:

kubectl get deploy

Kết quả tương tự như sau:

NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment     15        18        7            8           7m

Trạng thái rollout xác nhận cách các replica được thêm vào mỗi ReplicaSet.

kubectl get rs

Kết quả tương tự như sau:

NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-1989198191   7         7         0         7m
nginx-deployment-618515232    11        11        11        7m

Tạm dừng và tiếp tục rollout của một Deployment

Khi bạn cập nhật một Deployment, hoặc dự định cập nhật, bạn có thể tạm dừng các rollout của Deployment đó trước khi kích hoạt một hoặc nhiều cập nhật. Khi bạn đã sẵn sàng áp dụng các thay đổi đó, bạn tiếp tục các rollout cho Deployment. Cách làm này cho phép bạn áp dụng nhiều bản sửa lỗi trong khoảng thời gian giữa lúc tạm dừng và tiếp tục mà không kích hoạt các rollout không cần thiết.

  • Ví dụ, với một Deployment vừa được tạo:

    Lấy thông tin chi tiết của Deployment:

    kubectl get deploy
    

    Kết quả tương tự như sau:

    NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx     3         3         3            3           1m
    

    Lấy trạng thái rollout:

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         1m
    
  • Tạm dừng bằng cách chạy lệnh sau:

    kubectl rollout pause deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment paused
    
  • Sau đó cập nhật image của Deployment:

    kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment image updated
    
  • Lưu ý rằng không có rollout mới nào được bắt đầu:

    kubectl rollout history deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployments "nginx"
    REVISION  CHANGE-CAUSE
    1   <none>
    
  • Lấy trạng thái rollout để xác minh rằng ReplicaSet hiện có không thay đổi:

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         2m
    
  • Bạn có thể thực hiện bao nhiêu cập nhật tùy thích, ví dụ, cập nhật các tài nguyên sẽ được sử dụng:

    kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment resource requirements updated
    

    Trạng thái ban đầu của Deployment trước khi tạm dừng rollout vẫn tiếp tục hoạt động, nhưng các cập nhật mới cho Deployment sẽ không có tác dụng chừng nào rollout của Deployment còn đang bị tạm dừng.

  • Cuối cùng, tiếp tục rollout của Deployment và quan sát một ReplicaSet mới được tạo ra với tất cả các cập nhật mới:

    kubectl rollout resume deployment/nginx-deployment
    

    Kết quả tương tự như sau:

    deployment.apps/nginx-deployment resumed
    
  • Theo dõi (watch) trạng thái của rollout cho đến khi hoàn tất.

    kubectl get rs --watch
    

    Kết quả tương tự như sau:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   2         2         2         2m
    nginx-3926361531   2         2         0         6s
    nginx-3926361531   2         2         1         18s
    nginx-2142116321   1         2         2         2m
    nginx-2142116321   1         2         2         2m
    nginx-3926361531   3         2         1         18s
    nginx-3926361531   3         2         1         18s
    nginx-2142116321   1         1         1         2m
    nginx-3926361531   3         3         1         18s
    nginx-3926361531   3         3         2         19s
    nginx-2142116321   0         1         1         2m
    nginx-2142116321   0         1         1         2m
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         20s
    
  • Lấy trạng thái của rollout mới nhất:

    kubectl get rs
    

    Kết quả tương tự như sau:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         28s
    

Lưu ý:

Bạn không thể rollback một Deployment đang bị tạm dừng cho đến khi bạn tiếp tục (resume) nó.

Trạng thái của Deployment

Một Deployment trải qua nhiều trạng thái khác nhau trong vòng đời của nó. Nó có thể đang tiến triển trong khi rollout một ReplicaSet mới, có thể hoàn tất, hoặc có thể không tiến triển được.

Deployment đang tiến triển

Kubernetes đánh dấu một Deployment là đang tiến triển (progressing) khi một trong các tác vụ sau được thực hiện:

  • Deployment tạo một ReplicaSet mới.
  • Deployment đang scale up ReplicaSet mới nhất của nó.
  • Deployment đang scale down (các) ReplicaSet cũ hơn của nó.
  • Các Pod mới trở nên ready hoặc available (ready trong ít nhất MinReadySeconds).

Khi rollout chuyển sang trạng thái “progressing”, Deployment controller thêm một condition với các thuộc tính sau vào .status.conditions của Deployment:

  • type: Progressing
  • status: "True"
  • reason: NewReplicaSetCreated | reason: FoundNewReplicaSet | reason: ReplicaSetUpdated

Bạn có thể theo dõi tiến trình của một Deployment bằng cách sử dụng kubectl rollout status.

Deployment hoàn tất

Kubernetes đánh dấu một Deployment là hoàn tất (complete) khi nó có các đặc điểm sau:

  • Tất cả các replica liên kết với Deployment đã được cập nhật lên phiên bản mới nhất mà bạn chỉ định, nghĩa là mọi cập nhật bạn yêu cầu đều đã được hoàn thành.
  • Tất cả các replica liên kết với Deployment đều sẵn sàng (available).
  • Không có replica cũ nào của Deployment đang chạy.

Khi rollout chuyển sang trạng thái “complete”, Deployment controller đặt một condition với các thuộc tính sau vào .status.conditions của Deployment:

  • type: Progressing
  • status: "True"
  • reason: NewReplicaSetAvailable

Condition Progressing này sẽ giữ giá trị trạng thái "True" cho đến khi một rollout mới được khởi tạo. Condition này vẫn giữ nguyên ngay cả khi tính khả dụng của các replica thay đổi (điều này thay vào đó sẽ ảnh hưởng đến condition Available).

Bạn có thể kiểm tra xem một Deployment đã hoàn tất hay chưa bằng cách sử dụng kubectl rollout status. Nếu rollout hoàn tất thành công, kubectl rollout status trả về exit code bằng 0.

kubectl rollout status deployment/nginx-deployment

Kết quả tương tự như sau:

Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out

và exit status của kubectl rollout là 0 (thành công):

echo $?
0

Deployment thất bại

Deployment của bạn có thể bị kẹt khi cố gắng triển khai ReplicaSet mới nhất mà không bao giờ hoàn tất. Điều này có thể xảy ra do một số yếu tố sau:

  • Không đủ quota
  • Readiness probe thất bại
  • Lỗi khi kéo image (image pull)
  • Không đủ quyền
  • Limit range
  • Cấu hình runtime của ứng dụng bị sai

Một cách để phát hiện tình trạng này là chỉ định một tham số thời hạn (deadline) trong spec của Deployment: (.spec.progressDeadlineSeconds). .spec.progressDeadlineSeconds biểu thị số giây mà Deployment controller chờ trước khi báo hiệu (trong trạng thái của Deployment) rằng tiến trình của Deployment đã bị đình trệ.

Lệnh kubectl sau đây thiết lập spec với progressDeadlineSeconds để khiến controller báo cáo việc rollout của Deployment không có tiến triển sau 10 phút:

kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'

Kết quả tương tự như sau:

deployment.apps/nginx-deployment patched

Khi vượt quá thời hạn, Deployment controller sẽ thêm một DeploymentCondition với các thuộc tính sau vào .status.conditions của Deployment:

  • type: Progressing
  • status: "False"
  • reason: ProgressDeadlineExceeded

Condition này cũng có thể thất bại sớm và khi đó được đặt giá trị trạng thái "False" vì các lý do như ReplicaSetCreateError. Ngoài ra, thời hạn sẽ không còn được tính đến khi rollout của Deployment đã hoàn tất.

Xem Kubernetes API conventions để biết thêm thông tin về các status condition.

Lưu ý:

Kubernetes không thực hiện bất kỳ hành động nào đối với một Deployment bị đình trệ ngoài việc báo cáo một status condition với reason: ProgressDeadlineExceeded. Các orchestrator cấp cao hơn có thể tận dụng điều này và hành động tương ứng, ví dụ như rollback Deployment về phiên bản trước đó.

Lưu ý:

Nếu bạn tạm dừng rollout của một Deployment, Kubernetes không kiểm tra tiến trình so với thời hạn bạn đã chỉ định. Bạn có thể an toàn tạm dừng rollout của một Deployment giữa chừng rồi tiếp tục mà không kích hoạt condition vượt quá thời hạn.

Bạn có thể gặp phải các lỗi tạm thời với Deployment, do bạn đặt timeout quá thấp hoặc do bất kỳ loại lỗi nào khác có thể được coi là tạm thời. Ví dụ, giả sử bạn không đủ quota. Nếu bạn describe Deployment, bạn sẽ thấy phần sau:

kubectl describe deployment nginx-deployment

Kết quả tương tự như sau:

<...>
Conditions:
  Type            Status  Reason
  ----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     True    ReplicaSetUpdated
  ReplicaFailure  True    FailedCreate
<...>

Nếu bạn chạy kubectl get deployment nginx-deployment -o yaml, trạng thái của Deployment tương tự như sau:

status:
  availableReplicas: 2
  conditions:
  - lastTransitionTime: 2016-10-04T12:25:39Z
    lastUpdateTime: 2016-10-04T12:25:39Z
    message: Replica set "nginx-deployment-4262182780" is progressing.
    reason: ReplicaSetUpdated
    status: "True"
    type: Progressing
  - lastTransitionTime: 2016-10-04T12:25:42Z
    lastUpdateTime: 2016-10-04T12:25:42Z
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  - lastTransitionTime: 2016-10-04T12:25:39Z
    lastUpdateTime: 2016-10-04T12:25:39Z
    message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
      object-counts, requested: pods=1, used: pods=3, limited: pods=2'
    reason: FailedCreate
    status: "True"
    type: ReplicaFailure
  observedGeneration: 3
  replicas: 2
  unavailableReplicas: 2

Cuối cùng, khi vượt quá thời hạn tiến trình của Deployment, Kubernetes sẽ cập nhật trạng thái và lý do (reason) của condition Progressing:

Conditions:
  Type            Status  Reason
  ----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     False   ProgressDeadlineExceeded
  ReplicaFailure  True    FailedCreate

Bạn có thể giải quyết vấn đề thiếu quota bằng cách scale down Deployment, scale down các controller khác mà bạn đang chạy, hoặc tăng quota trong namespace của bạn. Nếu bạn đáp ứng các điều kiện về quota và sau đó Deployment controller hoàn tất rollout của Deployment, bạn sẽ thấy trạng thái của Deployment được cập nhật với một condition thành công (status: "True" và reason: NewReplicaSetAvailable).

Conditions:
  Type          Status  Reason
  ----          ------  ------
  Available     True    MinimumReplicasAvailable
  Progressing   True    NewReplicaSetAvailable

type: Available với status: "True" nghĩa là Deployment của bạn đạt mức khả dụng tối thiểu (minimum availability). Mức khả dụng tối thiểu được quyết định bởi các tham số được chỉ định trong chiến lược triển khai (deployment strategy). type: Progressing với status: "True" nghĩa là Deployment của bạn hoặc đang ở giữa quá trình rollout và đang tiến triển, hoặc đã hoàn tất tiến trình thành công và số lượng replica mới tối thiểu cần thiết đã sẵn sàng (xem Reason của condition để biết chi tiết - trong trường hợp của chúng ta, reason: NewReplicaSetAvailable nghĩa là Deployment đã hoàn tất).

Bạn có thể kiểm tra xem một Deployment có bị thất bại trong việc tiến triển hay không bằng cách sử dụng kubectl rollout status. kubectl rollout status trả về exit code khác 0 nếu Deployment đã vượt quá thời hạn tiến trình.

kubectl rollout status deployment/nginx-deployment

Kết quả tương tự như sau:

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline

và exit status của kubectl rollout là 1 (cho biết có lỗi):

echo $?
1

Thao tác trên một Deployment thất bại

Tất cả các thao tác áp dụng cho một Deployment hoàn tất cũng áp dụng cho một Deployment thất bại. Bạn có thể scale up/down, rollback về một revision trước đó, hoặc thậm chí tạm dừng nó nếu bạn cần áp dụng nhiều điều chỉnh cho Pod template của Deployment.

Chính sách dọn dẹp

Bạn có thể đặt trường .spec.revisionHistoryLimit trong một Deployment để chỉ định số lượng ReplicaSet cũ của Deployment này mà bạn muốn giữ lại. Phần còn lại sẽ được thu gom rác (garbage-collected) ở chế độ nền. Theo mặc định, giá trị này là 10.

Lưu ý:

Việc đặt tường minh trường này bằng 0 sẽ dẫn đến việc dọn sạch toàn bộ lịch sử của Deployment, do đó Deployment đó sẽ không thể rollback.

Việc dọn dẹp chỉ bắt đầu sau khi Deployment đạt trạng thái hoàn tất. Nếu bạn đặt .spec.revisionHistoryLimit bằng 0, mọi rollout vẫn kích hoạt việc tạo một ReplicaSet mới trước khi Kubernetes xóa ReplicaSet cũ.

Ngay cả khi giới hạn lịch sử revision khác 0, bạn vẫn có thể có nhiều ReplicaSet hơn giới hạn mà bạn cấu hình. Ví dụ, nếu các Pod bị crash liên tục (crash looping) và có nhiều sự kiện rolling update được kích hoạt theo thời gian, bạn có thể có nhiều ReplicaSet hơn .spec.revisionHistoryLimit vì Deployment không bao giờ đạt trạng thái hoàn tất.

Canary deployment

Nếu bạn muốn rollout các bản phát hành (release) cho một nhóm nhỏ người dùng hoặc máy chủ bằng Deployment, bạn có thể tạo nhiều Deployment, mỗi Deployment tương ứng với một bản phát hành, theo mô hình canary được mô tả trong quản lý tài nguyên.

Để tìm hiểu chi tiết, hãy làm theo hướng dẫn Triển khai một bản phát hành bằng Canary Deployment.

Viết spec cho Deployment

Giống như mọi cấu hình Kubernetes khác, một Deployment cần các trường .apiVersion, .kind và .metadata. Để biết thông tin chung về cách làm việc với các file cấu hình, xem triển khai ứng dụng, cấu hình container, và sử dụng kubectl để quản lý tài nguyên.

Khi control plane tạo các Pod mới cho một Deployment, .metadata.name của Deployment là một phần cơ sở để đặt tên cho các Pod đó. Tên của Deployment phải là một giá trị DNS subdomain hợp lệ, nhưng điều này có thể gây ra kết quả không mong muốn cho hostname của Pod. Để tương thích tốt nhất, tên nên tuân theo các quy tắc chặt chẽ hơn của một DNS label.

Một Deployment cũng cần có phần .spec.

Pod Template

.spec.template và .spec.selector là các trường bắt buộc duy nhất của .spec.

.spec.template là một Pod template. Nó có schema giống hệt một Pod, ngoại trừ việc nó được lồng bên trong và không có apiVersion hay kind.

Ngoài các trường bắt buộc của một Pod, Pod template trong một Deployment phải chỉ định các label và một restart policy phù hợp. Với label, hãy đảm bảo không trùng lặp với các controller khác. Xem selector.

Chỉ cho phép .spec.template.spec.restartPolicy bằng Always, đây cũng là giá trị mặc định nếu không được chỉ định.

Replicas

.spec.replicas là một trường tùy chọn, chỉ định số lượng Pod mong muốn. Giá trị mặc định là 1.

Nếu bạn scale một Deployment thủ công, ví dụ qua kubectl scale deployment deployment --replicas=X, rồi sau đó cập nhật Deployment đó dựa trên một manifest (ví dụ: bằng cách chạy kubectl apply -f deployment.yaml), thì việc áp dụng manifest đó sẽ ghi đè lên việc scale thủ công mà bạn đã thực hiện trước đó.

Nếu một HorizontalPodAutoscaler (hoặc bất kỳ API tương tự nào cho horizontal scaling) đang quản lý việc scale cho một Deployment, đừng đặt .spec.replicas.

Thay vào đó, hãy để control plane của Kubernetes tự động quản lý trường .spec.replicas.

Selector

.spec.selector là một trường bắt buộc, chỉ định một label selector cho các Pod mà Deployment này nhắm tới.

.spec.selector phải khớp với .spec.template.metadata.labels, nếu không sẽ bị API từ chối.

Trong phiên bản API apps/v1, .spec.selector và .metadata.labels không mặc định lấy giá trị của .spec.template.metadata.labels nếu không được đặt. Vì vậy chúng phải được đặt một cách tường minh. Cũng lưu ý rằng trong apps/v1, .spec.selector là bất biến sau khi Deployment được tạo.

Một Deployment có thể dừng (terminate) các Pod có label khớp với selector nếu template của chúng khác với .spec.template hoặc nếu tổng số lượng các Pod như vậy vượt quá .spec.replicas. Nó sẽ khởi chạy các Pod mới với .spec.template nếu số lượng Pod ít hơn số lượng mong muốn.

Lưu ý:

Bạn không nên tạo các Pod khác có label khớp với selector này, dù là trực tiếp, bằng cách tạo một Deployment khác, hay bằng cách tạo một controller khác như ReplicaSet hoặc ReplicationController. Nếu bạn làm vậy, Deployment đầu tiên sẽ cho rằng chính nó đã tạo ra các Pod khác này. Kubernetes không ngăn bạn làm điều này.

Nếu bạn có nhiều controller có selector trùng lặp nhau, các controller đó sẽ tranh chấp với nhau và sẽ không hoạt động đúng.

Strategy

.spec.strategy chỉ định chiến lược được sử dụng để thay thế các Pod cũ bằng các Pod mới. .spec.strategy.type có thể là "Recreate" hoặc "RollingUpdate". "RollingUpdate" là giá trị mặc định.

Recreate Deployment

Khi .spec.strategy.type==Recreate, tất cả các Pod hiện có sẽ bị dừng trước khi các Pod mới được tạo.

Lưu ý:

Điều này chỉ đảm bảo các Pod bị dừng trước khi tạo Pod mới đối với các lần nâng cấp. Nếu bạn nâng cấp một Deployment, tất cả các Pod của revision cũ sẽ bị dừng ngay lập tức. Hệ thống chờ việc xóa thành công rồi mới tạo bất kỳ Pod nào của revision mới. Nếu bạn xóa thủ công một Pod, vòng đời của nó do ReplicaSet kiểm soát và Pod thay thế sẽ được tạo ngay lập tức (ngay cả khi Pod cũ vẫn đang ở trạng thái Terminating). Nếu bạn cần đảm bảo "tối đa" (at most) cho các Pod của mình, bạn nên cân nhắc sử dụng một StatefulSet.

Rolling Update Deployment

Deployment cập nhật các Pod theo kiểu rolling update (scale down dần các ReplicaSet cũ và scale up ReplicaSet mới) khi .spec.strategy.type==RollingUpdate. Bạn có thể chỉ định maxUnavailable và maxSurge để kiểm soát quá trình rolling update.

Max Unavailable

.spec.strategy.rollingUpdate.maxUnavailable là một trường tùy chọn, chỉ định số lượng Pod tối đa có thể không khả dụng (unavailable) trong quá trình cập nhật. Giá trị có thể là một số tuyệt đối (ví dụ: 5) hoặc tỷ lệ phần trăm của số Pod mong muốn (ví dụ: 10%). Số tuyệt đối được tính từ tỷ lệ phần trăm bằng cách làm tròn xuống. Giá trị này không thể bằng 0 nếu .spec.strategy.rollingUpdate.maxSurge bằng 0. Giá trị mặc định là 25%.

Ví dụ, khi giá trị này được đặt là 30%, ReplicaSet cũ có thể được scale down xuống còn 70% số Pod mong muốn ngay khi rolling update bắt đầu. Khi các Pod mới đã sẵn sàng, ReplicaSet cũ có thể được scale down thêm, tiếp theo là scale up ReplicaSet mới, đảm bảo rằng tổng số Pod khả dụng tại mọi thời điểm trong quá trình cập nhật luôn ít nhất bằng 70% số Pod mong muốn.

Max Surge

.spec.strategy.rollingUpdate.maxSurge là một trường tùy chọn, chỉ định số lượng Pod tối đa có thể được tạo vượt quá số lượng Pod mong muốn. Giá trị có thể là một số tuyệt đối (ví dụ: 5) hoặc tỷ lệ phần trăm của số Pod mong muốn (ví dụ: 10%). Giá trị này không thể bằng 0 nếu maxUnavailable bằng 0. Số tuyệt đối được tính từ tỷ lệ phần trăm bằng cách làm tròn lên. Giá trị mặc định là 25%.

Ví dụ, khi giá trị này được đặt là 30%, ReplicaSet mới có thể được scale up ngay khi rolling update bắt đầu, sao cho tổng số Pod cũ và mới không vượt quá 130% số Pod mong muốn. Khi các Pod cũ đã bị dừng, ReplicaSet mới có thể được scale up thêm, đảm bảo rằng tổng số Pod đang chạy tại mọi thời điểm trong quá trình cập nhật tối đa là 130% số Pod mong muốn.

Dưới đây là một số ví dụ về Rolling Update Deployment sử dụng maxUnavailable và maxSurge:

apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxUnavailable: 1
apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxSurge: 1
apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxSurge: 1
     maxUnavailable: 1

Progress Deadline Seconds

.spec.progressDeadlineSeconds là một trường tùy chọn, chỉ định số giây bạn muốn chờ Deployment tiến triển trước khi hệ thống báo cáo rằng Deployment đã không tiến triển được - được thể hiện dưới dạng một condition với type: Progressing, status: "False". và reason: ProgressDeadlineExceeded trong trạng thái của tài nguyên. Deployment controller sẽ tiếp tục thử lại Deployment. Giá trị mặc định là 600.

Nếu được chỉ định, trường này cần lớn hơn .spec.minReadySeconds.

Min Ready Seconds

.spec.minReadySeconds là một trường tùy chọn, chỉ định số giây tối thiểu mà một Pod mới được tạo phải ở trạng thái ready mà không có container nào bị crash, để được coi là available (khả dụng). Giá trị mặc định là 0 (Pod sẽ được coi là available ngay khi nó ready). Để tìm hiểu thêm về thời điểm một Pod được coi là ready, xem Container Probes.

Các Pod đang dừng (terminating)

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

Bạn chỉ có thể thấy các Pod đang dừng nếu DeploymentReplicaSetTerminatingReplicas feature gate được bật trên API server và trên kube-controller-manager

Các Pod chuyển sang trạng thái đang dừng do bị xóa hoặc do scale down có thể mất nhiều thời gian để dừng hẳn, và có thể tiêu tốn thêm tài nguyên trong khoảng thời gian đó. Do đó, tổng số Pod có thể tạm thời vượt quá .spec.replicas. Bạn có thể theo dõi các Pod đang dừng bằng trường .status.terminatingReplicas của Deployment.

Revision History Limit

Lịch sử revision của một Deployment được lưu trữ trong các ReplicaSet mà nó kiểm soát.

.spec.revisionHistoryLimit là một trường tùy chọn, chỉ định số lượng ReplicaSet cũ được giữ lại để cho phép rollback. Các ReplicaSet cũ này tiêu tốn tài nguyên trong etcd và làm rối kết quả của kubectl get rs. Cấu hình của mỗi revision Deployment được lưu trữ trong các ReplicaSet của nó; do đó, một khi ReplicaSet cũ bị xóa, bạn sẽ mất khả năng rollback về revision đó của Deployment. Theo mặc định, 10 ReplicaSet cũ sẽ được giữ lại, tuy nhiên giá trị lý tưởng của trường này phụ thuộc vào tần suất và độ ổn định của các Deployment mới.

Cụ thể hơn, việc đặt trường này bằng 0 có nghĩa là tất cả các ReplicaSet cũ có 0 replica sẽ bị dọn dẹp. Trong trường hợp này, không thể hoàn tác (undo) một rollout mới của Deployment, vì lịch sử revision của nó đã bị dọn dẹp.

Paused

.spec.paused là một trường boolean tùy chọn dùng để tạm dừng và tiếp tục một Deployment. Điểm khác biệt duy nhất giữa một Deployment đang tạm dừng và một Deployment không bị tạm dừng là mọi thay đổi đối với PodTemplateSpec của Deployment đang tạm dừng sẽ không kích hoạt rollout mới chừng nào nó còn đang bị tạm dừng. Theo mặc định, một Deployment không bị tạm dừng khi được tạo.

Tiếp theo là gì

3.2 - Service

Cung cấp một ứng dụng đang chạy trong cluster của bạn qua một endpoint duy nhất hướng ra bên ngoài, ngay cả khi workload được chia thành nhiều backend.

Trong Kubernetes, Service là một cách để thể hiện ứng dụng đang chạy trong một tập các Pods dưới dạng dịch vụ mạng.

Một mục tiêu chính của Service trong Kubernetes là bạn không cần sửa đổi ứng dụng hiện có để dùng một cơ chế service discovery xa lạ. Bạn có thể chạy code trong các Pod, dù đó là code được thiết kế cho thế giới cloud-native hay một ứng dụng cũ mà bạn đã container hóa. Bạn dùng Service để cung cấp tập Pod đó trên mạng, nhờ vậy các client có thể tương tác với nó.

Nếu bạn dùng một Deployment để chạy ứng dụng, Deployment đó có thể tạo và hủy các Pod một cách linh hoạt. Từ thời điểm này sang thời điểm khác, bạn không biết có bao nhiêu Pod trong số đó đang hoạt động và khỏe mạnh; thậm chí bạn có thể không biết tên của các Pod khỏe mạnh đó. Các Pod trong Kubernetes được tạo và hủy để khớp với trạng thái mong muốn của cluster. Pod là tài nguyên tạm thời (bạn không nên kỳ vọng rằng một Pod riêng lẻ là đáng tin cậy và bền vững).

Mỗi Pod có địa chỉ IP riêng (Kubernetes yêu cầu các plugin mạng đảm bảo điều này). Với một Deployment nhất định trong cluster, tập Pod đang chạy tại một thời điểm có thể khác với tập Pod chạy ứng dụng đó ngay sau đó.

Điều này dẫn đến một vấn đề: nếu một tập Pod (gọi là "backend") cung cấp chức năng cho các Pod khác (gọi là "frontend") bên trong cluster, làm thế nào để các frontend tìm ra và theo dõi được địa chỉ IP cần kết nối tới, để frontend có thể sử dụng phần backend của workload?

Đó là lúc Service xuất hiện.

Service trong Kubernetes

Service API, một phần của Kubernetes, là một lớp trừu tượng giúp bạn cung cấp các nhóm Pod qua mạng. Mỗi đối tượng Service định nghĩa một tập logic các endpoint (thường các endpoint này là Pod) cùng với một chính sách về cách cho phép truy cập các pod đó.

Ví dụ, hãy xem xét một backend xử lý hình ảnh stateless đang chạy với 3 bản sao. Các bản sao đó có thể thay thế cho nhau—frontend không quan tâm chúng dùng backend nào. Mặc dù các Pod thực tế tạo nên tập backend có thể thay đổi, các client frontend không cần biết điều đó, cũng không cần tự theo dõi tập backend.

Lớp trừu tượng Service cho phép sự tách rời (decoupling) này.

Canary deployment là một trường hợp sử dụng phổ biến của Service. Để tìm hiểu những gì cần làm, hãy làm theo hướng dẫn Triển khai một bản phát hành bằng Canary Deployment.

Tập Pod mà một Service nhắm tới thường được xác định bởi một selector mà bạn định nghĩa. Để tìm hiểu các cách khác để định nghĩa endpoint cho Service, xem Service không có selector.

Nếu workload của bạn giao tiếp qua HTTP, bạn có thể chọn dùng một Ingress để kiểm soát cách lưu lượng web đến được workload đó. Ingress không phải là một loại Service, nhưng nó đóng vai trò điểm vào cho cluster của bạn. Ingress cho phép bạn gom các quy tắc định tuyến vào một tài nguyên duy nhất, để bạn có thể cung cấp nhiều thành phần của workload, chạy riêng biệt trong cluster, phía sau một listener duy nhất.

API Gateway dành cho Kubernetes cung cấp thêm các khả năng ngoài Ingress và Service. Bạn có thể thêm Gateway vào cluster - đây là một họ các API mở rộng, được triển khai bằng CustomResourceDefinition - rồi dùng chúng để cấu hình quyền truy cập tới các dịch vụ mạng đang chạy trong cluster.

Service discovery theo kiểu cloud-native

Nếu ứng dụng của bạn có thể dùng Kubernetes API cho service discovery, bạn có thể truy vấn API server để lấy các EndpointSlice tương ứng. Kubernetes cập nhật các EndpointSlice của một Service mỗi khi tập Pod trong Service đó thay đổi.

Với các ứng dụng không phải native, Kubernetes cung cấp các cách để đặt một cổng mạng hoặc bộ cân bằng tải (load balancer) giữa ứng dụng của bạn và các Pod backend.

Dù bằng cách nào, workload của bạn đều có thể dùng các cơ chế service discovery này để tìm đích mà nó muốn kết nối tới.

Định nghĩa một Service

Service là một đối tượng (giống như Pod hay ConfigMap là đối tượng). Bạn có thể tạo, xem hoặc sửa đổi định nghĩa Service bằng Kubernetes API. Thông thường bạn dùng một công cụ như kubectl để thực hiện các lệnh gọi API đó thay bạn.

Ví dụ, giả sử bạn có một tập Pod, mỗi Pod lắng nghe trên cổng TCP 9376 và được gắn label app.kubernetes.io/name=MyApp. Bạn có thể định nghĩa một Service để công bố listener TCP đó:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

Áp dụng manifest này sẽ tạo một Service mới tên là "my-service" với loại Service mặc định là ClusterIP. Service này nhắm tới cổng TCP 9376 trên bất kỳ Pod nào có label app.kubernetes.io/name: MyApp.

Kubernetes gán cho Service này một địa chỉ IP (cluster IP), mà cơ chế địa chỉ IP ảo sử dụng. Để biết thêm chi tiết về cơ chế đó, hãy đọc IP ảo và Service Proxy.

Controller của Service đó liên tục quét tìm các Pod khớp với selector của nó, rồi thực hiện mọi cập nhật cần thiết cho tập EndpointSlice của Service.

Tên của một đối tượng Service phải là một tên label RFC 1123 hợp lệ.

Lưu ý:

Một Service có thể ánh xạ bất kỳ port đến nào tới một targetPort. Theo mặc định và để thuận tiện, targetPort được đặt cùng giá trị với trường port.

Định nghĩa cổng

Định nghĩa cổng trong Pod có tên, và bạn có thể tham chiếu các tên này trong thuộc tính targetPort của một Service. Ví dụ, ta có thể gắn targetPort của Service với cổng của Pod theo cách sau:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc

---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

Cách này vẫn hoạt động ngay cả khi Service có một tập Pod hỗn hợp dùng cùng một tên đã cấu hình, với cùng một giao thức mạng nhưng ở các số cổng khác nhau. Điều này mang lại nhiều sự linh hoạt khi triển khai và phát triển các Service của bạn. Ví dụ, bạn có thể thay đổi số cổng mà các Pod cung cấp trong phiên bản tiếp theo của phần mềm backend mà không làm gián đoạn client.

Giao thức mặc định của Service là TCP; bạn cũng có thể dùng bất kỳ giao thức được hỗ trợ nào khác.

Vì nhiều Service cần cung cấp nhiều hơn một cổng, Kubernetes hỗ trợ nhiều định nghĩa cổng cho một Service. Mỗi định nghĩa cổng có thể có cùng protocol, hoặc khác nhau.

Service không có selector

Service thường trừu tượng hóa việc truy cập tới các Pod Kubernetes nhờ selector, nhưng khi được dùng cùng một tập đối tượng EndpointSlice tương ứng và không có selector, Service có thể trừu tượng hóa các loại backend khác, kể cả những backend chạy bên ngoài cluster.

Ví dụ:

  • Bạn muốn có một cluster cơ sở dữ liệu bên ngoài trong môi trường production, nhưng trong môi trường test bạn dùng các cơ sở dữ liệu của riêng mình.
  • Bạn muốn trỏ Service của mình tới một Service trong một Namespace khác hoặc trên một cluster khác.
  • Bạn đang chuyển (migrate) một workload sang Kubernetes. Trong lúc đánh giá cách tiếp cận, bạn chỉ chạy một phần backend trong Kubernetes.

Trong bất kỳ trường hợp nào ở trên, bạn đều có thể định nghĩa một Service mà không chỉ định selector để khớp với Pod. Ví dụ:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376

Vì Service này không có selector, các đối tượng EndpointSlice tương ứng sẽ không được tạo tự động. Bạn có thể ánh xạ Service tới địa chỉ mạng và cổng nơi nó đang chạy bằng cách thêm thủ công một đối tượng EndpointSlice. Ví dụ:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-1 # theo quy ước, dùng tên của Service
                     # làm tiền tố cho tên của EndpointSlice
  labels:
    # Bạn nên đặt label "kubernetes.io/service-name".
    # Đặt giá trị của nó khớp với tên của Service
    kubernetes.io/service-name: my-service
addressType: IPv4
ports:
  - name: http # nên khớp với tên của cổng Service đã định nghĩa ở trên
    appProtocol: http
    protocol: TCP
    port: 9376
endpoints:
  - addresses:
      - "10.4.5.6"
  - addresses:
      - "10.1.2.3"

EndpointSlice tùy chỉnh

Khi bạn tạo một đối tượng EndpointSlice cho một Service, bạn có thể dùng bất kỳ tên nào cho EndpointSlice đó. Mỗi EndpointSlice trong một namespace phải có tên duy nhất. Bạn liên kết một EndpointSlice với một Service bằng cách đặt label kubernetes.io/service-name trên EndpointSlice đó.

Lưu ý:

IP của endpoint không được là: loopback (127.0.0.0/8 với IPv4, ::1/128 với IPv6), hoặc link-local (169.254.0.0/16 và 224.0.0.0/24 với IPv4, fe80::/64 với IPv6).

Địa chỉ IP của endpoint không thể là cluster IP của các Service Kubernetes khác, vì kube-proxy không hỗ trợ IP ảo làm đích đến.

Với một EndpointSlice do chính bạn tạo, hoặc được tạo trong code của bạn, bạn cũng nên chọn một giá trị cho label endpointslice.kubernetes.io/managed-by. Nếu bạn tự viết code controller để quản lý EndpointSlice, hãy cân nhắc dùng một giá trị tương tự như "my-domain.example/name-of-controller". Nếu bạn dùng một công cụ bên thứ ba, hãy dùng tên của công cụ đó viết thường toàn bộ, và thay khoảng trắng cùng các dấu câu khác bằng dấu gạch ngang (-). Nếu mọi người trực tiếp dùng một công cụ như kubectl để quản lý EndpointSlice, hãy dùng một tên mô tả việc quản lý thủ công này, chẳng hạn "staff" hoặc "cluster-admins". Bạn nên tránh dùng giá trị dành riêng "controller", vì giá trị này xác định các EndpointSlice do chính control plane của Kubernetes quản lý.

Truy cập một Service không có selector

Việc truy cập một Service không có selector hoạt động giống như khi nó có selector. Trong ví dụ về Service không có selector, lưu lượng được định tuyến tới một trong hai endpoint được định nghĩa trong manifest EndpointSlice: một kết nối TCP tới 10.1.2.3 hoặc 10.4.5.6, trên cổng 9376.

Lưu ý:

Kubernetes API server không cho phép proxy tới các endpoint không được ánh xạ tới pod. Các thao tác như kubectl port-forward service/<service-name> forwardedPort:servicePort khi service không có selector sẽ thất bại do ràng buộc này. Điều này ngăn Kubernetes API server bị dùng làm proxy tới các endpoint mà bên gọi có thể không có quyền truy cập.

Service ExternalName là một trường hợp đặc biệt của Service, không có selector và dùng tên DNS thay thế. Để biết thêm thông tin, xem phần ExternalName.

EndpointSlice

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

EndpointSlice là các đối tượng đại diện cho một tập con (một slice) của các endpoint mạng đứng sau một Service.

Cluster Kubernetes của bạn theo dõi số lượng endpoint mà mỗi EndpointSlice đại diện. Nếu một Service có nhiều endpoint đến mức chạm tới một ngưỡng, thì Kubernetes sẽ thêm một EndpointSlice trống khác và lưu thông tin endpoint mới vào đó. Theo mặc định, Kubernetes tạo một EndpointSlice mới khi tất cả các EndpointSlice hiện có đều chứa ít nhất 100 endpoint. Kubernetes không tạo EndpointSlice mới cho đến khi cần thêm một endpoint nữa.

Xem EndpointSlice để biết thêm thông tin về API này.

Endpoints (không còn được hỗ trợ)

TRẠNG THÁI TÍNH NĂNG: Đã lỗi thời since Kubernetes v1.33

EndpointSlice API là bước phát triển tiếp theo của API Endpoints cũ hơn. Endpoints API không còn được hỗ trợ này có một số vấn đề so với EndpointSlice:

  • Nó không hỗ trợ cluster dual-stack.
  • Nó không chứa thông tin cần thiết để hỗ trợ các tính năng mới hơn, chẳng hạn như trafficDistribution.
  • Nó sẽ cắt bớt danh sách endpoint nếu danh sách quá dài để chứa trong một đối tượng duy nhất.

Vì vậy, tất cả client được khuyến nghị dùng EndpointSlice API thay vì Endpoints.

Endpoint vượt quá sức chứa

Kubernetes giới hạn số lượng endpoint có thể chứa trong một đối tượng Endpoints duy nhất. Khi một Service có hơn 1000 endpoint phía sau, Kubernetes cắt bớt dữ liệu trong đối tượng Endpoints. Vì một Service có thể được liên kết với nhiều hơn một EndpointSlice, giới hạn 1000 endpoint phía sau chỉ ảnh hưởng đến Endpoints API cũ (legacy).

Trong trường hợp đó, Kubernetes chọn tối đa 1000 endpoint backend khả dĩ để lưu vào đối tượng Endpoints, và đặt một chú thích (annotation) trên Endpoints: endpoints.kubernetes.io/over-capacity: truncated. Control plane cũng gỡ bỏ chú thích đó nếu số lượng Pod backend giảm xuống dưới 1000.

Lưu lượng vẫn được gửi tới các backend, nhưng mọi cơ chế cân bằng tải dựa vào Endpoints API cũ chỉ gửi lưu lượng tới tối đa 1000 endpoint trong số các endpoint phía sau hiện có.

Cũng vì giới hạn API đó, bạn không thể cập nhật thủ công một Endpoints để có hơn 1000 endpoint.

Giao thức ứng dụng

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

Trường appProtocol cung cấp một cách để chỉ định giao thức ứng dụng cho từng cổng của Service. Trường này được dùng làm gợi ý để các bản triển khai (implementation) cung cấp hành vi phong phú hơn cho các giao thức mà chúng hiểu. Giá trị của trường này được phản ánh sang các đối tượng Endpoints và EndpointSlice tương ứng.

Trường này tuân theo cú pháp label chuẩn của Kubernetes. Giá trị hợp lệ là một trong các loại sau:

  • Tên dịch vụ chuẩn của IANA.

  • Tên có tiền tố do bản triển khai định nghĩa, chẳng hạn mycompany.com/my-custom-protocol.

  • Tên có tiền tố do Kubernetes định nghĩa:

Giao thứcMô tả
kubernetes.io/h2cHTTP/2 qua kết nối không mã hóa (cleartext) như mô tả trong RFC 9113
kubernetes.io/wsWebSocket qua kết nối không mã hóa như mô tả trong RFC 6455
kubernetes.io/wssWebSocket qua TLS như mô tả trong RFC 6455

Service nhiều cổng

Với một số Service, bạn cần cung cấp nhiều hơn một cổng. Kubernetes cho phép bạn cấu hình nhiều định nghĩa cổng trên một đối tượng Service. Khi dùng nhiều cổng cho một Service, bạn phải đặt tên cho tất cả các cổng để chúng không bị nhầm lẫn. Ví dụ:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

Lưu ý:

Cũng như tên trong Kubernetes nói chung, tên cổng chỉ được chứa ký tự chữ và số viết thường và -. Tên cổng cũng phải bắt đầu và kết thúc bằng một ký tự chữ hoặc số.

Ví dụ, các tên 123-abc và web là hợp lệ, nhưng 123_abc và -web thì không.

Loại Service

Với một số phần của ứng dụng (ví dụ, frontend), bạn có thể muốn cung cấp Service trên một địa chỉ IP bên ngoài, có thể truy cập được từ bên ngoài cluster.

Các loại Service trong Kubernetes cho phép bạn chỉ định loại Service mà bạn muốn.

Các giá trị type hiện có và hành vi của chúng là:

ClusterIP
Cung cấp Service trên một IP nội bộ của cluster. Chọn giá trị này khiến Service chỉ có thể truy cập được từ bên trong cluster. Đây là giá trị mặc định nếu bạn không chỉ định rõ type cho Service. Bạn có thể cung cấp Service ra internet công cộng bằng một Ingress hoặc một Gateway.
NodePort
Cung cấp Service trên IP của mỗi Node tại một cổng tĩnh (NodePort). Để node port sẵn sàng, Kubernetes thiết lập một địa chỉ cluster IP, giống như khi bạn yêu cầu một Service có type: ClusterIP.
LoadBalancer
Cung cấp Service ra bên ngoài bằng một bộ cân bằng tải bên ngoài. Kubernetes không trực tiếp cung cấp thành phần cân bằng tải; bạn phải tự cung cấp, hoặc tích hợp cluster Kubernetes của bạn với một nhà cung cấp dịch vụ đám mây (cloud provider).
ExternalName
Ánh xạ Service tới nội dung của trường externalName (ví dụ, tới hostname api.foo.bar.example). Việc ánh xạ này cấu hình máy chủ DNS của cluster trả về một bản ghi CNAME với giá trị hostname bên ngoài đó. Không có bất kỳ hình thức proxy nào được thiết lập.

Trường type trong Service API được thiết kế theo dạng chức năng lồng nhau - mỗi cấp bổ sung thêm vào cấp trước. Tuy nhiên có một ngoại lệ đối với thiết kế lồng nhau này. Bạn có thể định nghĩa một Service LoadBalancer bằng cách tắt việc cấp phát NodePort cho bộ cân bằng tải.

type: ClusterIP

Loại Service mặc định này gán một địa chỉ IP từ một nhóm (pool) địa chỉ IP mà cluster của bạn đã dành riêng cho mục đích đó.

Một số loại Service khác được xây dựng dựa trên loại ClusterIP làm nền tảng.

Nếu bạn định nghĩa một Service có .spec.clusterIP được đặt thành "None" thì Kubernetes sẽ không gán địa chỉ IP. Xem headless Service để biết thêm thông tin.

Tự chọn địa chỉ IP

Bạn có thể chỉ định địa chỉ cluster IP của riêng mình như một phần của yêu cầu tạo Service. Để làm điều này, hãy đặt trường .spec.clusterIP. Ví dụ, khi bạn đã có sẵn một bản ghi DNS muốn tái sử dụng, hoặc có các hệ thống cũ (legacy) được cấu hình cho một địa chỉ IP cụ thể và khó cấu hình lại.

Địa chỉ IP bạn chọn phải là một địa chỉ IPv4 hoặc IPv6 hợp lệ nằm trong dải CIDR service-cluster-ip-range được cấu hình cho API server. Nếu bạn cố tạo một Service với giá trị địa chỉ clusterIP không hợp lệ, API server sẽ trả về mã trạng thái HTTP 422 để báo rằng có vấn đề.

Đọc tránh xung đột để tìm hiểu cách Kubernetes giúp giảm rủi ro và tác động khi hai Service khác nhau cùng cố dùng một địa chỉ IP.

type: NodePort

Nếu bạn đặt trường type thành NodePort, control plane của Kubernetes cấp phát một cổng từ dải được chỉ định bởi cờ --service-node-port-range (mặc định: 30000-32767). Mỗi node proxy cổng đó (cùng một số cổng trên mọi Node) vào Service của bạn. Service của bạn báo cáo cổng đã được cấp phát trong trường .spec.ports[*].nodePort.

Dùng NodePort cho bạn sự tự do trong việc thiết lập giải pháp cân bằng tải của riêng mình, cấu hình các môi trường mà Kubernetes chưa hỗ trợ đầy đủ, hoặc thậm chí cung cấp trực tiếp địa chỉ IP của một hay nhiều node.

Với một Service node port, Kubernetes cấp phát thêm một cổng (TCP, UDP hoặc SCTP, khớp với giao thức của Service). Mọi node trong cluster tự cấu hình để lắng nghe trên cổng được gán đó và chuyển tiếp lưu lượng tới một trong các endpoint sẵn sàng (ready) liên kết với Service đó. Bạn có thể kết nối tới Service type: NodePort từ bên ngoài cluster bằng cách kết nối tới bất kỳ node nào với giao thức phù hợp (ví dụ: TCP) và cổng phù hợp (cổng đã được gán cho Service đó).

Tự chọn cổng

Nếu bạn muốn một số cổng cụ thể, bạn có thể chỉ định giá trị trong trường nodePort. Control plane sẽ cấp phát cổng đó cho bạn hoặc báo rằng giao dịch API đã thất bại. Điều này có nghĩa là bạn cần tự xử lý các xung đột cổng có thể xảy ra. Bạn cũng phải dùng một số cổng hợp lệ, nằm trong dải được cấu hình cho NodePort.

Dưới đây là một manifest mẫu cho Service có type: NodePort chỉ định một giá trị NodePort (trong ví dụ này là 30007):

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      # Theo mặc định và để thuận tiện, `targetPort` được đặt cùng
      # giá trị với trường `port`.
      targetPort: 80
      # Trường tùy chọn
      # Theo mặc định và để thuận tiện, control plane của Kubernetes
      # sẽ cấp phát một cổng từ một dải (mặc định: 30000-32767)
      nodePort: 30007

Dành riêng dải NodePort để tránh xung đột

Chính sách gán cổng cho các Service NodePort áp dụng cho cả trường hợp gán tự động và gán thủ công. Khi người dùng muốn tạo một Service NodePort dùng một cổng cụ thể, cổng đích có thể xung đột với một cổng khác đã được gán.

Để tránh vấn đề này, dải cổng cho các Service NodePort được chia thành hai băng (band). Việc gán cổng động mặc định dùng băng trên, và có thể dùng băng dưới khi băng trên đã hết. Khi đó người dùng có thể cấp phát từ băng dưới với rủi ro xung đột cổng thấp hơn.

Khi dùng dải NodePort mặc định 30000-32767, các băng được phân chia như sau:

  • Băng tĩnh: 30000-30085
  • Băng động: 30086-32767

Xem Tránh xung đột khi gán cổng cho Service NodePort để biết thêm chi tiết về cách tính các băng tĩnh và động.

Cấu hình địa chỉ IP cho Service type: NodePort

Khi dùng kube-proxy ở chế độ iptables, theo mặc định các Service NodePort khả dụng trên tất cả IP của node. Khi dùng chế độ nftables, theo mặc định chúng chỉ khả dụng trên IP chính của node (hoặc các IP chính dual-stack).

Bạn có thể thay đổi tập IP của node mà các Service NodePort khả dụng bằng cờ --nodeport-addresses của kube-proxy, hoặc trường nodePortAddresses tương đương trong file cấu hình kube-proxy. Cờ này chấp nhận một danh sách các khối IP phân tách bằng dấu phẩy (ví dụ 10.0.0.0/8, 192.0.2.0/25) hoặc một hay nhiều từ khóa sau:

  • primary - địa chỉ IPv4 và/hoặc IPv6 chính của node, theo đối tượng Node. (Đây là giá trị mặc định cho chế độ nftables.)
  • localhost - các địa chỉ loopback của node (127.0.0.0/8, ::1/128).
  • all - tất cả địa chỉ. (Đây là giá trị mặc định cho chế độ iptables và ipvs.)

Ví dụ, nếu bạn khởi động kube-proxy với cờ --nodeport-addresses=192.168.0.0/24, thì kube-proxy sẽ cố tìm một địa chỉ IP cục bộ thuộc subnet đó trên mỗi node, và chỉ phục vụ các Service NodePort qua IP đó.

Service type: NodePort qua localhost

Các cơ chế mà service proxy dùng để triển khai Service NodePort không phải lúc nào cũng hỗ trợ cung cấp Service NodePort trên localhost. Với kube-proxy:

  • Khi dùng chế độ iptables, với giá trị --nodeport-addresses có bao gồm 127.0.0.1, các Service NodePort sẽ khả dụng trên 127.0.0.1. Tuy nhiên, điều này yêu cầu bật một sysctl của kernel (route_localnet) có thể gây ra tác dụng phụ thiếu an toàn trong một số cluster. Có thể tắt NodePort localhost của IPTables bằng cách truyền --iptables-localhost-nodeports false cho kube-proxy, hoặc bằng cách đặt --nodeport-addresses thành một dải không bao gồm 127.0.0.1.

  • Khi dùng chế độ ipvs, hoặc chế độ iptables trong cluster IPv6 single-stack, Service NodePort không khả dụng trên localhost.

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

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

See Enable Or Disable Feature Gates for more information.

  • Khi dùng chế độ nftables, Service NodePort sẽ khả dụng trên localhost khi feature gate KubeProxyNFTablesLocalhostNodePorts được bật, và --nodeport-addresses được đặt thành một giá trị có bao gồm rõ ràng localhost. (Chỉ đặt thành all sẽ không bật Service NodePort trên localhost.) Điều này được triển khai bằng cách chuyển hướng các kết nối NodePort localhost qua một proxy userspace, nên không hiệu quả bằng việc proxy service thông thường.

Các plugin mạng bên thứ ba có bản triển khai service proxy riêng có thể hỗ trợ hoặc không hỗ trợ NodePort trên localhost; hãy tham khảo tài liệu của các plugin đó.

type: LoadBalancer

Trên các nhà cung cấp dịch vụ đám mây hỗ trợ bộ cân bằng tải bên ngoài, việc đặt trường type thành LoadBalancer sẽ cấp phát một bộ cân bằng tải cho Service của bạn. Việc tạo bộ cân bằng tải thực tế diễn ra bất đồng bộ, và thông tin về bộ cân bằng tải được cấp phát sẽ được công bố trong trường .status.loadBalancer của Service. Ví dụ:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

Lưu lượng từ bộ cân bằng tải bên ngoài được chuyển tới các Pod backend. Nhà cung cấp dịch vụ đám mây quyết định cách cân bằng tải.

Để triển khai một Service type: LoadBalancer, Kubernetes thường bắt đầu bằng cách thực hiện các thay đổi tương đương với việc bạn yêu cầu một Service type: NodePort. Sau đó, thành phần cloud-controller-manager cấu hình bộ cân bằng tải bên ngoài để chuyển tiếp lưu lượng tới node port đã được gán đó.

Bạn có thể cấu hình một Service có cân bằng tải để bỏ qua việc gán node port, với điều kiện bản triển khai của nhà cung cấp dịch vụ đám mây hỗ trợ điều này.

Một số nhà cung cấp dịch vụ đám mây cho phép bạn chỉ định loadBalancerIP. Trong những trường hợp đó, bộ cân bằng tải được tạo với loadBalancerIP do người dùng chỉ định. Nếu trường loadBalancerIP không được chỉ định, bộ cân bằng tải sẽ được thiết lập với một địa chỉ IP tạm thời. Nếu bạn chỉ định loadBalancerIP nhưng nhà cung cấp dịch vụ đám mây của bạn không hỗ trợ tính năng này, trường loadbalancerIP mà bạn đặt sẽ bị bỏ qua.

Lưu ý:

Trường .spec.loadBalancerIP của Service đã không còn được hỗ trợ từ Kubernetes v1.24.

Trường này được đặc tả chưa đầy đủ và ý nghĩa của nó khác nhau giữa các bản triển khai. Nó cũng không thể hỗ trợ mạng dual-stack. Trường này có thể bị loại bỏ trong một phiên bản API tương lai.

Nếu bạn đang tích hợp với một nhà cung cấp hỗ trợ chỉ định (các) địa chỉ IP của bộ cân bằng tải cho Service thông qua một chú thích (riêng của nhà cung cấp), bạn nên chuyển sang cách đó.

Nếu bạn đang viết code tích hợp bộ cân bằng tải với Kubernetes, hãy tránh dùng trường này. Bạn có thể tích hợp với Gateway thay vì Service, hoặc bạn có thể tự định nghĩa các chú thích (riêng của nhà cung cấp) trên Service để chỉ định thông tin tương đương.

Ảnh hưởng của tình trạng hoạt động (liveness) của node tới lưu lượng bộ cân bằng tải

Kiểm tra sức khỏe (health check) của bộ cân bằng tải đóng vai trò then chốt đối với các ứng dụng hiện đại. Chúng được dùng để xác định máy chủ nào (máy ảo, hoặc địa chỉ IP) mà bộ cân bằng tải nên điều phối lưu lượng tới. Kubernetes API không định nghĩa cách triển khai kiểm tra sức khỏe cho các bộ cân bằng tải do Kubernetes quản lý, thay vào đó các nhà cung cấp dịch vụ đám mây (và những người viết code tích hợp) sẽ quyết định hành vi. Kiểm tra sức khỏe của bộ cân bằng tải được sử dụng rộng rãi trong bối cảnh hỗ trợ trường externalTrafficPolicy của Service.

Bộ cân bằng tải với nhiều loại giao thức

This is a stable feature in Kubernetes, and has been since the 1.26 release. You can no longer toggle this feature (the associated feature gate has been removed).

Theo mặc định, với các Service loại LoadBalancer, khi có nhiều hơn một cổng được định nghĩa, tất cả các cổng phải có cùng giao thức, và giao thức đó phải được nhà cung cấp dịch vụ đám mây hỗ trợ.

Feature gate MixedProtocolLBService (được bật mặc định cho kube-apiserver kể từ v1.24) cho phép dùng các giao thức khác nhau cho các Service loại LoadBalancer khi có nhiều hơn một cổng được định nghĩa.

Lưu ý:

Tập giao thức có thể dùng cho các Service có cân bằng tải do nhà cung cấp dịch vụ đám mây của bạn định nghĩa; họ có thể áp đặt các hạn chế ngoài những gì Kubernetes API quy định.

Tắt cấp phát NodePort cho bộ cân bằng tải

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

Bạn có thể tùy chọn tắt việc cấp phát node port cho Service type: LoadBalancer bằng cách đặt trường spec.allocateLoadBalancerNodePorts thành false. Chỉ nên dùng cách này cho các bản triển khai bộ cân bằng tải định tuyến lưu lượng trực tiếp tới pod thay vì dùng node port. Theo mặc định, spec.allocateLoadBalancerNodePorts là true và các Service loại LoadBalancer sẽ tiếp tục cấp phát node port. Nếu spec.allocateLoadBalancerNodePorts được đặt thành false trên một Service hiện có đã được cấp phát node port, các node port đó sẽ không được tự động thu hồi. Bạn phải xóa rõ ràng mục nodePorts trong từng cổng của Service để thu hồi các node port đó.

Chỉ định class cho bản triển khai bộ cân bằng tải

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

Với một Service có type được đặt thành LoadBalancer, trường .spec.loadBalancerClass cho phép bạn dùng một bản triển khai bộ cân bằng tải khác với mặc định của nhà cung cấp dịch vụ đám mây.

Theo mặc định, .spec.loadBalancerClass không được đặt và Service loại LoadBalancer sẽ dùng bản triển khai bộ cân bằng tải mặc định của nhà cung cấp dịch vụ đám mây nếu cluster được cấu hình với một nhà cung cấp dịch vụ đám mây thông qua cờ --cloud-provider của thành phần.

Nếu bạn chỉ định .spec.loadBalancerClass, hệ thống giả định rằng có một bản triển khai bộ cân bằng tải khớp với class đã chỉ định đang theo dõi các Service. Mọi bản triển khai bộ cân bằng tải mặc định (ví dụ, bản do nhà cung cấp dịch vụ đám mây cung cấp) sẽ bỏ qua các Service có đặt trường này. spec.loadBalancerClass chỉ có thể được đặt trên Service loại LoadBalancer. Một khi đã đặt, giá trị này không thể thay đổi. Giá trị của spec.loadBalancerClass phải là một định danh dạng label, với tiền tố tùy chọn như "internal-vip" hoặc "example.com/internal-vip". Các tên không có tiền tố được dành riêng cho người dùng cuối.

Chế độ địa chỉ IP của bộ cân bằng tải

Với một Service type: LoadBalancer, controller có thể đặt .status.loadBalancer.ingress.ipMode. .status.loadBalancer.ingress.ipMode chỉ định cách IP của bộ cân bằng tải hoạt động. Trường này chỉ có thể được chỉ định khi trường .status.loadBalancer.ingress.ip cũng được chỉ định.

Có hai giá trị khả dĩ cho .status.loadBalancer.ingress.ipMode: "VIP" và "Proxy". Giá trị mặc định là "VIP", nghĩa là lưu lượng được chuyển tới node với đích được đặt là IP và cổng của bộ cân bằng tải. Có hai trường hợp khi đặt giá trị này thành "Proxy", tùy thuộc vào cách bộ cân bằng tải của nhà cung cấp dịch vụ đám mây chuyển lưu lượng:

  • Nếu lưu lượng được chuyển tới node rồi được DNAT tới pod, đích sẽ được đặt là IP và node port của node;
  • Nếu lưu lượng được chuyển trực tiếp tới pod, đích sẽ được đặt là IP và cổng của pod.

Các bản triển khai Service có thể dùng thông tin này để điều chỉnh việc định tuyến lưu lượng.

Bộ cân bằng tải nội bộ

Trong một môi trường hỗn hợp, đôi khi cần định tuyến lưu lượng từ các Service bên trong cùng một khối địa chỉ mạng (ảo).

Trong môi trường DNS split-horizon, bạn sẽ cần hai Service để có thể định tuyến cả lưu lượng bên ngoài lẫn bên trong tới các endpoint của mình.

Để thiết lập một bộ cân bằng tải nội bộ, hãy thêm một trong các chú thích sau vào Service tùy theo nhà cung cấp dịch vụ đám mây mà bạn đang dùng:

Chọn một trong các tab.

metadata:
  name: my-service
  annotations:
    networking.gke.io/load-balancer-type: "Internal"
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
metadata:
  name: my-service
  annotations:
    service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: "private"
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"
metadata:
  annotations:
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-internal: true

type: ExternalName

Service loại ExternalName ánh xạ một Service tới một tên DNS, chứ không phải tới một selector thông thường như my-service hay cassandra. Bạn chỉ định các Service này bằng tham số spec.externalName.

Ví dụ, định nghĩa Service sau ánh xạ Service my-service trong namespace prod tới my.database.example.com:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

Lưu ý:

Service type: ExternalName chấp nhận một chuỗi địa chỉ IPv4, nhưng xử lý chuỗi đó như một tên DNS gồm các chữ số, chứ không phải như một địa chỉ IP (tuy nhiên internet không cho phép những tên như vậy trong DNS). Các Service có tên bên ngoài trông giống địa chỉ IPv4 sẽ không được các máy chủ DNS phân giải.

Nếu bạn muốn ánh xạ trực tiếp một Service tới một địa chỉ IP cụ thể, hãy cân nhắc dùng headless Service.

Khi tra cứu host my-service.prod.svc.cluster.local, DNS Service của cluster trả về một bản ghi CNAME với giá trị my.database.example.com. Việc truy cập my-service hoạt động giống như các Service khác nhưng có điểm khác biệt quan trọng là việc chuyển hướng diễn ra ở mức DNS thay vì qua proxy hay chuyển tiếp. Nếu sau này bạn quyết định chuyển cơ sở dữ liệu vào trong cluster, bạn có thể khởi chạy các Pod của nó, thêm các selector hoặc endpoint phù hợp, và thay đổi type của Service.

Chú ý:

Bạn có thể gặp khó khăn khi dùng ExternalName với một số giao thức phổ biến, bao gồm HTTP và HTTPS. Nếu bạn dùng ExternalName thì hostname mà các client bên trong cluster sử dụng sẽ khác với tên mà ExternalName tham chiếu tới.

Với các giao thức sử dụng hostname, sự khác biệt này có thể dẫn đến lỗi hoặc phản hồi không mong muốn. Các yêu cầu HTTP sẽ có header Host: mà máy chủ gốc không nhận ra; các máy chủ TLS sẽ không thể cung cấp chứng chỉ khớp với hostname mà client đã kết nối tới.

Headless Service

Đôi khi bạn không cần cân bằng tải và một IP Service duy nhất. Trong trường hợp này, bạn có thể tạo cái gọi là headless Service, bằng cách chỉ định rõ "None" cho địa chỉ cluster IP (.spec.clusterIP).

Bạn có thể dùng headless Service để giao tiếp với các cơ chế service discovery khác mà không bị ràng buộc vào cách triển khai của Kubernetes.

Với headless Service, cluster IP không được cấp phát, kube-proxy không xử lý các Service này, và nền tảng không thực hiện cân bằng tải hay proxy cho chúng.

Headless Service cho phép client kết nối trực tiếp tới bất kỳ Pod nào mà nó muốn. Các headless Service không cấu hình route và chuyển tiếp gói tin bằng địa chỉ IP ảo và proxy; thay vào đó, headless Service báo cáo địa chỉ IP endpoint của từng pod thông qua các bản ghi DNS nội bộ, được phục vụ qua dịch vụ DNS của cluster. Để định nghĩa một headless Service, bạn tạo một Service với .spec.type được đặt thành ClusterIP (cũng là giá trị mặc định của type), và đặt thêm .spec.clusterIP thành None.

Giá trị chuỗi None là một trường hợp đặc biệt và không giống với việc để trống trường .spec.clusterIP.

Cách DNS được cấu hình tự động phụ thuộc vào việc Service có định nghĩa selector hay không:

Có selector

Với các headless Service có định nghĩa selector, endpoints controller tạo các EndpointSlice trong Kubernetes API, và sửa đổi cấu hình DNS để trả về các bản ghi A hoặc AAAA (địa chỉ IPv4 hoặc IPv6) trỏ trực tiếp tới các Pod đứng sau Service.

Không có selector

Với các headless Service không định nghĩa selector, control plane không tạo các đối tượng EndpointSlice. Tuy nhiên, hệ thống DNS sẽ tìm và cấu hình một trong hai:

  • Bản ghi DNS CNAME cho các Service type: ExternalName.
  • Bản ghi DNS A / AAAA cho tất cả địa chỉ IP của các endpoint sẵn sàng của Service, với mọi loại Service ngoài ExternalName.
    • Với endpoint IPv4, hệ thống DNS tạo bản ghi A.
    • Với endpoint IPv6, hệ thống DNS tạo bản ghi AAAA.

Khi bạn định nghĩa một headless Service không có selector, port phải khớp với targetPort.

Tìm kiếm Service

Với các client chạy bên trong cluster, Kubernetes hỗ trợ hai cách chính để tìm một Service: biến môi trường và DNS.

Biến môi trường

Khi một Pod chạy trên một Node, kubelet thêm một tập biến môi trường cho mỗi Service đang hoạt động. Nó thêm các biến {SVCNAME}_SERVICE_HOST và {SVCNAME}_SERVICE_PORT, trong đó tên Service được viết hoa và dấu gạch ngang được chuyển thành dấu gạch dưới.

Ví dụ, Service redis-primary cung cấp cổng TCP 6379 và đã được cấp phát địa chỉ cluster IP 10.0.0.11 sẽ tạo ra các biến môi trường sau:

REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11

Lưu ý:

Khi bạn có một Pod cần truy cập một Service, và bạn đang dùng phương pháp biến môi trường để công bố cổng và cluster IP cho các Pod client, bạn phải tạo Service trước khi các Pod client được tạo ra. Nếu không, các biến môi trường của những Pod client đó sẽ không được điền giá trị.

Nếu bạn chỉ dùng DNS để tìm cluster IP của một Service, bạn không cần lo lắng về vấn đề thứ tự này.

Kubernetes cũng hỗ trợ và cung cấp các biến tương thích với tính năng "legacy container links" của Docker Engine. Bạn có thể đọc makeLinkVariables để xem cách tính năng này được triển khai trong Kubernetes.

DNS

Bạn có thể (và gần như luôn luôn nên) thiết lập một dịch vụ DNS cho cluster Kubernetes bằng một add-on.

Một máy chủ DNS nhận biết cluster (cluster-aware), chẳng hạn CoreDNS, theo dõi Kubernetes API để phát hiện các Service mới và tạo một tập bản ghi DNS cho mỗi Service. Nếu DNS đã được bật trên toàn bộ cluster thì tất cả các Pod sẽ tự động phân giải được Service theo tên DNS của chúng.

Ví dụ, nếu bạn có một Service tên là my-service trong namespace Kubernetes my-ns, control plane và DNS Service cùng phối hợp tạo một bản ghi DNS cho my-service.my-ns. Các Pod trong namespace my-ns sẽ có thể tìm thấy service bằng cách tra cứu tên my-service (my-service.my-ns cũng hoạt động).

Các Pod trong namespace khác phải dùng tên đầy đủ my-service.my-ns. Những tên này sẽ được phân giải thành cluster IP được gán cho Service.

Kubernetes cũng hỗ trợ bản ghi DNS SRV (Service) cho các cổng có tên. Nếu Service my-service.my-ns có một cổng tên là http với giao thức được đặt thành TCP, bạn có thể thực hiện truy vấn DNS SRV cho _http._tcp.my-service.my-ns để tìm số cổng của http, cũng như địa chỉ IP.

Máy chủ DNS của Kubernetes là cách duy nhất để truy cập các Service ExternalName. Bạn có thể tìm thêm thông tin về việc phân giải ExternalName trong DNS cho Service và Pod.

Cơ chế địa chỉ IP ảo

Trang IP ảo và Service Proxy giải thích cơ chế mà Kubernetes dùng để cung cấp một Service qua một địa chỉ IP ảo.

Chính sách lưu lượng

Bạn có thể đặt các trường .spec.internalTrafficPolicy và .spec.externalTrafficPolicy để kiểm soát cách Kubernetes định tuyến lưu lượng tới các backend khỏe mạnh (“ready”).

Xem Chính sách lưu lượng để biết thêm chi tiết.

Kiểm soát phân phối lưu lượng

Trường .spec.trafficDistribution cung cấp một cách khác để tác động tới việc định tuyến lưu lượng trong một Service Kubernetes. Trong khi chính sách lưu lượng tập trung vào các đảm bảo ngữ nghĩa chặt chẽ, phân phối lưu lượng cho phép bạn thể hiện các ưu tiên (chẳng hạn định tuyến tới các endpoint gần hơn về mặt topo mạng). Điều này có thể giúp tối ưu hiệu năng, chi phí, hoặc độ tin cậy. Trong Kubernetes 1.37, các giá trị sau được hỗ trợ:

PreferSameZone
Thể hiện ưu tiên định tuyến lưu lượng tới các endpoint nằm trong cùng zone với client.
PreferSameNode
Thể hiện ưu tiên định tuyến lưu lượng tới các endpoint nằm trên cùng node với client.
PreferClose (không còn được hỗ trợ)
Đây là một alias cũ của PreferSameZone, có ngữ nghĩa kém rõ ràng hơn.

Nếu trường này không được đặt, bản triển khai sẽ áp dụng chiến lược định tuyến mặc định của nó.

Xem Phân phối lưu lượng để biết thêm chi tiết.

Duy trì phiên (session stickiness)

Nếu bạn muốn đảm bảo rằng các kết nối từ một client cụ thể luôn được chuyển tới cùng một Pod, bạn có thể cấu hình session affinity dựa trên địa chỉ IP của client. Đọc session affinity để tìm hiểu thêm.

IP bên ngoài (External IP)

TRẠNG THÁI TÍNH NĂNG: Đã lỗi thời since Kubernetes v1.36

Tất cả người dùng nên bắt đầu chuyển dần khỏi externalIPs. Thay vào đó, hãy cân nhắc dùng một controller bộ cân bằng tải bên ngoài hoặc một bản triển khai Gateway API.

Nếu có các IP bên ngoài định tuyến tới một hoặc nhiều node của cluster, các Service Kubernetes có thể được cung cấp trên các externalIPs đó. Khi lưu lượng mạng đi vào cluster với IP bên ngoài (là IP đích) và cổng khớp với Service đó, các quy tắc và route mà Kubernetes đã cấu hình sẽ đảm bảo lưu lượng được định tuyến tới một trong các endpoint của Service đó.

Khi định nghĩa một Service, bạn có thể chỉ định externalIPs cho bất kỳ loại Service nào. Trong ví dụ dưới đây, client có thể truy cập Service tên "my-service" qua TCP, tại "198.51.100.32:80" (được tính từ .spec.externalIPs[] và .spec.ports[].port).

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 49152
  externalIPs:
    - 198.51.100.32

Lưu ý:

Kubernetes không quản lý việc cấp phát externalIPs; đây là trách nhiệm của quản trị viên cluster.

Đối tượng API

Service là một tài nguyên cấp cao nhất trong Kubernetes REST API. Bạn có thể tìm thêm chi tiết về đối tượng Service API.

Tiếp theo là gì

Tìm hiểu thêm về Service và vai trò của chúng trong Kubernetes:

  • Làm theo hướng dẫn Kết nối ứng dụng với Service.
  • Đọc về Ingress, thành phần cung cấp các route HTTP và HTTPS từ bên ngoài cluster tới các Service bên trong cluster của bạn.
  • Đọc về Gateway, một phần mở rộng của Kubernetes mang lại nhiều sự linh hoạt hơn Ingress.

Để hiểu thêm bối cảnh, hãy đọc các tài liệu sau:

3.3 - Tổng quan

3.3.1 - Kubernetes là gì

Trang tổng quan của Kubernetes.

Kubernetes là một nền tảng nguồn mở, khả chuyển, có thể mở rộng để quản lý các ứng dụng được đóng gói và các service, giúp thuận lợi trong việc cấu hình và tự động hoá việc triển khai ứng dụng. Kubernetes là một hệ sinh thái lớn và phát triển nhanh chóng. Các dịch vụ, sự hỗ trợ và công cụ có sẵn rộng rãi.

Tên gọi Kubernetes có nguồn gốc từ tiếng Hy Lạp, có ý nghĩa là người lái tàu hoặc hoa tiêu. Google mở mã nguồn Kubernetes từ năm 2014. Kubernetes xây dựng dựa trên một thập kỷ rưỡi kinh nghiệm mà Google có được với việc vận hành một khối lượng lớn workload trong thực tế, kết hợp với các ý tưởng và thực tiễn tốt nhất từ cộng đồng.

Quay ngược thời gian

Chúng ta hãy xem tại sao Kubernetes rất hữu ích bằng cách quay ngược thời gian.

Deployment evolution

Thời đại triển khai theo cách truyền thống: Ban đầu, các ứng dụng được chạy trên các máy chủ vật lý. Không có cách nào để xác định ranh giới tài nguyên cho các ứng dụng trong máy chủ vật lý và điều này gây ra sự cố phân bổ tài nguyên. Ví dụ, nếu nhiều ứng dụng cùng chạy trên một máy chủ vật lý, có thể có những trường hợp một ứng dụng sẽ chiếm phần lớn tài nguyên hơn và kết quả là các ứng dụng khác sẽ hoạt động kém đi. Một giải pháp cho điều này sẽ là chạy từng ứng dụng trên một máy chủ vật lý khác nhau. Nhưng giải pháp này không tối ưu vì tài nguyên không được sử dụng đúng mức và rất tốn kém cho các tổ chức để có thể duy trì nhiều máy chủ vật lý như vậy.

Thời đại triển khai ảo hóa: Như một giải pháp, ảo hóa đã được giới thiệu. Nó cho phép bạn chạy nhiều Máy ảo (VM) trên CPU của một máy chủ vật lý. Ảo hóa cho phép các ứng dụng được cô lập giữa các VM và cung cấp mức độ bảo mật vì thông tin của một ứng dụng không thể được truy cập tự do bởi một ứng dụng khác.

Ảo hóa cho phép sử dụng tốt hơn các tài nguyên trong một máy chủ vật lý và cho phép khả năng mở rộng tốt hơn vì một ứng dụng có thể được thêm hoặc cập nhật dễ dàng, giảm chi phí phần cứng và hơn thế nữa. Với ảo hóa, bạn có thể có một tập hợp các tài nguyên vật lý dưới dạng một cụm các máy ảo sẵn dùng.

Mỗi VM là một máy tính chạy tất cả các thành phần, bao gồm cả hệ điều hành riêng của nó, bên trên phần cứng được ảo hóa.

Thời đại triển khai Container: Các container tương tự như VM, nhưng chúng có tính cô lập để chia sẻ Hệ điều hành (HĐH) giữa các ứng dụng. Do đó, container được coi là nhẹ (lightweight). Tương tự như VM, một container có hệ thống tệp (filesystem), CPU, bộ nhớ, process space, v.v. Khi chúng được tách rời khỏi cơ sở hạ tầng bên dưới, chúng có thể khả chuyển (portable) trên cloud hoặc các bản phân phối Hệ điều hành.

Các container đã trở nên phổ biến vì chúng có thêm nhiều lợi ích, chẳng hạn như:

  • Tạo mới và triển khai ứng dụng Agile: gia tăng tính dễ dàng và hiệu quả của việc tạo các container image so với việc sử dụng VM image.
  • Phát triển, tích hợp và triển khai liên tục: cung cấp khả năng build và triển khai container image thường xuyên và đáng tin cậy với việc rollbacks dễ dàng, nhanh chóng.
  • Phân biệt giữa Dev và Ops: tạo các images của các application container tại thời điểm build/release thay vì thời gian triển khai, do đó phân tách các ứng dụng khỏi hạ tầng.
  • Khả năng quan sát không chỉ hiển thị thông tin và các metric ở mức Hệ điều hành, mà còn cả application health và các tín hiệu khác.
  • Tính nhất quán về môi trường trong suốt quá trình phát triển, testing và trong production: Chạy tương tự trên laptop như trên cloud.
  • Tính khả chuyển trên cloud và các bản phân phối HĐH: Chạy trên Ubuntu, RHEL, CoreOS, on-premises, Google Kubernetes Engine và bất kì nơi nào khác.
  • Quản lý tập trung ứng dụng: Tăng mức độ trừu tượng từ việc chạy một Hệ điều hành trên phần cứng ảo hóa sang chạy một ứng dụng trên một HĐH bằng logical resources.
  • Các micro-services phân tán, elastic: ứng dụng được phân tách thành các phần nhỏ hơn, độc lập và thể được triển khai và quản lý một cách linh hoạt - chứ không phải một app nguyên khối (monolithic).
  • Cô lập các tài nguyên: dự đoán hiệu năng ứng dụng
  • Sử dụng tài nguyên: hiệu quả

Tại sao bạn cần Kubernetes và nó có thể làm những gì?

Các container là một cách tốt để đóng gói và chạy các ứng dụng của bạn. Trong môi trường production, bạn cần quản lý các container chạy các ứng dụng và đảm bảo rằng không có khoảng thời gian downtime. Ví dụ, nếu một container bị tắt đi, một container khác cần phải khởi động lên. Điều này sẽ dễ dàng hơn nếu được xử lý bởi một hệ thống.

Đó là cách Kubernetes đến với chúng ta. Kubernetes cung cấp cho bạn một framework để chạy các hệ phân tán một cách mạnh mẽ. Nó đảm nhiệm việc nhân rộng và chuyển đổi dự phòng cho ứng dụng của bạn, cung cấp các mẫu deployment và hơn thế nữa. Ví dụ, Kubernetes có thể dễ dàng quản lý một triển khai canary cho hệ thống của bạn.

Kubernetes cung cấp cho bạn:

  • Service discovery và cân bằng tải
    Kubernetes có thể expose một container sử dụng DNS hoặc địa chỉ IP của riêng nó. Nếu lượng traffic truy cập đến một container cao, Kubernetes có thể cân bằng tải và phân phối lưu lượng mạng (network traffic) để việc triển khai được ổn định.
  • Điều phối bộ nhớ
    Kubernetes cho phép bạn tự động mount một hệ thống lưu trữ mà bạn chọn, như local storages, public cloud providers, v.v.
  • Tự động rollouts và rollbacks
    Bạn có thể mô tả trạng thái mong muốn cho các container được triển khai dùng Kubernetes và nó có thể thay đổi trạng thái thực tế sang trạng thái mong muốn với tần suất được kiểm soát. Ví dụ, bạn có thể tự động hoá Kubernetes để tạo mới các container cho việc triển khai của bạn, xoá các container hiện có và áp dụng tất cả các resource của chúng vào container mới.
  • Đóng gói tự động
    Bạn cung cấp cho Kubernetes một cluster gồm các node mà nó có thể sử dụng để chạy các tác vụ được đóng gói (containerized task). Bạn cho Kubernetes biết mỗi container cần bao nhiêu CPU và bộ nhớ (RAM). Kubernetes có thể điều phối các container đến các node để tận dụng tốt nhất các resource của bạn.
  • Tự phục hồi
    Kubernetes khởi động lại các containers bị lỗi, thay thế các container, xoá các container không phản hồi lại cấu hình health check do người dùng xác định và không cho các client biết đến chúng cho đến khi chúng sẵn sàng hoạt động.
  • Quản lý cấu hình và bảo mật
    Kubernetes cho phép bạn lưu trữ và quản lý các thông tin nhạy cảm như: password, OAuth token và SSH key. Bạn có thể triển khai và cập nhật lại secret và cấu hình ứng dụng mà không cần build lại các container image và không để lộ secret trong cấu hình stack của bạn.

Kubernetes không phải là gì?

Kubernetes không phải là một hệ thống PaaS (Nền tảng như một Dịch vụ) truyền thống, toàn diện. Do Kubernetes hoạt động ở tầng container chứ không phải ở tầng phần cứng, nó cung cấp một số tính năng thường áp dụng chung cho các dịch vụ PaaS, như triển khai, nhân rộng, cân bằng tải, ghi nhật ký và giám sát. Tuy nhiên, Kubernetes không phải là cấu trúc nguyên khối và các giải pháp mặc định này là tùy chọn và có thể cắm được (pluggable).

Kubernetes:

  • Không giới hạn các loại ứng dụng được hỗ trợ. Kubernetes nhằm mục đích hỗ trợ một khối lượng công việc cực kỳ đa dạng, bao gồm cả stateless, stateful và xử lý dữ liệu. Nếu một ứng dụng có thể chạy trong một container, nó sẽ chạy rất tốt trên Kubernetes.
  • Không triển khai mã nguồn và không build ứng dụng của bạn. Quy trình CI/CD được xác định bởi tổ chức cũng như các yêu cầu kỹ thuật.
  • Không cung cấp các service ở mức ứng dụng, như middleware (ví dụ, các message buses), các framework xử lý dữ liệu (ví dụ, Spark), cơ sở dữ liệu (ví dụ, MySQL), bộ nhớ cache, cũng như hệ thống lưu trữ của cluster (ví dụ, Ceph). Các thành phần như vậy có thể chạy trên Kubernetes và/hoặc có thể được truy cập bởi các ứng dụng chạy trên Kubernetes thông qua các cơ chế di động, chẳng hạn như Open Service Broker.
  • Không bắt buộc các giải pháp ghi lại nhật ký (logging), giám sát (monitoring) hoặc cảnh báo (alerting). Nó cung cấp một số sự tích hợp như proof-of-concept, và cơ chế để thu thập và xuất các số liệu.
  • Không cung cấp, không bắt buộc một cấu hình ngôn ngữ/hệ thống (ví dụ: Jsonnet). Nó cung cấp một API khai báo có thể được targeted bởi các hình thức khai báo tùy ý.
  • Không cung cấp cũng như áp dụng bất kỳ cấu hình toàn diện, bảo trì, quản lý hoặc hệ thống tự phục hồi.
  • Ngoài ra, Kubernetes không phải là một hệ thống điều phối đơn thuần. Trong thực tế, nó loại bỏ sự cần thiết của việc điều phối. Định nghĩa kỹ thuật của điều phối là việc thực thi một quy trình công việc được xác định: đầu tiên làm việc A, sau đó là B rồi sau chót là C. Ngược lại, Kubernetes bao gồm một tập các quy trình kiểm soát độc lập, có thể kết hợp, liên tục điều khiển trạng thái hiện tại theo trạng thái mong muốn đã cho. Nó không phải là vấn đề làm thế nào bạn có thể đi được từ A đến C. Kiểm soát tập trung cũng không bắt buộc. Điều này dẫn đến một hệ thống dễ sử dụng hơn, mạnh mẽ hơn, linh hoạt hơn và có thể mở rộng.

Tiếp theo là gì

3.4 - Kiến Trúc Cluster

3.4.1 - Leases

Trong các hệ thống phân tán, Kubernetes sử dụng cơ chế leases (giữ quyền tạm thời) để khóa tài nguyên dùng chung và điều phối hoạt động giữa các thành phần trong cụm. Trong Kubernetes, lease được biểu diễn bằng các đối tượng Lease thuộc API group coordination.k8s.io API Group, Những đối tượng này đóng vai trò quan trọng trong hệ thống, ví dụ như theo dõi trạng thái node (heartbeat) và cơ chế bầu chọn leader giữa các thành phần nội bộ.

Node heartbeats

Kubernetes sử dụng Lease API để truyền tín hiệu heartbeat từ kubelet về Kubernetes API server. Với mỗi đối tượng Node, sẽ có một đối tượng Lease tương ứng (có cùng tên) nằm trong namespace kube-node-lease. Ở tầng bên dưới, mỗi lần kubelet gửi heartbeat thực chất là một lệnh update lên đối tượng Lease, cập nhật trường spec.renewTime. Control plane của Kubernetes sẽ dựa vào dấu thời gian trong trường này để xác định node đó còn hoạt động hay không.

Xem Node Lease objects để biết thêm chi tiết.

Leader election

Kubernetes cũng sử dụng Lease để đảm bảo rằng chỉ một phiên bản duy nhất của một thành phần có thể hoạt động tại một thời điểm. Cơ chế này được áp dụng cho các thành phần của control plane như kube-controller-manager và kube-scheduler trong các cấu hình HA (High Availability) — nơi chỉ một phiên bản của thành phần đó được phép hoạt động chính, còn các phiên bản còn lại sẽ ở chế độ chờ.

Đọc thêm tại coordinated leader election để tìm hiểu cách Kubernetes sử dụng Lease API để chọn phiên bản nào sẽ đóng vai trò leader.

API server identity

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

Từ phiên bản Kubernetes v1.26, mỗi kube-apiserver sẽ sử dụng Lease API để công bố danh tính của mình với phần còn lại của hệ thống.Mặc dù việc này chưa mang lại lợi ích trực tiếp, nhưng nó cung cấp một cơ chế để các thành phần khác có thể phát hiện được có bao nhiêu phiên bản kube-apiserver đang hoạt động trong control plane. Việc tồn tại các Lease của kube-apiserver giúp chuẩn bị cho các tính năng trong tương lai, nơi các kube-apiserver có thể cần phối hợp hoạt động với nhau.

Bạn có thể kiểm tra các Lease này trong namespace kube-system, với tên theo dạng apiserver-<sha256-hash>. Hoặc sử dụng label để lọc apiserver.kubernetes.io/identity=kube-apiserver:

kubectl -n kube-system get lease -l apiserver.kubernetes.io/identity=kube-apiserver
NAME                                        HOLDER                                                                           AGE
apiserver-07a5ea9b9b072c4a5f3d1c3702        apiserver-07a5ea9b9b072c4a5f3d1c3702_0c8914f7-0f35-440e-8676-7844977d3a05        5m33s
apiserver-7be9e061c59d368b3ddaf1376e        apiserver-7be9e061c59d368b3ddaf1376e_84f2a85d-37c1-4b14-b6b9-603e62e4896f        4m23s
apiserver-1dfef752bcb36637d2763d1868        apiserver-1dfef752bcb36637d2763d1868_c5ffa286-8a9a-45d4-91e7-61118ed58d2e        4m43s

Chuỗi SHA256 hash được sử dụng trong tên của đối tượng Lease được tính dựa trên hostname của hệ điều hành mà kube-apiserver nhìn thấy. Do đó, mỗi kube-apiserver cần được cấu hình với một hostname duy nhất trong cụm Kubernetes để tránh xung đột. Khi có một instance mới của kube-apiserver được khởi động và sử dụng cùng hostname với một instance trước đó, nó sẽ tiếp quản Lease đã có sẵn bằng cách ghi đè holder identity, thay vì tạo một Lease mới.Bạn có thể kiểm tra hostname mà kube-apiserver đang sử dụng bằng cách tra nhãn kubernetes.io/hostname trên node hoặc pod tương ứng:

kubectl -n kube-system get lease apiserver-07a5ea9b9b072c4a5f3d1c3702 -o yaml
apiVersion: coordination.k8s.io/v1
kind: Lease
metadata:
  creationTimestamp: "2023-07-02T13:16:48Z"
  labels:
    apiserver.kubernetes.io/identity: kube-apiserver
    kubernetes.io/hostname: master-1
  name: apiserver-07a5ea9b9b072c4a5f3d1c3702
  namespace: kube-system
  resourceVersion: "334899"
  uid: 90870ab5-1ba9-4523-b215-e4d4e662acb1
spec:
  holderIdentity: apiserver-07a5ea9b9b072c4a5f3d1c3702_0c8914f7-0f35-440e-8676-7844977d3a05
  leaseDurationSeconds: 3600
  renewTime: "2023-07-04T21:58:48.065888Z"

Các Lease đã hết hạn từ những kube-apiserver không còn tồn tại sẽ được thu gom tự động (garbage collect) bởi các kube-apiserver mới sau 1 giờ.

Bạn có thể tắt cơ chế Lease định danh của API server bằng cách vô hiệu hóa feature gate APIServerIdentity. Xem thêm tại feature gate.

Workloads

Bạn có thể tự định nghĩa và sử dụng Lease cho chính workload của mình. Ví dụ: bạn có thể chạy một controller tùy chỉnh, trong đó một bản sao chính (primary hoặc leader) sẽ thực hiện các thao tác mà các bản sao còn lại không thực hiện. Bạn định nghĩa một đối tượng Lease để các bản sao của controller có thể chọn hoặc bầu chọn ra leader, sử dụng Kubernetes API để phối hợp hoạt động. Nếu bạn sử dụng Lease, cách thực hiện tốt là đặt tên Lease sao cho dễ liên kết với sản phẩm hoặc thành phần sử dụng nó. Ví dụ: nếu bạn có một thành phần tên là Example Foo, thì nên đặt Lease là example-foo.

Nếu người vận hành cluster hoặc người dùng cuối có thể triển khai nhiều phiên bản của cùng một thành phần, hãy chọn một tiền tố tên riêng biệt và áp dụng một cơ chế (chẳng hạn như hash của tên Deployment) để tránh trùng tên Lease.

Bạn cũng có thể sử dụng một cách tiếp cận khác, miễn là đạt được mục tiêu chung: các phần mềm khác nhau không gây xung đột với nhau khi sử dụng Lease.

3.4.2 - Các khái niệm nền tảng của Cloud Controller Manager

Khái niệm Cloud Controller Manager (CCM) (để tránh nhầm lẫn với bản binary build cùng tên) được định nghĩa riêng biệt để cho phép các bên cung cấp dịch vụ cloud và thành phần chính của Kubernetes phát triển độc lập với nhau. CCM chạy đồng thời với những thành phần khác thuộc máy chủ của một cluster như Controller Manager của Kubernetes, API server, và Scheduler. Nó cũng có thể đóng vai trò như một addon cho Kubernetes.

Cloud Controller Manager này được thiết kế dựa trên cơ chế plugin nhằm cho phép các bên Cloud Provider có thể tích hợp với Kubernetes một cách dễ dàng thông qua các plugin này. Đã có những bản kế hoạch được thiết kế sẵn nhằm mục đích hỗ trợ những cloud provider thay đổi từ mô hình cũ sang mô hình mới đi chung với CCM.

Tài liệu này thảo luận về những khái niệm đằng sau một CCM và đưa ra những chi tiết về chức năng liên quan của nó.

Dưới đây là kiến trúc của một Kubernetes cluster khi không đi cùng với Cloud Controller Manager:

Kiến trúc CCM Kube trước đây

Thiết kế

Trong sơ đồ trên, Kubernetes và nhà cung cấp dịch vụ cloud được tích hợp thông qua một số thành phần sau:

  • Kubelet
  • Kubernetes Controller Manager
  • Kubernetes API server

CCM hợp nhất tất cả các logic phụ thuộc trên một nền tàng Cloud từ 3 thành phần trên để tạo thành một điểm tích hợp duy nhất với hệ thống Cloud. Sơ đồ kiến trúc khi đi kèm với CCM sẽ trở thành:

Kiến trúc CCM Kube hiện tại

Các thành phần của CCM

Cloud Controller Manager phân nhỏ một số chức năng của Kubernetes controller manager (KCM) và chạy nó như một tiến trình tách biệt. Cụ thể hơn, nó phân nhỏ những controller trong Kubernetes Controller Manager phụ thuộc vào Cloud. Kubernetes Controller Manager sẽ có những controller nhỏ hơn:

  • Node controller
  • Volume controller
  • Route controller
  • Service controller

Tại phiên bản 1.9, CCM thực hiện chạy những controller sau từ trong danh sách trên:

  • Node controller
  • Route controller
  • Service controller

Lưu ý:

Volume controller được bỏ ra khỏi Cloud Controller Manager. Do độ phức tạp lớn ảnh hướng và sẽ tốn nhiều thời gian cũng như nhân lực không đáp ứng đủ cho việc tách hẳn tầng logic liên quan tới Volume từ những bên cung cấp dịch vụ, và quyết định cuối cùng là sẽ không triển khai quản lý Volume như một phần của CCM.

Kết hoạch ban đầu của dự án là hỗ trợ Volume sử dụng Cloud Controller Manager để áp dụng những Flex Volume linh hoạt nhằm dễ dàng tích hợp bổ sung thêm. Tuy nhiên, một giải pháp khác cũng đang được lên kế hoạch để thay thế Flex Volume được biết là CSI.

Sau khi xem xét về khía cạnh này, chúng tôi quyết định sẽ có một khoảng thời gian nghỉ trước khi CSI trở nên sẵn sàng cho việc sử dụng.

Chức năng của Cloud Controller Manager

CCM thừa hưởng những tính năng của nó từ các thành phần trong Kubernetes phụ thuộc vào các Cloud Provider. Phần kế tiếp sẽ giới thiệu những thành phần này.

1. Kubernetes Conntroller Manager

Phần lớn các tính năng của CCM bắt nguồn từ Kubernetes controller manager. Như đã đề cập ở phần trước, CCM bao gồm:

  • Node controller
  • Route controller
  • Service controller

Node controller

Node controller có vai trò khởi tạo một Node bằng cách thu thập thông tin về những Node đang chạy trong cluster từ các cloud provider.

Node controller sẽ thực hiện những chức năng sau:

  1. Khởi tạo một Node với các nhãn region/zone.
  2. Khởi tạo một Node với những thông tin được cung cấp từ cloud, ví dụ như loại máy và kích cỡ.
  3. Thu thập địa chỉ mạng của Node và hostname.
  4. Trong trường hợp một Node không có tín hiệu phản hồi, Node controller sẽ kiểm tra xem Node này có thực sự xóa khỏi hệ thống cloud hay chưa. Nếu Node đó không còn tồn tại trên cloud, controller sẽ xóa Node đó khỏi Kubernetes cluster.

Route controller

Route controller đóng vai trò cấu hình định tuyến trong nằm trong hệ thống cloud để các container trên các Node khác nhau trong Kubernetes cluster có thể giao tiếp với nhau. Route controller hiện chỉ đáp ứng được cho các Google Compute Engine cluster.

Service controller

Service controller lắng nghe các sự kiện tạo mới, cập nhật và xoá bỏ một service. Dựa trên trạng thái hiện tại của các vụ trên Kubernetes, nó cấu hình các dịch vụ cân bằng tải trên cloud (như ELB của AWS, Google Load Balancer, hay Oracle Cloud Infrastructure LB) nhằm phản ánh trạng thái của các Service trên Kubernetes. Ngoài ra, nó đảm bảo những service backends cho các dịch vụ cần bằng tải trên cloud được cập nhật

2. Kubelet

Node controller bao gồm một số tính năng phụ thuộc vào tầng cloud của Kubelet. Trước khi có CCM, Kubelet đảm nhận vai trò khởi tạo một Node với thông tin chi tiết từ cloud như địa chỉ IP, region hay instance type. Với CCM, vai trò này được CCM đảm nhận thay cho Kubelet.

Với mô hình mới này, Kubelet sẽ khởi tạo một Node nhưng không đi kèm với những thông tin từ cloud. Tuy nhiên, nó sẽ thêm vào một dấu Taint để đánh dấu Node sẽ không được lập lịch cho tới khi CCM khởi tạo xong Node này với những thông tin cụ thể cung cấp từ Cloud, sau đó nó sẽ xóa những dấu chờ này.

Cơ chế Plugin

CCM sử dụng interface trong ngôn ngữ Go cho phép triển khai trên bất kì hệ thống cloud nào cũng có thể plugged in. Cụ thể hơn, nó sử dụng CloudProvider Interface được định nghĩa ở đây.

Cách triển khai của bốn controller được nêu ở trên, và một số được thực hiện như giao diện chung cho các bên cung cấp dịch vụ cloud, sẽ ở trong lõi (core) của Kubernetes. Việc triển khai dành riêng cho từng cloud provider sẽ được xây dựng bên ngoài lõi (core) và triển khai các giao diện được xác định bên trong lõi.

Để biết thêm chỉ tiết, xem Cloud Controller Manager.

Phân quyền

Phần này sẽ phân nhỏ quyền truy cập cần có cho các API object cung cấp bởi CCM để thực hiện những hành động của nó.

Node controller

Node controller chỉ hoạt động với các Node. Nó yêu cầu đầy đủ quyền truy cập bao gồm get, list, create, update, patch, watch, và delete một Node.

v1/Node:

  • Get
  • List
  • Create
  • Update
  • Patch
  • Watch
  • Delete

Route controller

Route controller lắng nghe sự kiện tạo ra các Node và cấu hình các Route tương ứng. Nó yêu cầu có quyền truy cập get tới các đối Node.

v1/Node:

  • Get

Service controller

Service controller lắng nghe các sự kiện khởi tạo, cập nhật và xóa bỏ một Service và cấu hình những endpoint phù hợp.

Để truy cập các Service, nó cần quyền list, và watch. Để cập nhật Service, nó sẽ cần patch và update.

Để thiết lập các endpoint cho các Service, nó cần quyền create, list, get, watch, và update.

v1/Service:

  • List
  • Get
  • Watch
  • Patch
  • Update

Các vấn đề khác

Việc triển khai lõi của CCM yêu cầu cần có quyền tạo mới sự kiện và đảm bảo quyền thực thi một số hành động, nó cần có quyền tạo các Service Accounts

v1/Event:

  • Create
  • Patch
  • Update

v1/ServiceAccount:

  • Create

Với RBAC ClusterRole, CCM cần có ClusterRole tối thiểu:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cloud-controller-manager
rules:
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
      - update
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - "*"
  - apiGroups:
      - ""
    resources:
      - nodes/status
    verbs:
      - patch
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - list
      - patch
      - update
      - watch
  - apiGroups:
      - ""
    resources:
      - serviceaccounts
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - persistentvolumes
    verbs:
      - get
      - list
      - update
      - watch
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - create
      - get
      - list
      - watch
      - update

Các nhà cung cấp đã triển khai

Sau đây là danh sách các nhà cung cấp dịch vụ cloud đã triển khai CCM:

Quản lý Cluster

Hướng dẫn chi tiết cho việc cấu hình và chạy CCM được cung cấp tại đây.

3.4.3 - Kubernetes - Khả năng tự phục hồi (Self-Healing)

Kubernetes được thiết kế với khả năng tự phục hồi giúp duy trì tình trạng khỏe mạnh và tính khả dụng của các workload. Nó tự động thay thế các container bị lỗi, lập lịch lại các workload khi node trở nên không khả dụng, và đảm bảo rằng trạng thái mong muốn của hệ thống được duy trì.

Khả năng tự phục hồi

  • Khởi động lại ở cấp độ container: Nếu một container bên trong Pod bị lỗi, Kubernetes sẽ khởi động lại nó dựa trên restartPolicy.

  • Thay thế replica: Nếu một Pod trong Deployment hoặc StatefulSet bị lỗi, Kubernetes sẽ tạo một Pod thay thế để duy trì số lượng replica được chỉ định. Nếu một Pod thuộc DaemonSet bị lỗi, control plane sẽ tạo một Pod thay thế để chạy trên cùng node đó.

  • Phục hồi persistent storage: Nếu một node đang chạy Pod với PersistentVolume (PV) được gắn kết, và node đó bị lỗi, Kubernetes có thể gắn lại volume vào Pod mới trên node khác.

  • Cân bằng tải cho Service: Nếu một Pod đằng sau Service bị lỗi, Kubernetes sẽ tự động loại bỏ nó khỏi endpoint của Service để chỉ định tuyến traffic đến các Pod khỏe mạnh.

Dưới đây là một số thành phần chính cung cấp khả năng tự phục hồi của Kubernetes:

  • kubelet: Đảm bảo rằng các container đang chạy, và khởi động lại những container bị lỗi.

  • ReplicaSet, StatefulSet và DaemonSet controller: Duy trì số lượng replica Pod mong muốn.

  • PersistentVolume controller: Quản lý việc gắn kết và tháo gỡ volume cho các stateful workload.

Những điều cần cân nhắc

  • Lỗi Storage: Nếu một persistent volume trở nên không khả dụng, có thể cần các bước phục hồi thủ công.

  • Lỗi Ứng dụng: Kubernetes có thể khởi động lại container, nhưng các vấn đề ứng dụng cơ bản phải được giải quyết riêng biệt.

Tiếp theo là gì

3.4.4 - Proxy Đa Phiên Bản (Mixed Version Proxy)

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

Kubernetes 1.37 giới thiệu một tính năng alpha cho phép API Server proxy các yêu cầu tài nguyên đến các API server ngang hàng khác. Tính năng này đặc biệt hữu ích khi trong một cụm có nhiều API server đang chạy các phiên bản Kubernetes khác nhau (ví dụ: trong quá trình nâng cấp cụm kéo dài sang phiên bản mới).

Điều này giúp quản trị viên của cluster cấu hình các cluster có độ sẵn sàng cao (high availability) có thể được nâng cấp một cách an toàn hơn, bằng cách chuyển hướng các yêu cầu tài nguyên (trong thời gian nâng cấp) đến đúng kube-api server. Cơ chế proxy này giúp người dùng tránh gặp lỗi 404 (Not Found) không mong muốn do quá trình nâng cấp gây ra.

Cơ chế này được gọi là Proxy Đa Phiên Bản.

Bật tính năng Proxy Đa Phiên Bản

Đảm bảo rằng cờ feature gate UnknownVersionInteroperabilityProxy đã được bật khi khởi động API Server:

kube-apiserver \
--feature-gates=UnknownVersionInteroperabilityProxy=true \
# các tham số dòng lệnh bắt buộc cho tính năng này
--peer-ca-file=<đường dẫn đến CA cert của kube-apiserver>
--proxy-client-cert-file=<đường dẫn đến chứng chỉ proxy của aggregator>,
--proxy-client-key-file=<đường dẫn đến khóa proxy của aggregator>,
--requestheader-client-ca-file=<đường dẫn đến CA cert của aggregator>,
# requestheader-allowed-names có thể để trống để chấp nhận mọi Common Name
--requestheader-allowed-names=<các Common Name hợp lệ để xác minh chứng chỉ proxy client>,

# các cờ tuỳ chọn cho tính năng này
--peer-advertise-ip=<Địa chỉ IP của kube-apiserver này để peer sử dụng khi proxy> --peer-advertise-port=<Cổng mà kube-apiserver này mở để peer sử dụng khi proxy>

# …và các cờ khác như thường lệ

Kết nối và xác thực giữa các API server

  • API server nguồn tái sử dụng các cờ xác thực client cho API server hiện có là --proxy-client-cert-file và --proxy-client-key-file để trình bày danh tính của nó, danh tính này sẽ được kube-apiserver đích (destination kube-apiserver) xác minh. API server đích sẽ xác thực kết nối từ phía đối tác dựa trên cấu hình được chỉ định thông qua tham số dòng lệnh --requestheader-client-ca-file.

  • Để xác thực chứng chỉ phục vụ (serving cert) của API server đích, bạn cần cấu hình một gói chứng chỉ CA bằng cách cung cấp tham số dòng lệnh --peer-ca-file cho API server nguồn.

Cấu hình kết nối tới peer API server

Để khai báo địa chỉ mạng của một API server mà các peer sẽ sử dụng để proxy yêu cầu, sử dụng các tham số --peer-advertise-ip và --peer-advertise-port, hoặc khai báo trong tệp cấu hình của API server.

Nếu không khai báo các cờ này, kube-apiserver sẽ mặc định sử dụng giá trị từ --advertise-address hoặc --bind-address. Nếu các tham số này cũng không được cấu hình, địa chỉ giao diện mạng mặc định của máy chủ sẽ được dùng.

Cơ chế proxy giữa các phiên bản khác nhau

Khi proxy đa phiên bản được bật, aggregation layer sẽ tải một bộ lọc đặc biệt với các hành vi sau:

  • Khi một API server nhận được yêu cầu tài nguyên mà nó không thể xử lý (do chưa hỗ trợ API đó hoặc API bị tắt), nó sẽ tìm cách proxy yêu cầu đến một API server ngang hàng có thể xử lý yêu cầu đó.

Việc này được thực hiện bằng cách xác định các nhóm / phiên bản / tài nguyên API mà server hiện tại không nhận biết, rồi chuyển tiếp yêu cầu tới một peer có thể xử lý được.

  • Nếu API server peer gặp lỗi khi phản hồi, API server nguồn sẽ trả về lỗi 503 ("Service Unavailable").

Cách hoạt động bên trong

Khi một API server nhận yêu cầu tài nguyên, nó kiểm tra xem API server nào có thể xử lý yêu cầu đó. Việc kiểm tra này dựa trên API StorageVersion nội bộ.

  • Nếu tài nguyên đã được API server nhận biết (ví dụ: GET /api/v1/pods/some-pod), yêu cầu sẽ được xử lý tại chỗ.

  • Nếu không có đối tượng StorageVersion nào tương ứng với tài nguyên yêu cầu (ví dụ: GET /my-api/v1/my-resource) nhưng APIService tương ứng được cấu hình để proxy đến một API server mở rộng, thì yêu cầu sẽ được xử lý theo luồng proxy mở rộng.

  • Nếu có một đối tượng StorageVersion hợp lệ cho tài nguyên được yêu cầu (ví dụ: GET /batch/v1/jobs) và API server đang cố xử lý yêu cầu đó (gọi là handling API server) đã tắt nhóm API batch, thì handling API server sẽ truy xuất danh sách các API server ngang hàng (peer API servers) có phục vụ nhóm API / phiên bản / tài nguyên tương ứng (trong trường hợp này là api/batch/v1) dựa trên thông tin từ đối tượng StorageVersion đã truy xuất. Sau đó, handling API server sẽ chuyển tiếp (proxy) yêu cầu đến một trong những kube-apiserver ngang hàng phù hợp, vốn có khả năng xử lý tài nguyên được yêu cầu.

    • Nếu không có peer nào khả dụng cho nhóm / phiên bản / tài nguyên đó, API server sẽ trả lại lỗi 404 ("Not Found").

    • Nếu có peer phù hợp nhưng không phản hồi (do lỗi mạng, hoặc thông tin về peer chưa được đăng ký đúng lúc), thì API server sẽ trả về lỗi 503 ("Service Unavailable").

3.5 - Secrets

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

3.6 - 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.

3.6.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ì

3.6.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.6.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ì

3.6.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ì

3.6.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ì

3.7 - Jobs

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

3.8 - Quản lý tài nguyên cho Containers

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

3.9 - Lưu trữ

Các cách cung cấp lưu trữ dài hạn và tạm thời cho các Pod trong cluster của bạn.

3.9.1 - Persistent Volumes

Tài liệu này mô tả persistent volume trong Kubernetes. Bạn nên làm quen trước với volume, StorageClass và VolumeAttributesClass.

Giới thiệu

Quản lý lưu trữ là một bài toán khác hẳn với quản lý các phiên bản tính toán. Hệ thống con PersistentVolume cung cấp một API cho người dùng và quản trị viên, giúp tách biệt chi tiết về cách lưu trữ được cung cấp khỏi cách nó được sử dụng. Để làm điều này, chúng tôi giới thiệu hai tài nguyên API mới: PersistentVolume và PersistentVolumeClaim.

Một PersistentVolume (PV) là một phần lưu trữ trong cluster, được quản trị viên cấp phát hoặc được cấp phát động bằng Storage Class. Nó là một tài nguyên trong cluster, giống như node là một tài nguyên của cluster. PV là các volume plugin giống như Volume, nhưng có vòng đời độc lập với bất kỳ Pod riêng lẻ nào sử dụng PV đó. Đối tượng API này nắm giữ các chi tiết về cách triển khai lưu trữ, dù đó là NFS, iSCSI, hay một hệ thống lưu trữ riêng của nhà cung cấp đám mây.

Một PersistentVolumeClaim (PVC) là một yêu cầu lưu trữ của người dùng. Nó tương tự như một Pod. Pod tiêu thụ tài nguyên của node, còn PVC tiêu thụ tài nguyên của PV. Pod có thể yêu cầu các mức tài nguyên cụ thể (CPU và bộ nhớ). Claim có thể yêu cầu kích thước và chế độ truy cập (access mode) cụ thể (ví dụ: có thể được mount ở chế độ ReadWriteOnce, ReadOnlyMany, ReadWriteMany, hoặc ReadWriteOncePod, xem AccessModes).

Mặc dù PersistentVolumeClaim cho phép người dùng tiêu thụ tài nguyên lưu trữ trừu tượng, người dùng thường cần các PersistentVolume với những thuộc tính khác nhau, chẳng hạn như hiệu năng, cho các bài toán khác nhau. Quản trị viên cluster cần có khả năng cung cấp nhiều loại PersistentVolume khác nhau không chỉ về kích thước và chế độ truy cập, mà không để người dùng phải tiếp xúc với chi tiết về cách các volume đó được triển khai. Để đáp ứng những nhu cầu này, có tài nguyên StorageClass.

Xem hướng dẫn chi tiết kèm các ví dụ hoạt động được.

Vòng đời của volume và claim

PV là các tài nguyên trong cluster. PVC là các yêu cầu đối với những tài nguyên đó và cũng đóng vai trò như phiếu nhận tài nguyên. Tương tác giữa PV và PVC tuân theo vòng đời sau:

Cấp phát (provisioning)

Có hai cách để cấp phát PV: tĩnh hoặc động.

Tĩnh

Quản trị viên cluster tạo một số PV. Chúng chứa thông tin chi tiết về lưu trữ thực, sẵn sàng cho người dùng cluster sử dụng. Chúng tồn tại trong Kubernetes API và sẵn sàng để được tiêu thụ.

Động

Khi không có PV tĩnh nào do quản trị viên tạo khớp với PersistentVolumeClaim của người dùng, cluster có thể thử cấp phát động một volume dành riêng cho PVC đó. Việc cấp phát này dựa trên StorageClass: PVC phải yêu cầu một storage class và quản trị viên phải đã tạo và cấu hình class đó thì việc cấp phát động mới diễn ra. Các claim yêu cầu class "" thực chất đã tắt cấp phát động cho chính chúng.

Để bật cấp phát lưu trữ động dựa trên storage class, quản trị viên cluster cần bật admission controller DefaultStorageClass trên API server. Ví dụ, có thể làm điều này bằng cách đảm bảo DefaultStorageClass nằm trong danh sách giá trị có thứ tự, phân tách bằng dấu phẩy, của cờ --enable-admission-plugins của thành phần API server. Để biết thêm thông tin về các cờ dòng lệnh của API server, hãy xem tài liệu về kube-apiserver.

Gắn kết (binding)

Người dùng tạo, hoặc trong trường hợp cấp phát động thì đã tạo sẵn, một PersistentVolumeClaim với một lượng lưu trữ cụ thể được yêu cầu và với một số chế độ truy cập nhất định. Một vòng điều khiển trong control plane theo dõi các PVC mới, tìm một PV phù hợp (nếu có thể), và gắn chúng với nhau. Nếu một PV được cấp phát động cho một PVC mới, vòng điều khiển sẽ luôn gắn PV đó với PVC. Ngược lại, người dùng sẽ luôn nhận được ít nhất những gì họ yêu cầu, nhưng volume có thể lớn hơn mức được yêu cầu. Một khi đã được gắn, việc gắn kết PersistentVolumeClaim là độc quyền, bất kể chúng được gắn theo cách nào. Việc gắn kết PVC với PV là ánh xạ một-một, sử dụng ClaimRef, là một liên kết hai chiều giữa PersistentVolume và PersistentVolumeClaim.

Claim sẽ ở trạng thái chưa được gắn vô thời hạn nếu không tồn tại volume phù hợp. Claim sẽ được gắn khi có volume phù hợp. Ví dụ, một cluster được cấp phát nhiều PV 50Gi sẽ không khớp với một PVC yêu cầu 100Gi. PVC có thể được gắn khi một PV 100Gi được thêm vào cluster.

Sử dụng

Pod sử dụng claim như volume. Cluster kiểm tra claim để tìm volume đã được gắn và mount volume đó cho Pod. Với các volume hỗ trợ nhiều chế độ truy cập, người dùng chỉ định chế độ mong muốn khi sử dụng claim của họ làm volume trong Pod.

Khi người dùng có một claim và claim đó đã được gắn, PV đã gắn thuộc về người dùng trong suốt thời gian họ cần. Người dùng lập lịch Pod và truy cập các PV đã claim bằng cách thêm phần persistentVolumeClaim vào khối volumes của Pod. Xem Claim dưới dạng volume để biết thêm chi tiết.

Bảo vệ đối tượng lưu trữ đang được sử dụng

Mục đích của tính năng Bảo vệ đối tượng lưu trữ đang được sử dụng (Storage Object in Use Protection) là đảm bảo rằng các PersistentVolumeClaim (PVC) đang được Pod sử dụng và các PersistentVolume (PV) đã được gắn với PVC không bị xóa khỏi hệ thống, vì điều này có thể dẫn đến mất dữ liệu.

Lưu ý:

PVC được coi là đang được Pod sử dụng khi tồn tại một đối tượng Pod đang dùng PVC đó.

Nếu người dùng xóa một PVC đang được Pod sử dụng, PVC sẽ không bị xóa ngay lập tức. Việc xóa PVC được hoãn lại cho đến khi PVC không còn được Pod nào sử dụng. Tương tự, nếu quản trị viên xóa một PV đã được gắn với một PVC, PV sẽ không bị xóa ngay lập tức. Việc xóa PV được hoãn lại cho đến khi PV không còn được gắn với PVC nào.

Bạn có thể thấy một PVC đang được bảo vệ khi trạng thái của PVC là Terminating và danh sách Finalizers có chứa kubernetes.io/pvc-protection:

kubectl describe pvc hostpath
Name:          hostpath
Namespace:     default
StorageClass:  example-hostpath
Status:        Terminating
Volume:
Labels:        <none>
Annotations:   volume.beta.kubernetes.io/storage-class=example-hostpath
               volume.beta.kubernetes.io/storage-provisioner=example.com/hostpath
Finalizers:    [kubernetes.io/pvc-protection]
...

Tương tự, bạn có thể thấy một PV đang được bảo vệ khi trạng thái của PV là Terminating và danh sách Finalizers có chứa kubernetes.io/pv-protection:

kubectl describe pv task-pv-volume
Name:            task-pv-volume
Labels:          type=local
Annotations:     <none>
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    standard
Status:          Terminating
Claim:
Reclaim Policy:  Delete
Access Modes:    RWO
Capacity:        1Gi
Message:
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /tmp/data
    HostPathType:
Events:            <none>

Thu hồi (reclaiming)

Khi người dùng không còn cần volume, họ có thể xóa các đối tượng PVC khỏi API để cho phép thu hồi tài nguyên. Chính sách thu hồi (reclaim policy) của một PersistentVolume cho cluster biết phải làm gì với volume sau khi nó được giải phóng khỏi claim. Hiện tại, volume có thể được giữ lại (Retain), tái chế (Recycle), hoặc xóa (Delete).

Retain

Chính sách thu hồi Retain cho phép thu hồi tài nguyên thủ công. Khi PersistentVolumeClaim bị xóa, PersistentVolume vẫn tồn tại và volume được coi là "đã giải phóng" (released). Nhưng nó chưa sẵn sàng cho một claim khác vì dữ liệu của claim trước đó vẫn còn trên volume. Quản trị viên có thể thu hồi volume thủ công theo các bước sau.

  1. Xóa PersistentVolume. Tài nguyên lưu trữ liên quan trong hạ tầng bên ngoài vẫn tồn tại sau khi PV bị xóa.
  2. Dọn dẹp thủ công dữ liệu trên tài nguyên lưu trữ liên quan cho phù hợp.
  3. Xóa thủ công tài nguyên lưu trữ liên quan.

Nếu bạn muốn tái sử dụng cùng một tài nguyên lưu trữ, hãy tạo một PersistentVolume mới với cùng định nghĩa tài nguyên lưu trữ đó.

Delete

Với các volume plugin hỗ trợ chính sách thu hồi Delete, việc xóa sẽ loại bỏ cả đối tượng PersistentVolume khỏi Kubernetes, lẫn tài nguyên lưu trữ liên quan trong hạ tầng bên ngoài. Các volume được cấp phát động kế thừa chính sách thu hồi của StorageClass tương ứng, mà mặc định là Delete. Quản trị viên nên cấu hình StorageClass theo mong đợi của người dùng; nếu không, PV phải được chỉnh sửa hoặc patch sau khi được tạo. Xem Thay đổi chính sách thu hồi của một PersistentVolume.

Recycle

Cảnh báo:

Chính sách thu hồi Recycle không còn được hỗ trợ. Thay vào đó, cách được khuyến nghị là sử dụng cấp phát động.

Nếu volume plugin bên dưới hỗ trợ, chính sách thu hồi Recycle sẽ thực hiện một thao tác xóa cơ bản (rm -rf /thevolume/*) trên volume và làm cho nó sẵn sàng trở lại cho một claim mới.

Tuy nhiên, quản trị viên có thể cấu hình một bản mẫu (template) Pod tái chế tùy chỉnh bằng các đối số dòng lệnh của Kubernetes controller manager như được mô tả trong tài liệu tham khảo. Bản mẫu Pod tái chế tùy chỉnh phải chứa đặc tả volumes, như trong ví dụ dưới đây:

apiVersion: v1
kind: Pod
metadata:
  name: pv-recycler
  namespace: default
spec:
  restartPolicy: Never
  volumes:
  - name: vol
    hostPath:
      path: /any/path/it/will/be/replaced
  containers:
  - name: pv-recycler
    image: "registry.k8s.io/busybox"
    command: ["/bin/sh", "-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/*  && test -z \"$(ls -A /scrub)\" || exit 1"]
    volumeMounts:
    - name: vol
      mountPath: /scrub

Tuy nhiên, đường dẫn cụ thể được chỉ định trong phần volumes của bản mẫu Pod tái chế tùy chỉnh sẽ được thay thế bằng đường dẫn cụ thể của volume đang được tái chế.

Finalizer bảo vệ việc xóa PersistentVolume

This is a stable feature in Kubernetes, and has been since the 1.33 release. You can no longer toggle this feature (the associated feature gate has been removed).

Có thể thêm finalizer vào PersistentVolume để đảm bảo rằng các PersistentVolume có chính sách thu hồi Delete chỉ bị xóa sau khi lưu trữ bên dưới đã bị xóa.

Finalizer external-provisioner.volume.kubernetes.io/finalizer (được giới thiệu trong v1.31) được thêm vào cả các CSI volume được cấp phát động lẫn được cấp phát tĩnh.

Finalizer kubernetes.io/pv-controller (được giới thiệu trong v1.31) được thêm vào các volume in-tree plugin được cấp phát động và được bỏ qua với các volume in-tree plugin được cấp phát tĩnh.

Sau đây là ví dụ về một volume in-tree plugin được cấp phát động:

kubectl describe pv pvc-74a498d6-3929-47e8-8c02-078c1ece4d78
Name:            pvc-74a498d6-3929-47e8-8c02-078c1ece4d78
Labels:          <none>
Annotations:     kubernetes.io/createdby: vsphere-volume-dynamic-provisioner
                 pv.kubernetes.io/bound-by-controller: yes
                 pv.kubernetes.io/provisioned-by: kubernetes.io/vsphere-volume
Finalizers:      [kubernetes.io/pv-protection kubernetes.io/pv-controller]
StorageClass:    vcp-sc
Status:          Bound
Claim:           default/vcp-pvc-1
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        1Gi
Node Affinity:   <none>
Message:
Source:
    Type:               vSphereVolume (a Persistent Disk resource in vSphere)
    VolumePath:         [vsanDatastore] d49c4a62-166f-ce12-c464-020077ba5d46/kubernetes-dynamic-pvc-74a498d6-3929-47e8-8c02-078c1ece4d78.vmdk
    FSType:             ext4
    StoragePolicyName:  vSAN Default Storage Policy
Events:                 <none>

Finalizer external-provisioner.volume.kubernetes.io/finalizer được thêm vào cho các CSI volume. Sau đây là một ví dụ:

Name:            pvc-2f0bab97-85a8-4552-8044-eb8be45cf48d
Labels:          <none>
Annotations:     pv.kubernetes.io/provisioned-by: csi.vsphere.vmware.com
Finalizers:      [kubernetes.io/pv-protection external-provisioner.volume.kubernetes.io/finalizer]
StorageClass:    fast
Status:          Bound
Claim:           demo-app/nginx-logs
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        200Mi
Node Affinity:   <none>
Message:
Source:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            csi.vsphere.vmware.com
    FSType:            ext4
    VolumeHandle:      44830fa8-79b4-406b-8b58-621ba25353fd
    ReadOnly:          false
    VolumeAttributes:      storage.kubernetes.io/csiProvisionerIdentity=1648442357185-8081-csi.vsphere.vmware.com
                           type=vSphere CNS Block Volume
Events:                <none>

Khi cờ tính năng CSIMigration{provider} được bật cho một in-tree volume plugin cụ thể, finalizer kubernetes.io/pv-controller sẽ được thay thế bằng finalizer external-provisioner.volume.kubernetes.io/finalizer.

Các finalizer đảm bảo rằng đối tượng PV chỉ bị xóa sau khi volume đã bị xóa khỏi backend lưu trữ, với điều kiện chính sách thu hồi của PV là Delete. Điều này cũng đảm bảo rằng volume bị xóa khỏi backend lưu trữ bất kể thứ tự xóa PV và PVC.

Đặt trước một PersistentVolume

Control plane có thể gắn các PersistentVolumeClaim với các PersistentVolume phù hợp trong cluster. Tuy nhiên, nếu bạn muốn một PVC gắn với một PV cụ thể, bạn cần gắn trước chúng.

Bằng cách chỉ định một PersistentVolume trong một PersistentVolumeClaim, bạn khai báo việc gắn kết giữa PV và PVC cụ thể đó. Nếu PersistentVolume tồn tại và chưa đặt trước PersistentVolumeClaim nào thông qua trường claimRef của nó, thì PersistentVolume và PersistentVolumeClaim sẽ được gắn với nhau.

Việc gắn kết diễn ra bất kể một số tiêu chí khớp volume, bao gồm cả node affinity. Control plane vẫn kiểm tra rằng storage class, chế độ truy cập và kích thước lưu trữ được yêu cầu là hợp lệ.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: foo-pvc
  namespace: foo
spec:
  storageClassName: "" # Phải đặt chuỗi rỗng một cách tường minh, nếu không StorageClass mặc định sẽ được đặt
  volumeName: foo-pv
  ...

Phương pháp này không đảm bảo bất kỳ quyền ưu tiên gắn kết nào đối với PersistentVolume. Nếu các PersistentVolumeClaim khác có thể sử dụng PV mà bạn chỉ định, trước tiên bạn cần đặt trước volume lưu trữ đó. Hãy chỉ định PersistentVolumeClaim liên quan trong trường claimRef của PV để các PVC khác không thể gắn với nó.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: foo-pv
spec:
  storageClassName: ""
  claimRef:
    name: foo-pvc
    namespace: foo
  ...

Điều này hữu ích nếu bạn muốn sử dụng các PersistentVolume có persistentVolumeReclaimPolicy được đặt thành Retain, bao gồm cả trường hợp bạn đang tái sử dụng một PV có sẵn.

Mở rộng Persistent Volume Claim

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

Hỗ trợ mở rộng PersistentVolumeClaim (PVC) được bật theo mặc định. Bạn có thể mở rộng các loại volume sau:

  • csi (bao gồm một số loại volume đã được di chuyển sang CSI)
  • flexVolume (không còn được hỗ trợ)
  • portworxVolume (không còn được hỗ trợ)

Bạn chỉ có thể mở rộng một PVC nếu trường allowVolumeExpansion của storage class tương ứng được đặt thành true.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: example-vol-default
provisioner: vendor-name.example/magicstorage
parameters:
  resturl: "http://192.168.10.100:8080"
  restuser: ""
  secretNamespace: ""
  secretName: ""
allowVolumeExpansion: true

Để yêu cầu một volume lớn hơn cho PVC, hãy chỉnh sửa đối tượng PVC và chỉ định một kích thước lớn hơn. Việc này kích hoạt mở rộng volume nằm dưới PersistentVolume tương ứng. Một PersistentVolume mới không bao giờ được tạo để đáp ứng claim. Thay vào đó, volume hiện có sẽ được thay đổi kích thước.

Cảnh báo:

Chỉnh sửa trực tiếp kích thước của một PersistentVolume có thể ngăn việc tự động thay đổi kích thước của volume đó. Nếu bạn chỉnh sửa dung lượng của một PersistentVolume, rồi chỉnh sửa .spec của PersistentVolumeClaim tương ứng để kích thước của PersistentVolumeClaim khớp với PersistentVolume, thì sẽ không có việc thay đổi kích thước lưu trữ nào xảy ra. Control plane của Kubernetes sẽ thấy rằng trạng thái mong muốn của cả hai tài nguyên đã khớp nhau, kết luận rằng kích thước volume bên dưới đã được tăng thủ công và không cần thay đổi kích thước.

Mở rộng CSI volume

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

Hỗ trợ mở rộng CSI volume được bật theo mặc định, nhưng nó cũng yêu cầu CSI driver cụ thể phải hỗ trợ mở rộng volume. Hãy tham khảo tài liệu của CSI driver cụ thể đó để biết thêm thông tin.

Thay đổi kích thước volume chứa hệ thống file

Bạn chỉ có thể thay đổi kích thước các volume chứa hệ thống file nếu hệ thống file đó là XFS, Ext3, hoặc Ext4.

Khi một volume chứa hệ thống file, hệ thống file chỉ được thay đổi kích thước khi một Pod mới sử dụng PersistentVolumeClaim ở chế độ ReadWrite. Việc mở rộng hệ thống file được thực hiện khi Pod đang khởi động, hoặc khi Pod đang chạy và hệ thống file bên dưới hỗ trợ mở rộng trực tuyến.

FlexVolume (không còn được hỗ trợ kể từ Kubernetes v1.23) cho phép thay đổi kích thước nếu driver được cấu hình với khả năng RequiresFSResize là true. FlexVolume có thể được thay đổi kích thước khi Pod khởi động lại.

Thay đổi kích thước PersistentVolumeClaim đang được sử dụng

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

Trong trường hợp này, bạn không cần xóa và tạo lại Pod hoặc deployment đang sử dụng PVC hiện có. Mọi PVC đang được sử dụng sẽ tự động sẵn sàng cho Pod của nó ngay khi hệ thống file của nó đã được mở rộng. Tính năng này không có tác dụng với các PVC không được Pod hoặc deployment nào sử dụng. Bạn phải tạo một Pod sử dụng PVC trước khi việc mở rộng có thể hoàn tất.

Tương tự như các loại volume khác - volume FlexVolume cũng có thể được mở rộng khi đang được Pod sử dụng.

Lưu ý:

Chỉ có thể thay đổi kích thước FlexVolume khi driver bên dưới hỗ trợ thay đổi kích thước.

Khôi phục khi mở rộng volume thất bại

Nếu người dùng chỉ định một kích thước mới quá lớn mà hệ thống lưu trữ bên dưới không thể đáp ứng, việc mở rộng PVC sẽ được thử lại liên tục cho đến khi người dùng hoặc quản trị viên cluster thực hiện hành động nào đó. Điều này có thể không mong muốn, vì vậy Kubernetes cung cấp các phương pháp sau để khôi phục từ những lỗi như vậy.

Nếu việc mở rộng lưu trữ bên dưới thất bại, quản trị viên cluster có thể khôi phục thủ công trạng thái của Persistent Volume Claim (PVC) và hủy các yêu cầu thay đổi kích thước. Nếu không, các yêu cầu thay đổi kích thước sẽ được controller thử lại liên tục mà không cần sự can thiệp của quản trị viên.

  1. Đánh dấu PersistentVolume (PV) đã được gắn với PersistentVolumeClaim (PVC) bằng chính sách thu hồi Retain.
  2. Xóa PVC. Vì PV có chính sách thu hồi Retain nên chúng ta sẽ không mất dữ liệu khi tạo lại PVC.
  3. Xóa mục claimRef khỏi đặc tả của PV để PVC mới có thể gắn với nó. Việc này sẽ làm cho PV trở thành Available.
  4. Tạo lại PVC với kích thước nhỏ hơn PV và đặt trường volumeName của PVC thành tên của PV. Việc này sẽ gắn PVC mới với PV hiện có.
  5. Đừng quên khôi phục chính sách thu hồi của PV.

Nếu việc mở rộng một PVC thất bại, bạn có thể thử mở rộng lại với kích thước nhỏ hơn giá trị đã yêu cầu trước đó. Để yêu cầu một lần mở rộng mới với kích thước đề xuất nhỏ hơn, hãy chỉnh sửa .spec.resources của PVC đó và chọn một giá trị nhỏ hơn giá trị bạn đã thử trước đó. Điều này hữu ích nếu việc mở rộng lên giá trị cao hơn không thành công do giới hạn dung lượng. Nếu điều đó đã xảy ra, hoặc bạn nghi ngờ rằng nó có thể đã xảy ra, bạn có thể thử mở rộng lại bằng cách chỉ định một kích thước nằm trong giới hạn dung lượng của nhà cung cấp lưu trữ bên dưới. Bạn có thể theo dõi trạng thái của thao tác thay đổi kích thước bằng cách theo dõi .status.allocatedResourceStatuses và các sự kiện trên PVC.

Lưu ý rằng, mặc dù bạn có thể chỉ định lượng lưu trữ thấp hơn mức đã yêu cầu trước đó, giá trị mới vẫn phải cao hơn .status.capacity. Kubernetes không hỗ trợ thu nhỏ một PVC xuống dưới kích thước hiện tại của nó.

Các loại Persistent Volume

Các loại PersistentVolume được triển khai dưới dạng plugin. Kubernetes hiện hỗ trợ các plugin sau:

  • csi - Container Storage Interface (CSI)
  • fc - Lưu trữ Fibre Channel (FC)
  • hostPath - Volume HostPath (chỉ dùng để kiểm thử trên một node; SẼ KHÔNG HOẠT ĐỘNG trong cluster nhiều node; hãy cân nhắc sử dụng volume local thay thế)
  • iscsi - Lưu trữ iSCSI (SCSI over IP)
  • local - các thiết bị lưu trữ cục bộ được mount trên node.
  • nfs - Lưu trữ Network File System (NFS)

Các loại PersistentVolume sau không còn được hỗ trợ nhưng vẫn khả dụng. Nếu bạn đang sử dụng các loại volume này, ngoại trừ flexVolume, cephfs và rbd, hãy cài đặt các CSI driver tương ứng.

  • awsElasticBlockStore - AWS Elastic Block Store (EBS) (di chuyển được bật theo mặc định kể từ v1.23)
  • azureDisk - Azure Disk (di chuyển được bật theo mặc định kể từ v1.23)
  • azureFile - Azure File (di chuyển được bật theo mặc định kể từ v1.24)
  • cinder - Cinder (lưu trữ khối của OpenStack) (di chuyển được bật theo mặc định kể từ v1.21)
  • flexVolume - FlexVolume (không còn được hỗ trợ kể từ v1.23, không có kế hoạch di chuyển và không có kế hoạch loại bỏ hỗ trợ)
  • gcePersistentDisk - GCE Persistent Disk (di chuyển được bật theo mặc định kể từ v1.23)
  • portworxVolume - Volume Portworx (di chuyển được bật theo mặc định kể từ v1.31)
  • vsphereVolume - Volume vSphere VMDK (di chuyển được bật theo mặc định kể từ v1.25)

Các phiên bản Kubernetes cũ hơn cũng từng hỗ trợ các loại PersistentVolume in-tree sau:

  • cephfs (không khả dụng kể từ v1.31)
  • flocker - Lưu trữ Flocker. (không khả dụng kể từ v1.25)
  • glusterfs - Lưu trữ GlusterFS. (không khả dụng kể từ v1.26)
  • photonPersistentDisk - Ổ đĩa persistent của Photon controller. (không khả dụng kể từ v1.15)
  • quobyte - Volume Quobyte. (không khả dụng kể từ v1.25)
  • rbd - Volume Rados Block Device (RBD) (không khả dụng kể từ v1.31)
  • scaleIO - Volume ScaleIO. (không khả dụng kể từ v1.21)
  • storageos - Volume StorageOS. (không khả dụng kể từ v1.25)

Persistent Volume

Mỗi PV chứa một spec và một status, tức là đặc tả và trạng thái của volume. Tên của một đối tượng PersistentVolume phải là một tên DNS subdomain hợp lệ.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /tmp
    server: 172.17.0.2

Lưu ý:

Có thể cần các chương trình hỗ trợ liên quan đến loại volume để sử dụng một PersistentVolume trong cluster. Trong ví dụ này, PersistentVolume thuộc loại NFS và cần chương trình hỗ trợ /sbin/mount.nfs để hỗ trợ việc mount hệ thống file NFS.

Dung lượng

Thông thường, một PV sẽ có một dung lượng lưu trữ cụ thể. Dung lượng này được đặt bằng thuộc tính capacity của PV, là một giá trị Quantity.

Hiện tại, kích thước lưu trữ là tài nguyên duy nhất có thể được đặt hoặc yêu cầu. Các thuộc tính trong tương lai có thể bao gồm IOPS, thông lượng, v.v.

Chế độ volume

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

Kubernetes hỗ trợ hai volumeModes cho PersistentVolume: Filesystem và Block.

volumeMode là một tham số API tùy chọn. Filesystem là chế độ mặc định được dùng khi bỏ qua tham số volumeMode.

Một volume với volumeMode: Filesystem được mount vào một thư mục trong Pod. Nếu volume dựa trên một thiết bị khối (block device) và thiết bị đó trống, Kubernetes sẽ tạo một hệ thống file trên thiết bị trước khi mount nó lần đầu tiên.

Bạn có thể đặt giá trị của volumeMode thành Block để sử dụng volume như một thiết bị khối thô (raw block device). Volume như vậy được trình bày trong Pod dưới dạng một thiết bị khối, không có hệ thống file nào trên đó. Chế độ này hữu ích để cung cấp cho Pod cách nhanh nhất có thể để truy cập volume, mà không có lớp hệ thống file nào giữa Pod và volume. Mặt khác, ứng dụng chạy trong Pod phải biết cách xử lý một thiết bị khối thô. Xem Hỗ trợ raw block volume để biết ví dụ về cách sử dụng volume với volumeMode: Block trong Pod.

Chế độ truy cập

Một PersistentVolume có thể được mount trên một host theo bất kỳ cách nào mà nhà cung cấp tài nguyên hỗ trợ. Như trong bảng dưới đây, các nhà cung cấp sẽ có những khả năng khác nhau và chế độ truy cập của mỗi PV được đặt theo các chế độ cụ thể mà volume đó hỗ trợ. Ví dụ, NFS có thể hỗ trợ nhiều client đọc/ghi, nhưng một PV NFS cụ thể có thể được export trên server ở chế độ chỉ đọc. Mỗi PV có tập hợp chế độ truy cập riêng mô tả khả năng của chính PV đó.

Các chế độ truy cập gồm:

ReadWriteOnce
volume có thể được mount ở chế độ đọc-ghi bởi một node duy nhất. Chế độ truy cập ReadWriteOnce vẫn có thể cho phép nhiều pod truy cập (đọc hoặc ghi) volume đó khi các pod chạy trên cùng một node. Để chỉ một pod truy cập, hãy xem ReadWriteOncePod.
ReadOnlyMany
volume có thể được mount ở chế độ chỉ đọc bởi nhiều node.
ReadWriteMany
volume có thể được mount ở chế độ đọc-ghi bởi nhiều node.
ReadWriteOncePod
TRẠNG THÁI TÍNH NĂNG: GA since Kubernetes v1.29
volume có thể được mount ở chế độ đọc-ghi bởi một Pod duy nhất. Hãy dùng chế độ truy cập ReadWriteOncePod nếu bạn muốn đảm bảo rằng chỉ một pod trong toàn bộ cluster có thể đọc hoặc ghi vào PVC đó.

Lưu ý:

Chế độ truy cập ReadWriteOncePod chỉ được hỗ trợ cho các CSI volume và Kubernetes phiên bản 1.22 trở lên. Để sử dụng tính năng này, bạn cần cập nhật các CSI sidecar sau lên các phiên bản này hoặc mới hơn:

Trong CLI, các chế độ truy cập được viết tắt như sau:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany
  • RWOP - ReadWriteOncePod

Lưu ý:

Kubernetes sử dụng chế độ truy cập của volume để khớp PersistentVolumeClaim với PersistentVolume. Trong một số trường hợp, chế độ truy cập của volume cũng giới hạn nơi PersistentVolume có thể được mount. Chế độ truy cập của volume không áp đặt cơ chế chống ghi sau khi lưu trữ đã được mount. Ngay cả khi chế độ truy cập được chỉ định là ReadWriteOnce, ReadOnlyMany, hoặc ReadWriteMany, chúng không đặt ra bất kỳ ràng buộc nào lên volume. Ví dụ, ngay cả khi một PersistentVolume được tạo với ReadOnlyMany, không có gì đảm bảo rằng nó sẽ ở chế độ chỉ đọc. Nếu chế độ truy cập được chỉ định là ReadWriteOncePod, volume sẽ bị ràng buộc và chỉ có thể được mount trên một Pod duy nhất.

Quan trọng! Một volume chỉ có thể được mount bằng một chế độ truy cập tại một thời điểm, ngay cả khi nó hỗ trợ nhiều chế độ.

Volume PluginReadWriteOnceReadOnlyManyReadWriteManyReadWriteOncePod
AzureFile✓✓✓-
CephFS✓✓✓-
CSItùy thuộc vào drivertùy thuộc vào drivertùy thuộc vào drivertùy thuộc vào driver
FC✓✓--
FlexVolume✓✓tùy thuộc vào driver-
HostPath✓---
iSCSI✓✓--
NFS✓✓✓-
RBD✓✓--
VsphereVolume✓-- (hoạt động khi các Pod được đặt cùng chỗ)-
PortworxVolume✓-✓-

Class

Một PV có thể có một class, được chỉ định bằng cách đặt thuộc tính storageClassName thành tên của một StorageClass. Một PV thuộc một class cụ thể chỉ có thể được gắn với các PVC yêu cầu class đó. Một PV không có storageClassName thì không có class và chỉ có thể được gắn với các PVC không yêu cầu class cụ thể nào.

Trước đây, annotation volume.beta.kubernetes.io/storage-class được dùng thay cho thuộc tính storageClassName. Annotation này vẫn hoạt động; tuy nhiên, nó sẽ hoàn toàn không còn được hỗ trợ trong một bản phát hành Kubernetes tương lai.

Chính sách thu hồi

Các chính sách thu hồi hiện tại gồm:

  • Retain -- thu hồi thủ công
  • Recycle -- xóa cơ bản (rm -rf /thevolume/*)
  • Delete -- xóa volume

Với Kubernetes 1.37, chỉ các loại volume nfs và hostPath hỗ trợ tái chế.

Tùy chọn mount

Quản trị viên Kubernetes có thể chỉ định các tùy chọn mount bổ sung khi một Persistent Volume được mount trên một node.

Lưu ý:

Không phải loại Persistent Volume nào cũng hỗ trợ tùy chọn mount.

Các loại volume sau hỗ trợ tùy chọn mount:

  • csi (bao gồm các loại volume đã được di chuyển sang CSI)
  • iscsi
  • nfs

Tùy chọn mount không được xác thực. Nếu một tùy chọn mount không hợp lệ, việc mount sẽ thất bại.

Trước đây, annotation volume.beta.kubernetes.io/mount-options được dùng thay cho thuộc tính mountOptions. Annotation này vẫn hoạt động; tuy nhiên, nó sẽ hoàn toàn không còn được hỗ trợ trong một bản phát hành Kubernetes tương lai.

Node affinity

Lưu ý:

Với hầu hết các loại volume, bạn không cần đặt trường này. Bạn cần đặt trường này một cách tường minh cho các volume local.

Một PV có thể chỉ định node affinity để xác định các ràng buộc giới hạn những node nào có thể truy cập volume này. Các Pod sử dụng một PV sẽ chỉ được lập lịch lên các node được node affinity chọn. Để chỉ định node affinity, hãy đặt nodeAffinity trong .spec của PV. Tài liệu tham khảo API PersistentVolume có thêm chi tiết về trường này.

Cập nhật node affinity

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

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

See Enable Or Disable Feature Gates for more information.

Nếu feature gate MutablePVNodeAffinity được bật trong cluster của bạn, trường .spec.nodeAffinity của một PersistentVolume có thể thay đổi được. Điều này cho phép quản trị viên cluster hoặc controller lưu trữ bên ngoài cập nhật node affinity của một PersistentVolume khi dữ liệu được di chuyển, mà không làm gián đoạn các pod đang chạy.

Khi cập nhật node affinity, bạn nên đảm bảo rằng node affinity mới vẫn khớp với các node mà volume hiện đang được sử dụng. Với các pod vi phạm affinity mới, nếu pod đã đang chạy thì nó có thể tiếp tục chạy. Nhưng Kubernetes không hỗ trợ cấu hình này. Bạn nên sớm chấm dứt các pod vi phạm. Do cơ chế cache trong bộ nhớ, các pod được tạo sau khi cập nhật vẫn có thể được lập lịch theo node affinity cũ trong một khoảng thời gian ngắn.

Để sử dụng tính năng này, bạn nên bật feature gate MutablePVNodeAffinity trên các thành phần sau:

  • kube-apiserver
  • kubelet

Giai đoạn

Một PersistentVolume sẽ ở một trong các giai đoạn (phase) sau:

Available
một tài nguyên rảnh, chưa được gắn với claim nào
Bound
volume đã được gắn với một claim
Released
claim đã bị xóa, nhưng tài nguyên lưu trữ liên quan chưa được cluster thu hồi
Failed
volume đã thất bại trong quá trình thu hồi (tự động)

Bạn có thể xem tên của PVC được gắn với PV bằng lệnh kubectl describe persistentvolume <name>.

Dấu thời gian chuyển giai đoạn

This is a stable feature in Kubernetes, and has been since the 1.31 release. You can no longer toggle this feature (the associated feature gate has been removed).

Trường .status của một PersistentVolume có thể bao gồm trường alpha lastPhaseTransitionTime. Trường này ghi lại dấu thời gian của lần cuối cùng volume chuyển giai đoạn. Với các volume mới được tạo, giai đoạn được đặt là Pending và lastPhaseTransitionTime được đặt là thời điểm hiện tại.

PersistentVolumeClaim

Mỗi PVC chứa một spec và một status, tức là đặc tả và trạng thái của claim. Tên của một đối tượng PersistentVolumeClaim phải là một tên DNS subdomain hợp lệ.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
      - {key: environment, operator: In, values: [dev]}

Chế độ truy cập

Claim sử dụng cùng quy ước như volume khi yêu cầu lưu trữ với các chế độ truy cập cụ thể.

Chế độ volume

Claim sử dụng cùng quy ước như volume để cho biết volume được sử dụng dưới dạng hệ thống file hay thiết bị khối.

Tên volume

Claim có thể sử dụng trường volumeName để gắn một cách tường minh với một PersistentVolume cụ thể. Bạn cũng có thể để volumeName trống, cho biết rằng bạn muốn Kubernetes thiết lập một PersistentVolume mới khớp với claim. Nếu PV được chỉ định đã được gắn với một PVC khác, việc gắn kết sẽ bị kẹt ở trạng thái chờ (pending).

Tài nguyên

Giống như Pod, claim có thể yêu cầu một lượng tài nguyên cụ thể. Trong trường hợp này, yêu cầu là dành cho lưu trữ. Cùng một mô hình tài nguyên áp dụng cho cả volume và claim.

Lưu ý:

Với các volume Filesystem, yêu cầu lưu trữ đề cập đến kích thước volume "bên ngoài" (tức là kích thước được cấp phát từ backend lưu trữ). Điều này có nghĩa là kích thước có thể ghi được có thể thấp hơn một chút đối với các nhà cung cấp xây dựng hệ thống file trên một thiết bị khối, do chi phí phụ trội của hệ thống file. Điều này đặc biệt dễ thấy với XFS, nơi nhiều tính năng siêu dữ liệu (metadata) được bật theo mặc định.

Selector

Claim có thể chỉ định một label selector để lọc thêm tập hợp các volume. Chỉ những volume có label khớp với selector mới có thể được gắn với claim. Selector có thể gồm hai trường:

  • matchLabels - volume phải có một label với giá trị này
  • matchExpressions - một danh sách các yêu cầu được tạo bằng cách chỉ định key, danh sách giá trị, và toán tử liên hệ giữa key và các giá trị. Các toán tử hợp lệ gồm In, NotIn, Exists và DoesNotExist.

Tất cả các yêu cầu, từ cả matchLabels và matchExpressions, được kết hợp bằng phép AND – tất cả đều phải được thỏa mãn thì mới khớp.

Class

Một claim có thể yêu cầu một class cụ thể bằng cách chỉ định tên của một StorageClass qua thuộc tính storageClassName. Chỉ những PV thuộc class được yêu cầu, tức là những PV có cùng storageClassName với PVC, mới có thể được gắn với PVC.

PVC không nhất thiết phải yêu cầu một class. Một PVC có storageClassName được đặt bằng "" luôn được hiểu là đang yêu cầu một PV không có class, do đó nó chỉ có thể được gắn với các PV không có class (không có annotation hoặc annotation được đặt bằng ""). Một PVC không có storageClassName thì không hoàn toàn giống vậy và được cluster xử lý khác đi, tùy thuộc vào việc admission plugin DefaultStorageClass có được bật hay không.

  • Nếu admission plugin được bật, quản trị viên có thể chỉ định một StorageClass mặc định. Tất cả các PVC không có storageClassName chỉ có thể được gắn với các PV thuộc class mặc định đó. Việc chỉ định StorageClass mặc định được thực hiện bằng cách đặt annotation storageclass.kubernetes.io/is-default-class bằng true trong một đối tượng StorageClass. Nếu quản trị viên không chỉ định class mặc định, cluster sẽ phản hồi việc tạo PVC như thể admission plugin đã bị tắt. Nếu có nhiều hơn một StorageClass mặc định được chỉ định, class mặc định mới nhất sẽ được dùng khi PVC được cấp phát động.
  • Nếu admission plugin bị tắt, sẽ không có khái niệm StorageClass mặc định. Tất cả các PVC có storageClassName được đặt thành "" chỉ có thể được gắn với các PV cũng có storageClassName được đặt thành "". Tuy nhiên, các PVC thiếu storageClassName có thể được cập nhật sau khi StorageClass mặc định khả dụng. Nếu PVC được cập nhật, nó sẽ không còn gắn với các PV có storageClassName cũng được đặt thành "".

Xem gán StorageClass mặc định hồi tố để biết thêm chi tiết.

Tùy thuộc vào phương thức cài đặt, một StorageClass mặc định có thể được addon manager triển khai vào cluster Kubernetes trong quá trình cài đặt.

Khi một PVC chỉ định một selector ngoài việc yêu cầu một StorageClass, các yêu cầu được kết hợp bằng phép AND: chỉ một PV thuộc class được yêu cầu và có các label được yêu cầu mới có thể được gắn với PVC.

Lưu ý:

Hiện tại, một PVC có selector không rỗng không thể được cấp phát động một PV.

Trước đây, annotation volume.beta.kubernetes.io/storage-class được dùng thay cho thuộc tính storageClassName. Annotation này vẫn hoạt động; tuy nhiên, nó sẽ không được hỗ trợ trong một bản phát hành Kubernetes tương lai.

Gán StorageClass mặc định hồi tố

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

Bạn có thể tạo một PersistentVolumeClaim mà không chỉ định storageClassName cho PVC mới, và bạn có thể làm vậy ngay cả khi không có StorageClass mặc định nào tồn tại trong cluster của bạn. Trong trường hợp này, PVC mới được tạo đúng như bạn đã định nghĩa, và storageClassName của PVC đó vẫn chưa được đặt cho đến khi có class mặc định.

Khi một StorageClass mặc định trở nên khả dụng, control plane sẽ xác định mọi PVC hiện có không có storageClassName. Với các PVC có giá trị rỗng cho storageClassName hoặc không có key này, control plane sau đó sẽ cập nhật các PVC đó để đặt storageClassName khớp với StorageClass mặc định mới. Nếu bạn có một PVC hiện có với storageClassName là "", và bạn cấu hình một StorageClass mặc định, thì PVC này sẽ không được cập nhật.

Để tiếp tục gắn với các PV có storageClassName được đặt thành "" (trong khi có một StorageClass mặc định), bạn cần đặt storageClassName của PVC liên quan thành "".

Hành vi này giúp quản trị viên thay đổi StorageClass mặc định bằng cách xóa class cũ trước rồi tạo hoặc đặt một class khác. Khoảng thời gian ngắn không có class mặc định này khiến các PVC không có storageClassName được tạo vào lúc đó không có class mặc định nào, nhưng nhờ việc gán StorageClass mặc định hồi tố, cách thay đổi class mặc định này là an toàn.

Theo dõi PVC không được sử dụng

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

Khi được bật, PVC protection controller sẽ thêm một condition Unused vào mỗi PersistentVolumeClaim để cho biết liệu nó hiện có đang được tham chiếu bởi Pod nào chưa ở trạng thái kết thúc (non-terminal) hay không.

Condition này có hai trạng thái:

Unused với status "True" (reason NoPodsUsingPVC)
Không có Pod chưa kết thúc nào tham chiếu đến PVC này. lastTransitionTime ghi lại thời điểm PVC trở nên không được sử dụng.
Unused với status "False" (reason PodUsingPVC)
Có ít nhất một Pod chưa kết thúc hiện đang tham chiếu đến PVC này. lastTransitionTime ghi lại thời điểm PVC bắt đầu được sử dụng.

Một Pod được coi là chưa kết thúc nếu giai đoạn của nó không phải là Succeeded hoặc Failed. Điều này có nghĩa là một Pod ở trạng thái Pending (kể cả Pod chưa được lập lịch) cũng được tính là đang sử dụng PVC.

lastTransitionTime của condition Unused có thể được quản trị viên cluster, các công cụ giám sát và các controller bên ngoài sử dụng để xác định những PVC đã không được sử dụng trong thời gian dài. Ví dụ, để tìm tất cả các PVC đã không được sử dụng hơn 30 ngày, bạn có thể truy vấn các PVC có condition Unused với status: "True" và lastTransitionTime cũ hơn 30 ngày.

Lưu ý:

Khoảng thời gian không sử dụng mà condition này cho biết có thể ngắn hơn thời gian không sử dụng thực tế do độ trễ xử lý trong controller hoặc do tính năng được bật sau khi PVC đã không được sử dụng. Condition này không được cập nhật khi PVC có deletionTimestamp được đặt (tức là các PVC đang bị xóa).

Claim dưới dạng volume

Pod truy cập lưu trữ bằng cách sử dụng claim như một volume. Claim phải tồn tại trong cùng namespace với Pod sử dụng claim đó. Cluster tìm claim trong namespace của Pod và sử dụng nó để lấy PersistentVolume nằm dưới claim. Sau đó volume được mount vào host và vào Pod.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

Lưu ý về namespace

Việc gắn kết PersistentVolume là độc quyền, và vì PersistentVolumeClaim là các đối tượng thuộc namespace, việc mount claim với các chế độ "Many" (ROX, RWX) chỉ có thể thực hiện trong phạm vi một namespace.

PersistentVolume loại hostPath

Một PersistentVolume hostPath sử dụng một file hoặc thư mục trên Node để mô phỏng lưu trữ gắn qua mạng. Xem ví dụ về volume loại hostPath.

Hỗ trợ raw block volume

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

Các volume plugin sau hỗ trợ raw block volume, bao gồm cả cấp phát động khi có thể áp dụng:

  • CSI (bao gồm một số loại volume đã được di chuyển sang CSI)
  • FC (Fibre Channel)
  • iSCSI
  • Local volume

PersistentVolume sử dụng raw block volume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: block-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  persistentVolumeReclaimPolicy: Retain
  fc:
    targetWWNs: ["50060e801049cfd1"]
    lun: 0
    readOnly: false

PersistentVolumeClaim yêu cầu raw block volume

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: block-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  resources:
    requests:
      storage: 10Gi

Đặc tả Pod thêm đường dẫn raw block device trong container

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-block-volume
spec:
  containers:
    - name: fc-container
      image: fedora:26
      command: ["/bin/sh", "-c"]
      args: [ "tail -f /dev/null" ]
      volumeDevices:
        - name: data
          devicePath: /dev/xvda
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: block-pvc

Lưu ý:

Khi thêm một raw block device cho Pod, bạn chỉ định đường dẫn thiết bị trong container thay vì đường dẫn mount.

Gắn kết block volume

Nếu người dùng yêu cầu một raw block volume bằng cách chỉ định điều này qua trường volumeMode trong đặc tả PersistentVolumeClaim, các quy tắc gắn kết sẽ hơi khác so với các bản phát hành trước, vốn không coi chế độ này là một phần của đặc tả. Dưới đây là bảng các tổ hợp mà người dùng và quản trị viên có thể chỉ định khi yêu cầu một raw block device. Bảng cho biết volume có được gắn hay không với từng tổ hợp: Ma trận gắn kết volume cho các volume được cấp phát tĩnh:

PV volumeModePVC volumeModeKết quả
không chỉ địnhkhông chỉ địnhGẮN KẾT
không chỉ địnhBlockKHÔNG GẮN KẾT
không chỉ địnhFilesystemGẮN KẾT
Blockkhông chỉ địnhKHÔNG GẮN KẾT
BlockBlockGẮN KẾT
BlockFilesystemKHÔNG GẮN KẾT
FilesystemFilesystemGẮN KẾT
FilesystemBlockKHÔNG GẮN KẾT
Filesystemkhông chỉ địnhGẮN KẾT

Lưu ý:

Chỉ các volume được cấp phát tĩnh mới được hỗ trợ trong bản phát hành alpha. Quản trị viên nên cân nhắc kỹ các giá trị này khi làm việc với raw block device.

Hỗ trợ volume snapshot và khôi phục volume từ snapshot

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

Volume snapshot chỉ hỗ trợ các CSI volume plugin out-of-tree. Để biết chi tiết, xem Volume Snapshot. Các in-tree volume plugin không còn được hỗ trợ. Bạn có thể đọc về các volume plugin không còn được hỗ trợ trong Câu hỏi thường gặp về Volume Plugin.

Tạo PersistentVolumeClaim từ volume snapshot

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: restore-pvc
spec:
  storageClassName: csi-hostpath-sc
  dataSource:
    name: new-snapshot-test
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Nhân bản volume

Nhân bản volume (volume cloning) chỉ khả dụng cho các CSI volume plugin.

Tạo PersistentVolumeClaim từ một PVC có sẵn

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cloned-pvc
spec:
  storageClassName: my-csi-plugin
  dataSource:
    name: existing-src-pvc-name
    kind: PersistentVolumeClaim
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Volume populator và nguồn dữ liệu

Nhân bản volume và khôi phục snapshot điền sẵn dữ liệu cho một volume mới từ một nguồn dữ liệu (data source) có sẵn. Volume populator mở rộng cơ chế này để một PersistentVolumeClaim có thể được điền sẵn dữ liệu từ các loại nguồn khác (một custom resource), được tham chiếu thông qua trường dataSourceRef của nó:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: populated-pvc
spec:
  dataSourceRef:
    name: example-name
    kind: ExampleDataSource
    apiGroup: example.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Để biết chi tiết, bao gồm cả nguồn dữ liệu xuyên namespace, xem Volume Populator và nguồn dữ liệu.

Viết cấu hình di động

Nếu bạn đang viết các bản mẫu cấu hình hoặc ví dụ chạy trên nhiều loại cluster khác nhau và cần lưu trữ persistent, bạn nên sử dụng mô hình sau:

  • Đưa các đối tượng PersistentVolumeClaim vào gói cấu hình của bạn (cùng với Deployment, ConfigMap, v.v.).
  • Không đưa các đối tượng PersistentVolume vào cấu hình, vì người dùng khởi tạo cấu hình có thể không có quyền tạo PersistentVolume.
  • Cho người dùng tùy chọn cung cấp tên storage class khi khởi tạo bản mẫu.
    • Nếu người dùng cung cấp tên storage class, hãy đặt giá trị đó vào trường persistentVolumeClaim.storageClassName. Điều này sẽ khiến PVC khớp với storage class phù hợp nếu cluster có StorageClass được quản trị viên bật.
    • Nếu người dùng không cung cấp tên storage class, hãy để trường persistentVolumeClaim.storageClassName là nil. Điều này sẽ khiến một PV được tự động cấp phát cho người dùng với StorageClass mặc định trong cluster. Nhiều môi trường cluster có cài đặt sẵn một StorageClass mặc định, hoặc quản trị viên có thể tạo StorageClass mặc định của riêng họ.
  • Trong công cụ của bạn, hãy theo dõi các PVC không được gắn sau một khoảng thời gian và thông báo điều này cho người dùng, vì điều này có thể cho thấy cluster không có hỗ trợ lưu trữ động (trong trường hợp đó người dùng nên tạo một PV phù hợp) hoặc cluster không có hệ thống lưu trữ (trong trường hợp đó người dùng không thể triển khai cấu hình yêu cầu PVC).

Tiếp theo là gì

Tài liệu tham khảo API

Đọc về các API được mô tả trong trang này:

3.10 - IPv4/IPv6 dual-stack

Kubernetes cho phép bạn cấu hình mạng IPv4 đơn, mạng IPv6 đơn, hoặc mạng kép với cả hai họ mạng hoạt động. Trang này giải thích cách thức hoạt động.

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

3.11 - Mở rộng Kubernetes

Các cách khác nhau để thay đổi hành vi của cluster Kubernetes của bạn.

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

3.12 - ReplicaSet

Mục đích của ReplicaSet là duy trì một tập hợp ổn định các Pod bản sao đang chạy tại bất kỳ thời điểm nào. Thông thường, bạn định nghĩa một Deployment và để Deployment đó quản lý các ReplicaSet tự động.

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

4 - Tasks

Phần này của tài liệu chứa các hướng dẫn thực hiện các tác vụ. Mỗi tài liệu hướng dẫn tác vụ chỉ dẫn cách thực hiện một việc duy nhất, thường bằng cách đưa ra một chuỗi các bước ngắn.

Các tác vụ bao gồm: Cài đặt tool, chạy jobs, quản lý GPUs, etc.

Bạn có thể tạo và đóng góp tài liệu về một tác vụ mới thông qua Hướng dẫn tạo tài liệu mới.

4.1 - Cài đặt các công cụ

Thiết lập các công cụ Kubernetes trên máy tính của bạn.

kubectl

Công cụ dòng lệnh Kubernetes, kubectl, cho phép bạn chạy các câu lệnh tương tác tới các cụm Kubernetes. Bạn có thể sử dụng kubectl để triển khai các ứng dụng, kiểm tra và quản lý các tài nguyên của cụm, và xem log. Để biết thêm thông tin bao gồm một danh sách đầy đủ các lệnh của kubectl, xem tài liệu tham khảo kubectl.

kubectl có thể cài đặt trên nhiều nền tảng Linux, macOS và Windows. Chọn hệ điều hành ưa thích của bạn bên dưới.

kind

kind cho phép bạn chạy Kubernetes trên máy tính cục bộ của bạn. Công cụ này yêu cầu bạn phải có hoặc Docker hoăc Podman được cài đặt sẵn.

Trang Bắt đầu nhanh của kind cho bạn biết cần phải làm những gì để bắt đầu và chạy với kind.

Xem Hướng dẫn Bắt đầu nhanh của kind

minikube

Giống kind, minikube là một công cụ cho phép bạn chạy Kubernetes cục bộ. minikube chạy một cụm Kubernetes cục bộ tất-cả-trong-một hoặc nhiều-node trên máy tính cá nhân (bao gồm Windows, macOS và Linux) vì vậy bạn có thể thử Kubernetes, hoặc cho công việc phát triển hàng ngày.

Bạn có thể theo dõi hướng dẫn chính thức Bắt đầu! nếu bạn tập trung vào việc cài đặt công cụ.

Xem Hướng dẫn Bắt đầu! của minikube

Một khi bạn có minikube đang chạy, bạn có thể dùng nó để chạy một ứng dụng mẫu.

kubeadm

Bạn có thể dùng công cụ kubeadm để tạo và quản lý các cụm Kubernetes. Nó thực hiện các hành động cần thiết để có được sự khả thi tối thiểu, đảm bảo cụm khởi động và chạy theo một cách thân thiện với người dùng.

Cài đặt kubeadm hướng dẫn bạn cách để cài đặt kubeadm. Một khi được cài đặt, bạn có thể dùng nó để tạo một cụm.

Xem Hướng dẫn Cài đặt kubeadm

4.1.1 - Cài đặt và cấu hình kubectl

Công cụ command-line trong Kubernetes, kubectl, cho phép bạn thực thi các câu lệnh trong Kubernetes clusters. Bạn có thể sử dụng kubectl để triển khai các ứng dụng, theo dõi và quản lý tài nguyên của cluster, và xem log. Để biết các thao tác của kubectl, truy cập tới Tổng quan về kubectl.

Trước khi bạn bắt đầu

Bạn cần phải sử dụng phiên bản kubectl sai lệch không quá một phiên bản với version của cluster. Ví dụ, một client v1.2 nên được hoạt động với master v1.1, v1.2 và v1.3. Sử dụng phiên bản mới nhất của kubectl giúp tránh được các vấn đề không lường trước được.

Cài đặt kubectl trên Linux

Cài đặt kubectl binary với curl trên Linux

  1. Tải về phiên bản mới nhất với câu lệnh:

    curl -LO https://dl.k8s.io/release/`curl -LS https://dl.k8s.io/release/stable.txt`/bin/linux/amd64/kubectl
    

    Để tải về phiên bản cụ thể, hãy thay thế phần $(curl -LS https://dl.k8s.io/release/stable.txt) trong câu lệnh với một phiên bản cụ thể.

    Ví dụ như, để tải về phiên bản 1.37.0 trên Linux, hãy nhập như sau:

    curl -LO https://dl.k8s.io/release/v1.37.0/bin/linux/amd64/kubectl
    
  2. Tạo kubectl binary thực thi.

    chmod +x ./kubectl
    
  3. Đưa bản binary vào biến môi trường PATH của bạn.

    sudo mv ./kubectl /usr/local/bin/kubectl
    
  4. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

Cài đặt kubectl sử dụng trình quản lý gói


sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key
EOF
sudo yum install -y kubectl

Cài đặt với snap

Nếu bạn đang sử dụng Ubuntu hoặc distro Linux khác hỗ trợ trình quản lý gói snap, thì kubectl đã có sẵn trong snap.

  1. Chuyển sang user snap và thực thi câu lệnh cài đặt:

    sudo snap install kubectl --classic
    
  2. Kiểm tra phiên bản bạn vừa cài là mới nhất:

    kubectl version
    

Cài đặt kubectl trên macOS

Cài đặt kubectl binary với curl trên macOS

  1. Tải về phiên bản mới nhất:

    curl -LO "https://dl.k8s.io/release/$(curl -LS https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"
    

    Để tải về phiên bản cụ thể, hãy thay thế phần $(curl -LS https://dl.k8s.io/release/stable.txt) trong câu lệnh với phiên bản cụ thể.

    Ví dụ, để tải về phiên bản 1.37.0 trên macOS, gõ:

    curl -LO https://dl.k8s.io/release/v1.37.0/bin/darwin/amd64/kubectl
    
  2. Tạo kubectl binary thực thi.

    chmod +x ./kubectl
    
  3. Đưa bản binary vào biến môi trường PATH của bạn.

    sudo mv ./kubectl /usr/local/bin/kubectl
    
  4. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

Cài đặt với Homebrew trên macOS

Nếu bạn đang trên macOS và sử dụng trình quản lý gói Homebrew, bạn có thể cài đặt kubectl với Homebrew.

  1. Chạy câu lệnh cài đặt:

    brew install kubectl 
    

    hoặc

    brew install kubernetes-cli
    
  2. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

Cài đặt với Macports trên macOS

Nếu bạn đang trên macOS và sử dụng trình quản lý gói Macports, bạn có thể cài đặt kubectl với Macports.

  1. Chạy câu lệnh cài đặt:

    sudo port selfupdate
    sudo port install kubectl
    
  2. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

Cài đặt kubectl trên Windows

Cài đặt kubectl binary với curl trên Windows

  1. Tải về phiên bản mới nhất 1.37.0 từ đường dẫn này.

    Hoặc nếu bạn đã cài đặt curl, hãy sử dụng câu lệnh sau:

    curl -LO https://dl.k8s.io/release/v1.37.0/bin/windows/amd64/kubectl.exe
    

    Để tìm ra phiên bản ổn định mới nhất, hãy xem https://dl.k8s.io/release/stable.txt.

  2. Đưa bản binary vào biến môi trường PATH của bạn.

  3. Kiểm tra chắn chắn phiên bản kubectl giống với bản đã tải về:

    kubectl version
    

Lưu ý:

Docker Desktop cho Windows thêm phiên bản kubectl riêng của nó vào PATH. Nếu bạn đã cài đặt Docker Desktop trước đây, bạn có thể cần đặt đường dẫn PATH của bạn trước khi bản cài đặt Docker Desktop thêm 1 PATH vào hoặc loại bỏ kubectl của Docker Desktop.

Cài đặt với Powershell từ PSGallery

Nếu bạn đang ở trên Windows và sử dụng trình quản lý gói Powershell Gallery, bạn có thể cài đặt và cập nhật kubectl với Powershell.

  1. Thực thi các câu lệnh cài đặt sau (hãy đảm bảo bạn tự định nghĩa DownloadLocation):

    Install-Script -Name install-kubectl -Scope CurrentUser -Force
    install-kubectl.ps1 [-DownloadLocation <path>]
    

    Lưu ý:

    Nếu bạn không định nghĩa DownloadLocation, kubectl sẽ được cài đặt ở thư mục temp của user.

    Bản cài đặt sẽ tạo ra $HOME/.kube và hướng dẫn để tạo ra file cấu hình

  2. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

    Lưu ý:

    Cập nhật của bản cài đặt sẽ được thực hiện khi chạy lại các câu lệnh từ bước 1.

Cài đặt trên Windows sử dụng Chocolatey hoặc Scoop

Để cài đặt kubectl trên Windows bạn có thể sử dụng trình quản lý gói Chocolatey hoặc bộ cài đặt câu lệnh Scoop.

choco install kubernetes-cli
scoop install kubectl
2. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

```
kubectl version
```
  1. Di chuyển tới thư mục home của bạn:

    cd %USERPROFILE%
    
  2. Tạo thư mục .kube:

    mkdir .kube
    
  3. Di chuyển tới thư mục .kube bạn vừa mới tạo:

    cd .kube
    
  4. Cấu hình kubectl để sử dụng Kubernetes cluster từ xa:

    New-Item config -type file
    

    Lưu ý:

    Chỉnh sửa file cấu hình với trình soạn thảo văn bản, như là Notepad.

Tải xuống từ một phần của Google Cloud SDK

Bạn có thể cài đặt kubectl từ một phần của Google Cloud SDK.

  1. Cài đặt Google Cloud SDK.

  2. Thực thi câu lệnh cài đặt kubectl:

    gcloud components install kubectl
    
  3. Kiểm tra chắc chắn rằng phiên bản bạn cài là mới nhất:

    kubectl version
    

Xác minh cấu hình kubectl

Để kubectl tìm kiếm và truy cập Kubernetes cluster, nó cần một kubeconfig file, được tự động tạo ra khi bạn tạo mới một cluster sử dụng kube-up.sh hoặc triển khai thành công một Minikube cluster. Mặc định thì cấu hình của kubectl được xác định tại ~/.kube/config.

Kiểm tra kubectl được cấu hình đúng bằng việc xem trạng thái của cluster:

kubectl cluster-info

Nếu bạn trông thấy một URL phản hồi, thì kubectl đã được cấu hình đúng để truy cập vào cluster của bạn.

Nếu bạn trông thấy một tin nhắn tương tự bên dưới, thì kuberctl chưa được cấu hình đúng hoặc chưa thể kết nối với Kubernetes cluster.

The connection to the server <server-name:port> was refused - did you specify the right host or port?

Ví dụ như, nếu bạn đang định chạy một Kubernetes cluster trên laptop của bạn (locally), bạn sẽ cần một công cụ như Minikube được cài trước đó và chạy lại các câu lệnh bên trên.

Nếu kubectl cluster-info trả về url nhưng bạn không thể truy cập vào cluster của bạn, thì hãy kiểm tra nó đã được cấu hình đúng hay chưa, bằng cách:

kubectl cluster-info dump

Các lựa chọn cấu hình kubectl

Kích hoạt shell autocompletion

kubectl cung cấp autocompletion hỗ trợ cho Bash and Zsh, giúp bạn giảm thiểu việc phải gõ nhiều câu lệnh.

Bên dưới đâu là các bước để thiết lập autocompletion cho Bash (bao gồm sự khác nhau giữa Linux và macOS) và Zsh.

Giới thiệu

Kubelet completion script cho Bash được tạo ra với câu lệnh kubectl completion bash. Sau khi script được tạo ra, bạn cần source (thực thi) script đó để kích hoạt tính năng autocompletion.

Tuy nhiên, completion script phụ thuộc vào bash-completion, nên bạn phải cài đặt bash-completion trước đó (kiểm tra bash-completion tồn tại với câu lệnh type _init_completion).

Cài đặt bash-completion

bash-completion được cung cấp bởi nhiều trình quản lý gói (xem tại đây). Bạn có thể cài đặt với lệnh apt-get install bash-completion hoặc yum install bash-completion.

Các lệnh trên tạo ra /usr/share/bash-completion/bash_completion, đây là script chính của bash-completion. Tùy thuộc vào trình quản lý gói của bạn, mà bạn phải source (thực thi) file này trong file ~/.bashrc.

Để tìm ra file này, reload lại shell hiện tại của bạn và chạy lệnh type _init_completion. Nếu thành công, bạn đã thiết lập xong, không thì hãy thêm đoạn sau vào file ~/.bashrc của bạn:

source /usr/share/bash-completion/bash_completion

Reload lại shell của bạn và xác nhận bash-completion được cài đặt đúng bằng lệnh type _init_completion.

Kích hoạt kubectl autocompletion

Bây giờ bạn cần đảm bảo rằng kubectl completion script được sourced trên tất cả các session của shell. Có 2 cách để làm việc này:

  • Source script trong file ~/.bashrc:

    echo 'source <(kubectl completion bash)' >>~/.bashrc
    
  • Thêm script vào thư mục /etc/bash_completion.d:

    kubectl completion bash >/etc/bash_completion.d/kubectl
    
  • Nếu bạn có một alias cho kubectl, bạn có thể thêm một shell completion nữa cho alias đó:

    echo 'alias k=kubectl' >>~/.bashrc
    echo 'complete -F __start_kubectl k' >>~/.bashrc
    

Lưu ý:

bash-completion sources tất cả completion scripts trong /etc/bash_completion.d.

Các cách trên đều hiệu quả tương đương nhau. Sau khi reload lại shell, kubectl autocompletion sẽ làm việc.

Giới thiệu

Kubectl completion script trên Bash được tạo ra bởi kubectl completion bash. Source script này sẽ kích hoạt tính năng kubectl completion.

Tuy nhiên, kubectl completion script phụ thuộc vào bash-completion mà bạn cài trước đó.

Cảnh báo:

Có 2 phiên bản của bash-completion là v1 và v2. V1 dành cho Bash 3.2 (Bash mặc định trên macOS), và v2 dành cho Bash 4.1+. Kubectl completion script không làm việc phù hợp với bash-completion v1 và Bash 3.2. Nó tương thích với bash-completion v2 và Bash 4.1+. Vì vậy, để sử dụng kubectl completion một cách chính xác trên macOS thì bạn phải cài đặt Bash 4.1+ (hướng dẫn). Hướng dẫn tiếp theo giả định rằng bạn đang sử dụng Bash 4.1+ (nghĩa là, bất kỳ phiên bản Bash nào từ 4.1 trở lên).

Cài đặt bash-completion

Lưu ý:

Như đã đề cập, những hướng dẫn này giả định bạn đang sử dụng Bash 4.1+, có nghĩa rằng bạn sẽ cài đặt bash-completion v2 (trái ngược với Bash 3.2 và bash-completion v1, trong trường hợp đó, kubectl completion sẽ không hoạt động).

Bạn có thể kiểm tra bash-completion v2 đã cài đặt trước đó chưa với lệnh type _init_completion. Nếu chưa, bạn có thể cài đặt nó với Homebrew:

brew install bash-completion@2

Từ đầu ra của lệnh này, hãy thêm đoạn sau vào file ~/.bashrc của bạn:

export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d"
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"

Tải lại shell của bạn và xác minh rằng bash-completion v2 được cài đặt chính xác chưa bằng lệnh type _init_completion.

Kích hoạt kubectl autocompletion

Bây giờ bạn phải đảm bảo rằng kubectl completion script đã được sourced trong tất cả các phiên shell của bạn. Có nhiều cách để đạt được điều này:

  • Source completion script trong file ~/.bashrc:

    echo 'source <(kubectl completion bash)' >>~/.bashrc
    
  • Thêm completion script vào thư mục /usr/local/etc/bash_completion.d:

    kubectl completion bash >/usr/local/etc/bash_completion.d/kubectl
    
  • Nếu bạn có alias cho kubectl, bạn có thể mở rộng shell completion để làm việc với alias đó:

    echo 'alias k=kubectl' >>~/.bashrc
    echo 'complete -F __start_kubectl k' >>~/.bashrc
    
  • Nếu bạn đã cài kubectl với Homebrew (như đã giới thiệu bên trên)) thì kubectl completion script sẽ có trong /usr/local/etc/bash_completion.d/kubectl. Trong trường hợp này thì bạn không cần làm gì cả.

Lưu ý:

Cài đặt theo cách Homebrew đã source tất cả các tệp trong thư mục BASH_COMPLETION_COMPAT_DIR, đó là lý do tại sao hai phương thức sau hoạt động.

Trong mọi trường hợp, sau khi tải lại shell của bạn, kubectl completion sẽ hoạt động.

Kubectl completion script cho Zsh được tạo ra với lệnh kubectl completion zsh. Source completion script trong shell của bạn sẽ kích hoạt kubectl autocompletion.

Để nó hoạt động cho tất cả các shell, thêm dòng sau vào file ~/.zshrc:

source <(kubectl completion zsh)

Nếu bạn có alias cho kubectl, bạn có thể mở rộng shell completion để làm việc với alias đó:

echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc

Sau khi tải lại shell, kubectl autocompletion sẽ hoạt động.

Nếu bạn nhận được lỗi complete:13: command not found: compdef, thêm dòng sau vào đầu file ~/.zshrc:

autoload -Uz compinit
compinit

Tiếp theo là gì

4.1.2 - Cài đặt Minikube

Tài liệu này sẽ hướng dẫn các bạn cách cài đặt Minikube, một công cụ chạy một Kubernetes cluster chỉ gồm một node trong một máy ảo (VM) trên máy tính của bạn.

Trước khi bạn bắt đầu

Để kiểm tra xem việc ảo hóa (virtualization) có được hỗ trợ trên Linux không, chạy lệnh sau và chắc chắn rằng kết quả trả về là non-empty:

grep -E --color 'vmx|svm' /proc/cpuinfo

Để kiểm tra xem việc ảo hóa (virtualization) có được hỗ trợ trên macOS không, chạy lệnh sau trên terminal:

sysctl -a | grep -E --color 'machdep.cpu.features|VMX' 

Nếu bạn thấy VMX ở kết quả trả về (có màu), thì VT-x đã được hỗ trợ.

Để kiểm tra xem việc ảo hóa (virtualization) có được hỗ trợ trên Windows 8 và các phiên bản Windows cao hơn không, chạy lệnh sau trên terminal của Windows hoặc command promt.

systeminfo

Nếu bạn thấy những thông tin sau, ảo hóa được hỗ trợ trên Windows.

Hyper-V Requirements:     VM Monitor Mode Extensions: Yes
                          Virtualization Enabled In Firmware: Yes
                          Second Level Address Translation: Yes
                          Data Execution Prevention Available: Yes

Nếu bạn thấy thông tin sau, thì hệ thống đã được cài đặt Hypervisor và bạn có thể bỏ qua bước tiếp theo.

Hyper-V Requirements:     A hypervisor has been detected. Features required for Hyper-V will not be displayed.

Cài đặt minikube

Cài đặt kubectl

Đảm bảo bạn đã cài đặt kubectl. Bạn có thể cài đặt kubectl theo hướng dẫn sau tại Install and Set Up kubectl.

Cài đặt Hypervisor

Nếu bạn chưa cài đặt Hypervisor, hãy cài đặt một trong những phần mềm sau đây:

• KVM, sử dụng QEMU

• VirtualBox

Lưu ý:

Minikube cũng hỗ trợ tùy chọn --vm-driver=none để chạy các thành phần của Kubernetes ngay trên máy chủ chứ không phải trong một VM. Sử dụng driver này yêu cầu Docker và môi trường Linux chứ không phải một Hypervisor. Bạn nên sử dụng cài đặt apt của docker từ Docker khi sử dụng non driver. Cài đặt snap của docker không hoạt động với minikube.

Cài đặt Minikube sử dụng package

Có các gói thử nghiệm cho Minikube có sẵn; bạn có thể tìm thấy các gói Linux (AMD64) từ trang phát hành của Minikube trên Github.

Sử dụng các package tool của bản phân phối Linux của bạn để cài đặt package phù hợp.

Cài đặt Minikube thông qua tải xuống trực tiếp

Nếu bạn không cài đặt qua package, bạn có thể tải xuống bản binary và sử dụng.

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
  && chmod +x minikube

Đây là một cách dễ dàng để thêm Minikube vào biến môi trường path của bạn:

sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

Cài đặt Minikube sử dụng Homebrew

Một lựa chọn khác là bạn có thể cài đặt Minikube bằng cách sử dụng Linux Homebrew:

brew install minikube

Cài đặt kubectl

Đảm bảo bạn đã cài đặt kubectl. Bạn có thể cài đặt kubectl theo hướng dẫn sau tại Install and Set Up kubectl.

Cài đặt Hypervisor

Nếu bạn chưa cài đặt Hypervisor, hãy cài đặt một trong những phần mềm sau đây:

• HyperKit

• VirtualBox

• VMware Fusion

Cài đặt Minikube

Cách đơn giản nhất để cài đặt Minikube trên macOS là sử dụng Homebrew:

brew install minikube

Bạn cũng có thể cài đặt trên macOS bằng việc tải xuống bản binary:

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 \
  && chmod +x minikube

Đây là một cách dễ dàng để thêm Minikube vào biến môi trường path của bạn:

sudo mv minikube /usr/local/bin

Cài đặt kubectl

Đảm bảo bạn đã cài đặt kubectl. Bạn có thể cài đặt kubectl theo hướng dẫn sau tại Install and Set Up kubectl.

Cài đặt Hypervisor

Nếu bạn chưa cài đặt Hypervisor, hãy cài đặt một trong những phần mềm sau đây:

• Hyper-V

• VirtualBox

Lưu ý:

Hyper-V có thể chạy trên 3 phiên bản khác nhau của Windows 10: Windows 10 Enterprise, Windows 10 Professional, và Windows 10 Education.

Cài đặt Minikube sử dụng Chocolatey

Cách đơn giản nhất để cài đặt Minikube trên Windows là sử dụng Chocolatey (chạy với quyền admin):

choco install minikube

Sau khi Minikube hoàn tất việc cài đặt, hãy đóng CLI hiện tại và khởi động lại. Minikube sẽ được tự động thêm vào biến môi trường path của bạn.

Cài đặt Minikube sử dụng gói cài đặt thực thi

Để cài đặt Minikube thủ công trên Windows sử dụng Windows Installer, tải về minikube-installer.exe và chạy bản cài đặt đó.

Cài đặt Minikube thông qua tải về trực tiếp

Để cài đặt Minikube thủ công trên Windows, tải về minikube-windows-amd64, đổi tên nó thành minikube.exe, và thêm nó vào biến môi trường path.

Dọn dẹp local state

Nếu bạn đã cài Minikube trước đó, và chạy:

minikube start

và tiếp đó minikube start trả về lỗi:

machine does not exist

thì tiếp theo bạn cần xóa bỏ local state của minikube:

minikube delete

Tiếp theo là gì

4.2 - Cấu hình Pods và Containers

Thực hiện các tác vụ cấu hình thông dụng cho Pods và containers.

4.2.1 - Cấp phát tài nguyên bộ nhớ cho Containers và Pods

Trang này hướng dẫn cách cấp phát bộ nhớ request (tối thiểu) và bộ nhớ limit (tối đa) cho một Container. Một Container được đảm bảo có đủ bộ nhớ như nó yêu cầu, nhưng không được phép sử dụng nhiều bộ nhớ hơn giới hạn của nó.

Trước khi bạn bắt đầu

Bạn cần có một cluster Kubernetes, và kubectl phải được cấu hình để giao tiếp với cluster của bạn. Khuyến nghị nên chạy hướng dẫn này trên một cluster có ít nhất hai node không đóng vai trò là máy chủ control plane. Nếu bạn chưa có cluster, bạn có thể tạo một cluster bằng cách sử dụng minikube hoặc sử dụng một trong các sân chơi Kubernetes sau:

Để kiểm tra phiên bản của kubectl, hãy chạy lệnh kubectl version.

Để kiểm tra phiên bản, nhập kubectl version.

Mỗi Node trong Cluster của bạn phải có ít nhất 300 MiB bộ nhớ.

Một số bước trong trang này yêu cầu bạn chạy dịch vụ metrics-server trong Cluster. Nếu bạn đã có metrics-server đang chạy, bạn có thể bỏ qua các bước này.

Nếu bạn đang chạy Minikube, hãy chạy lệnh sau để bật metrics-server:

minikube addons enable metrics-server

Để kiểm tra xem metrics-server có đang chạy hay không, hoặc hệ thống giám sát tài nguyên khác (metrics.k8s.io), hãy chạy lệnh sau:

kubectl get apiservices

Nếu hệ thống giám sát tài nguyên có sẵn, kết quả sẽ chứa metrics.k8s.io.

NAME
v1beta1.metrics.k8s.io

Tạo namespace

Tạo một namespace để các tài nguyên mà bạn tạo trong bài này được tách biệt khỏi phần còn lại của cluster.

kubectl create namespace mem-example

Cài đặt bộ nhớ tối thiểu và bộ nhớ tối đa

Để cài đặt bộ nhớ tối thiểu cho một Container, bạn cần thêm trường resources:requests vào phần khai báo trong tệp cấu hình Container. Với bộ nhớ tối đa, bạn hãy thêm resources:limits.

Trong phần thực hành này, bạn sẽ tạo một Pod có một Container. Container này có bộ nhớ tối thiểu là 100 MiB và bộ nhớ tối đa là 200 MiB. Đây là file cấu hình cho Pod:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Phần args trong tệp cấu hình cung cấp các tham số cho Container khi nó khởi tạo. Các tham số "--vm-bytes", "150M" yêu cầu Container cấp phát 150 MiB bộ nhớ.

Tạo Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example

Kiểm tra Pod đang chạy:

kubectl get pod memory-demo --namespace=mem-example

Xem thông tin chi tiết về Pod:

kubectl get pod memory-demo --output=yaml --namespace=mem-example

Kết quả cho thấy Container trong Pod có bộ nhớ tối thiểu là 100 MiB và bộ nhớ tối đa là 200 MiB.

...
resources:
  requests:
    memory: 100Mi
  limits:
    memory: 200Mi
...

Chạy lệnh kubectl top để xem các thông số của Pod:

kubectl top pod memory-demo --namespace=mem-example

Kết quả cho thấy Pod đang sử dụng khoảng 162,900,000 bytes bộ nhớ, tương đương khoảng 150MiB. Mức này cao hơn 100MiB tối thiểu nhưng vẫn nằm trong giới hạn 200MiB.

NAME                        CPU(cores)   MEMORY(bytes)
memory-demo                 <something>  162856960

Xóa Pod:

kubectl delete pod memory-demo --namespace=mem-example

Vượt quá bộ nhớ tối đa của Container

Một Container có thể sử dụng nhiều bộ nhớ hơn mức tối thiểu nếu Node còn bộ nhớ trống. Tuy nhiên, Container không được phép sử dụng bộ nhớ hơn mức tối đa của nó. Nếu Container cấp phát nhiều bộ nhớ hơn mức tối đa, Container đó sẽ có khả năng bị dừng hoạt động. Nếu Container tiếp tục sử dụng bộ nhớ vượt quá giới hạn, nó sẽ được dừng hoàn toàn. Nếu Container đó có thể khởi động lại, kubelet sẽ khởi động lại nó, lỗi quá bộ nhớ được xử lý giống như đối với các lỗi runtime khác.

Trong phần thực hành này, bạn sẽ tạo một Pod cố gắng cấp phát bộ nhớ nhiều hơn giới hạn của nó. Đây là tệp cấu hình cho một Pod có một Container với bộ nhớ tối thiểu là 50 MiB và bộ nhớ tối đa là 100 MiB:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

Trong phần args của tệp cấu hình, bạn có thể thấy Container sẽ cố gắng cấp phát 250 MiB bộ nhớ, vượt xa giới hạn 100 MiB.

Tạo Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

Xem thông tin chi tiết Pod:

kubectl get pod memory-demo-2 --namespace=mem-example

Tại thời điểm này, Container có thể đang chạy hoặc đã được dừng hoạt động. Lặp lại lệnh trước đó cho đến khi Container dừng hoạt động:

NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          24s

Xem chi tiết hơn về trạng thái của Container:

kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

Kết quả cho thấy Container đã dừng hoạt động vì hết bộ nhớ (OOM - Out Of Memory):

lastState:
   terminated:
     containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
     exitCode: 137
     finishedAt: 2017-06-20T20:52:19Z
     reason: OOMKilled
     startedAt: null

Container trong phần thực hành này có thể được khởi động lại, vì vậy kubelet sẽ khởi động lại nó. Lặp lại lệnh này vài lần để thấy Container liên tục bị dừng hoạt động và khởi động lại:

kubectl get pod memory-demo-2 --namespace=mem-example

Kết quả cho thấy Container bị dừng hoạt động, khởi động lại, bị dừng hoạt động lần nữa, khởi động lại lần nữa, và cứ tiếp tục như vậy:

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          37s

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-2   1/1       Running   2          40s

Xem thông tin chi tiết về lịch sử của Pod:

kubectl describe pod memory-demo-2 --namespace=mem-example

Kết quả cho thấy Container liên tục khởi động và thất bại:

... Normal  Created   Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff   Back-off restarting failed container

Xem thông tin chi tiết về các Node trong Cluster:

kubectl describe nodes

Kết quả cho thấy việc Container bị dừng hoạt động do tình trạng hết bộ nhớ:

Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

Xóa Pod:

kubectl delete pod memory-demo-2 --namespace=mem-example

Cài đặt bộ nhớ tối thiểu vượt quá khả năng của Nodes

Bộ nhớ tối thiểu và tối đa được gắn với các Container, nhưng cũng có thể hiểu rằng một Pod có tổng bộ nhớ tối thiểu và tối đa riêng. Bộ nhớ tối thiểu cho Pod là tổng các bộ nhớ tối thiểu của tất cả các Container trong Pod. Tương tự, bộ nhớ tối đa cho Pod là tổng của các bộ nhớ tối đa của tất cả các Container trong Pod.

Khi lập lịch (scheduling) Pod, Kubernetes dựa vào bộ nhớ tối thiểu. Một Pod chỉ được chạy trên Node nếu Node có đủ bộ nhớ trống để đáp ứng bộ nhớ tối thiểu của Pod.

Trong phần thực hành này, bạn sẽ tạo một Pod có bộ nhớ tối thiểu lớn đến mức vượt quá khả năng của bất kỳ Node nào trong cluster của bạn. Đây là tệp cấu hình cho một Pod có một Container với 1000 GiB bộ nhớ tối thiểu, có khả năng vượt quá khả năng của bất kỳ Node nào trong cluster của bạn.

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-3
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "1000Gi"
      limits:
        memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Khởi tạo Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

Xem trạng thái của Pod:

kubectl get pod memory-demo-3 --namespace=mem-example

Kết quả cho thấy trạng thái của Pod là PENDING. Nghĩa là, Pod không được lập lịch để chạy trên bất kỳ Node nào, và nó sẽ tiếp tục ở trạng thái PENDING vô thời hạn:

kubectl get pod memory-demo-3 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-3   0/1       Pending   0          25s

Xem thông tin chi tiết về Pod, bao gồm cả sự kiện:

kubectl describe pod memory-demo-3 --namespace=mem-example

Kết quả cho thấy Container không thể được lập lịch do không đủ bộ nhớ trên các Nodes:

Events:
  ...  Reason            Message
       ------            -------
  ...  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient memory (3).

Đơn vị đo bộ nhớ

Tài nguyên bộ nhớ được đo bằng byte. Bạn có thể biểu thị bộ nhớ dưới dạng số nguyên thông thường hoặc số thập phân cố định với một trong các hậu tố sau: E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki. Ví dụ, các giá trị sau đây biểu thị xấp xỉ cùng một giá trị:

128974848, 129e6, 129M, 123Mi

Xoá Pod:

kubectl delete pod memory-demo-3 --namespace=mem-example

Nếu bạn không cài đặt bộ nhớ tối đa

Nếu bạn không cài đặt bộ nhớ tối đa cho một Container, một trong các tình huống sau sẽ xảy ra:

  • Container không có giới hạn tối đa về lượng bộ nhớ mà nó sử dụng. Container có thể sử dụng tất cả bộ nhớ có sẵn trên Node nơi nó đang chạy, điều này có thể kích hoạt OOM Killer. Hơn nữa, trong trường hợp OOM Kill, một container không có giới hạn tài nguyên sẽ có khả năng bị dừng hoạt động cao hơn.
  • Container đang chạy trong một namespace có bộ nhớ tối đa mặc định, và Container tự động được gán giới hạn mặc định đó. Cluster administrators có thể sử dụng LimitRange để chỉ định giá trị mặc định cho bộ nhớ tối đa.

Lý do cần có bộ nhớ tối thiểu và bộ nhớ tối đa

Bằng cách cấu hình bộ nhớ tối thiểu và tối đa cho các Container chạy trong cluster của bạn, bạn có thể sử dụng hiệu quả tài nguyên bộ nhớ có sẵn trên các Node của cluster. Với việc giữ bộ nhớ tối thiểu của Pod ở mức thấp, Pod dễ được triển khai hơn. Bằng cách có bộ nhớ tối đa lớn hơn bộ nhớ tối thiểu, bạn đạt được hai điều:

  • Pod có thể có các đợt hoạt động cao điểm sử dụng bộ nhớ đang có sẵn.
  • Lượng bộ nhớ mà Pod có thể sử dụng trong đợt cao điểm được giới hạn ở một mức hợp lý.

Xóa các thành phần đã tạo

Xóa namespace của bạn. Thao tác này sẽ xóa tất cả các Pod bạn đã tạo cho phần này:

kubectl delete namespace mem-example

Tiếp theo là gì

Dành cho nhà phát triển ứng dụng

Dành cho quản trị viên cluster

4.3 - Giám sát, ghi nhật ký và gỡ lỗi

Thiết lập hệ thống giám sát và ghi nhật ký để khắc phục sự cố cụm, hoặc gỡ lỗi ứng dụng trong container.

Đôi khi mọi thứ diễn ra không như mong muốn. Hướng dẫn này sẽ giúp bạn thu thập những thông tin cần thiết và khắc phục sự cố. Hướng dẫn này được chia làm 4 phần:

  • Gỡ lỗi ứng dụng - Hữu ích cho những người triển khai ứng dụng lên Kubernetes và muốn hiểu vì sao ứng dụng không hoạt động như mong đợi.

  • Gỡ lỗi cụm - Hữu ích cho các quản trị viên và người vận hành cụm khắc phục các sự cố trong cụm.

  • Ghi nhật ký trong Kubernetes - Hữu ích cho các quản trị viên muốn thiết lập và quản lý hệ thống nhật ký trong Kubernetes.

  • Giám sát trong Kubernetes - Hữu ích cho các quản trị viên muốn triển khai hệ thống giám sát trong Kubernetes.

Bạn cũng nên tham khảo các sự cố đã biết của phiên bản mà bạn đang sử dụng.

Nhận trợ giúp

Nếu bạn vẫn chưa tìm được cách xử lý cho vấn đề của mình trong các hướng dẫn ở trên, bạn có thể tìm kiếm sự hỗ trợ từ cộng đồng Kubernetes thông qua nhiều kênh khác nhau.

Câu hỏi

Tài liệu trên trang này được tổ chức nhằm giải đáp nhiều loại câu hỏi khác nhau về Kubernetes. Khái niệm giải thích kiến trúc của Kubernetes và cách thức hoạt động của từng thành phần. Thiết lập cung cấp các hướng dẫn để bạn bắt đầu sử dụng Kubernetes. Tác vụ hướng dẫn cách thực hiện các tác vụ thường gặp, và Hướng dẫn thực hành cung cấp hướng dẫn chi tiết cho các tình huống thực tế, theo từng lĩnh vực hoặc trong toàn bộ quy trình phát triển. Mục Tài liệu tham khảo cung cấp tài liệu chi tiết về Kubernetes API và các giao diện dòng lệnh (CLIs) như kubectl.

Giúp với! Vấn đề của tôi không có trong tài liệu! Tôi cần hỗ trợ ngay!

Stack Exchange, Stack Overflow, hoặc Server Fault

Nếu bạn có câu hỏi liên quan đến phát triển phần mềm cho ứng dụng chạy trong container, bạn có thể đặt câu hỏi trên Stack Overflow.

Nếu bạn có câu hỏi về Kubernetes liên quan đến quản lý cụm hay cấu hình, bạn có thể đặt câu hỏi trên Server Fault.

Ngoài ra, hệ thống Stack Exchange còn có nhiều trang chuyên biệt khác, phù hợp để đặt các câu hỏi về Kubernetes trong những lĩnh vực như DevOps, Software Engineering, hay InfoSec.

Rất có thể đã có một thành viên trong cộng đồng gặp phải vấn đề tương tự hoặc có thể sẵn sàng giúp bạn giải quyết vấn đề.

Đội ngũ Kubernetes cũng theo dõi các bài đăng được gắn thẻ Kubernetes. Nếu không có câu hỏi nào giải quyết được vấn đề của bạn, hãy đảm bảo rằng vấn đề đó phù hợp với chủ đề của Stack Overflow, Server Fault, hoặc trang Stack Exchange mà bạn định đăng bài, đồng thời hãy đọc qua hướng dẫn cách đặt câu hỏi mới trước khi tạo bài đăng!

Slack

Nhiều thành viên trong cộng đồng Kubernetes trao đổi trên Kubernetes Slack, trong kênh #kubernetes-users. Slack yêu cầu phải đăng ký; bạn có thể gửi yêu cầu tham dự, việc đăng ký được mở cho tất cả mọi người. Đừng ngại tham gia và đặt bất kỳ câu hỏi nào. Sau khi đăng ký, truy cập Kubernetes trên Slack thông qua trình duyệt hoặc qua ứng dụng Slack.

Sau khi tham gia, bạn có thể khám phá danh sách các kênh thảo luận theo từng chủ đề. Ví dụ, người mới bắt đầu với Kubernetes có thể tham gia kênh #kubernetes-novice. Các nhà phát triển có thể tham gia kênh #kubernetes-contributors.

Ngoài ra còn có các kênh dành riêng cho từng quốc gia hoặc ngôn ngữ. Bạn có thể tham gia các kênh này để nhận được sự hỗ trợ và trao đổi thông tin bằng ngôn ngữ địa phương:

Kênh Slack cho các quốc gia / ngôn ngữ
Quốc giaKênh
Trung Quốc#cn-users, #cn-events
Phần Lan#fi-users
Pháp#fr-users, #fr-events
Đức#de-users, #de-events
Ấn Độ#in-users, #in-events
Ý#it-users, #it-events
Nhật Bản#jp-users, #jp-events
Hàn Quốc#kr-users
Hà Lan#nl-users
Na Uy#norw-users
Ba Lan#pl-users
Nga#ru-users
Tây Ban Nha#es-users
Thuỵ Điển#se-users
Thổ Nhĩ Kỳ#tr-users, #tr-events

Diễn đàn

Bạn được chào đón tham gia diễn đàn chính thức của Kubernetes: discuss.kubernetes.io.

Báo lỗi và đề xuất tính năng

Nếu bạn phát hiện ra lỗi hoặc muốn đề xuất một tính năng, hãy sử dụng GitHub issue.

Trước khi tạo một issue mới, hãy tìm trong các issue hiện có để xem các vấn đề của bạn đã được thảo luận trước đó hay chưa.

Khi báo cáo lỗi, hãy cung cấp đầy đủ thông tin để có thể tái hiện lỗi, ví dụ:

  • Phiên bản Kubernetes kubectl version
  • Nhà cung cấp Cloud, hệ điều hành, cấu hình mạng, phiên bản container runtime
  • Các bước để tái hiện sự cố

4.4 - Horizontal Pod Autoscaling

Trang này đang được dịch. Vui lòng xem phiên bản tiếng Anh để biết thông tin mới nhất.

5 - Tutorials

Phần này của tài liệu có chứa các hướng dẫn. Phần hướng dẫn sẽ chỉ cho bạn cách thực hiện một mục tiêu lớn hơn một tác vụ đơn lẻ.

Thông thường, một hướng dẫn có nhiều phần, mỗi phần có một trình tự các bước. Trước khi thực hiện từng hướng dẫn, bạn có thể muốn đánh dấu trang Thuật ngữ chuẩn hóa để tham khảo.

5.1 - Học kiến thức cơ bản về Kubernetes

Kiến thức cơ bản về Kubernetes

Hướng dẫn này cung cấp những kiến thức cơ bản về một cụm Kubernetes. Mỗi mô-đun chứa một số thông tin cơ bản về các tính năng cũng như khái niệm chính của Kubernetes, đồng thời bao gồm một hướng dẫn tương tác trực tuyến. Các hướng dẫn tương tác này giúp bạn quản lý một cluster đơn giản và các ứng dụng được đóng gói của bạn.

Bằng các hướng dẫn tương tác, bạn có thể học cách:

  • Triển khai một ứng dụng container trong một cluster.
  • Thay đổi quy mô triển khai.
  • Cập nhật ứng dụng container.
  • Debug ứng dụng container.

Những hướng dẫn này dùng Katacoda để chạy một terminal ảo trên trình duyệt web của bạn chạy Minikube. Không cần phải cài đặt và cấu hình bất kỳ phần mềm nào; mỗi hướng dẫn tương tác chạy trực tiếp từ trình duyệt web của bạn.


Kubernetes có thế làm những gì?

Với các dịch vụ web hiện đại, người dùng mong muốn các ứng dụng luôn sẵn sàng hoạt động 24/7 và các lập trình viên muốn triển khai các phiên bản của ứng dụng đó nhiều lần trong ngày. Việc đóng gói ứng dụng vào container giúp giải quyết mục tiêu này, cho phép các ứng dụng được phát hành và cập nhật một cách dễ dàng, nhanh chóng mà không có downtime. Kubernetes giúp bạn đảm bảo các ứng dụng container chạy ở bất kì đâu và bất kì lúc nào bạn muốn, đồng thời giúp chúng tìm thấy các tài nguyên và công cụ cần thiết để chạy. Kubernetes là nền tảng mã nguồn mở, chạy được trong môi trường production, được thiết kế và phát triển bởi Google, kết hợp với những ý tưởng tốt nhất từ cộng đồng.


5.1.1 - Tạo một Cluster

5.1.1.1 - Sử dụng Minikube để tạo một Cluster

Mục tiêu

  • Tìm hiểu Kubernetes cluster là gì?
  • Tìm hiểu Minikube là gì?
  • Khởi tạo một Kubernetes cluster sử dụng terminal trực tuyến.

Kubernetes Clusters

Kubernetes kết nối và điều phối các máy tính trong một cluster để chúng có thể hoạt động như một đơn vị thống nhất (unit). Nó cho phép bạn triển khai các ứng dụng trên Container mà không cần phải bận tâm chúng sẽ được khởi chạy trên chiếc máy tính cụ thể nào trong cluster. Để sử dụng mô hình triển khai của Kubernetes, các ứng dụng cần được đóng gói theo một cách linh động và không phụ thuộc vào từng máy tính cụ thể (host): tức là các ứng dụng được Container hóa. Các ứng dụng dạng Container có được sự khả chuyển và sẵn sàng cao hơn các mô hình triển khai được sử dụng trong quá khứ, ở đó chúng được cài đặt trực tiếp trên các máy tính cụ thể và gắn chặt với các bộ thư viện trên đó. Kubernetes phân bổ và điều phối các ứng dụng hoàn toàn tự động xuyên suốt cluster theo một cách hiệu quả. Ngoài ra Kubernetes là mã nguồn mở và sẵn sàng để sử dụng trong môi trường triển khai thực tế (production).

Một Kubernetes cluster bao gồm 2 loại tài nguyên:

  • Node Master làm nhiệm vụ quản lý toàn cluster.
  • Các Node còn lại khởi chạy các ứng dụng trực tiếp trên đó là các Worker.

Tổng kết:

  • Kubernetes cluster
  • Minikube

Kubernetes là một bộ công cụ mã nguồn mở, đáp ứng tiêu chuẩn triển khai thực tế, làm nhiệm vụ điều phối và khởi chạy các ứng dụng dạng Container bên trong một cluster hoặc thậm chí xuyên suốt nhiều cluster.


Mô hình Cluster


Node Master chịu trách nhiệm quản lý cluster. Nó quản lý toàn bộ các hoạt động bên trong cluster, như là việc khởi chạy các ứng dụng, kiểm soát chúng để chắc chắn chúng luôn ở các trạng thái như mong muốn, thay đổi khả năng đáp ứng của chúng (scaling), hoặc triển khai các phiên bản nâng cấp theo thời gian.

Một Node có thể là một máy ảo (VM) hoặc một máy tính vật lý làm việc với vai trò cung cấp khả năng tính toán cho cluster. Mỗi Node có một chương trình chạy thường trực bên trong tên là Kubelet, làm nhiệm vụ quản lý Node và duy trì kết nối với node Master. Mỗi Node bên cạnh đó còn chạy các chương trình dùng để khởi chạy và quản lý các Container như Docker hay rkt. Mỗi một Kubernetes cluster được triển khai trong thực tế khai thác thường có ít nhất 3 node thuộc 2 loại như bên trên.

Master quản lý cluster và các Node đóng vai trò chạy các ứng dụng Container.

Khi bạn triển khai các ứng dụng trên Kubernetes, bạn yêu cầu node Master phân bổ và khởi chạy các ứng dụng của bạn. Node Master tiếp đó tính toán để tìm ra các Node nào thích hợp cho việc triển khai ứng dụng. Các Node trong cluster kết nối và giao tiếp với nhau theo bộ qui tắc Kubernetes API do node Master đưa ra. Quản trị viên hoặc người sử dụng đầu cuối cũng có thể sử dụng bộ qui tắc này để tương tác trực tiếp với một cluster.

Một Kubernetes cluster có thể được xây dựng trên các máy tính vật lý hoặc các máy ảo. Để bắt đầu việc phát triển cho Kubernetes, bạn có thể sử dụng Minikube. Minikube là một bộ cài đặt Kubernetes bằng cách tạo ra một máy ảo trên máy tính của bạn và triển khai một cluster đơn giản bên trong máy ảo đó chỉ bao gồm một Node. Minikube có cho Linux, macOS, và Windows. Minikube CLI, một bộ công cụ dòng lệnh, cung cấp khả năng điều khiển cluster cho người sử dụng, như chạy, dừng chạy, xem trạng thái, hoặc xóa một thành phần trong cluster. Trong bài hướng dẫn này, bạn sẽ sử dụng một giao diện terminal trực tuyến với Minikube đã được cài đặt sẵn để thao tác.

Giờ bạn đã biết Kubernetes là gì, hãy tiếp tục với phần tương tác và tạo ra cluster đầu tiên!


5.1.1.2 - Hướng dẫn tương tác - Tạo một Cluster

Để tương tác với Terminal, hãy dùng phiên bản dành cho desktop/tablet

5.1.2 - Triển khai một ứng dụng

5.1.2.1 - Sử dụng kubectl để triển khai ứng dụng

Mục tiêu

  • Tìm hiểu về triển khai ứng dụng (Deployment).
  • Triển khai ứng dụng đầu tiên của bạn trên Kubernetes với kubectl.

Kubernetes Deployments

Giả sử bạn đã có một Kubernetes cluster đang hoạt động, bạn có thể triển khai ứng dụng của bạn trên cluster này. Để thực hiện điều đó, bạn cần tạo một kịch bản triển khai (Deployment). Kịch bản này sẽ giúp Kubernetes có thể tạo và cập nhật các phiên bản chạy (instances) của ứng dụng của bạn. Sau khi một kịch bản triển khai được tạo ra trong Kubernetes, node Master sẽ lập lịch để khởi chạy ứng dụng của bạn trên các Node của cluster.

Sau khi ứng dụng của bạn được khởi chạy trên các Node của cluster, Kubernetes sẽ tiếp tục theo dõi các chương trình đang chạy (instances) này. Nếu một Node đang chạy một instance của ứng dụng của bạn gặp trục trặc hoặc bị xóa khỏi cluster, Kubernetes sẽ thay thế instance đó bằng cách khởi chạy một instance mới trên một Node khác của cluster. Đây là cơ chế tự phục hồi (self-healing) khi có lỗi xảy ra hoặc khi một Node nào đó cần được bảo trì.

Ở thời điểm trước Kubernetes, các ứng dụng thường được khởi chạy thông qua các bộ tool cài đặt (installation scripts), nhưng chúng hầu như không thể hỗ trợ việc phục hồi khi có lỗi xảy ra với một máy tính trong cluster. Bằng cách khởi chạy các instances của ứng dụng trên nhiều Node xuyên suốt cluster, Kubernetes về cơ bản đã cho thấy một cách tiếp cận rất khác biệt về việc quản lý các ứng dụng.

Tổng kết:

  • Deployments
  • Kubectl

Một kịch bản triển khai (Deployment) là một tập hợp các thao tác làm nhiệm vụ khởi chạy ứng dụng của bạn và theo dõi cập nhật các instances của ứng dụng trên phạm vi toàn cluster


Triển khai ứng dụng đầu tiên của bạn trên Kubernetes


Bạn có thể tạo ra và quản lý các kịch bản triển khai (Deployment) thông qua giao diện dòng lệnh của Kubernetes với Kubectl. Kubectl sử dụng Kubernetes API để tương tác với cluster. Ở bài hướng dẫn này, bạn sẽ tìm hiểu các câu lệnh cơ bản nhất của Kubectl cần thiết để triển khai ứng dụng của bạn trên một Kubernetes cluster.

Khi tạo một kịch bản triển khai (Deployment), bạn cần chỉ ra một tệp Container Image chứa ứng dụng của bạn và số lượng bản sao (replicas) của ứng dụng bạn muốn chạy. Bạn hoàn toàn có thể thay đổi các thông số này bằng cách cập nhật kịch bản triển khai sau thông qua Module 5 và 6 của tập hướng dẫn cách cập nhật các Deployments.

Các ứng dụng phải được đóng gói trong một định dạng Container được hỗ trợ bởi Kubernetes để có thể triển khai trên hệ thống này

Về ứng dụng dầu tiên của bạn, nó sẽ là một ứng dụng Node.js được đóng gói trong một Docker container. (Nếu bạn chưa biết cách tạo một ứng dụng Node.js và đóng gói dưới dạng Container, vui lòng theo dõi hướng dẫn tại địa chỉ Hello Minikube tutorial).

Giờ bạn đã biết kịch bản triển khai (Deployment) là gì, hãy bắt đầu triển khai ứng dụng đầu tiên của bạn!


5.1.2.2 - Hướng dẫn tương tác - Triển khai một ứng dụng


Để tương tác với Terminal, hãy sử dụng phiên bản dành cho desktop/tablet

5.1.3 - Khám phá ứng dụng

5.1.3.1 - Khám Phá Pods Và Nodes

Mục tiêu

  • Tìm hiểu Kubernetes Pods là gì?
  • Tìm hiểu Kubernetes Nodes là gì?
  • Khắc phục sự cố ứng dụng đã triển khai

Kubernetes Pods

Khi bạn triển khai ứng dụng thông qua Module 2, Kubernetes tạo ra Pod để lưu trữ phiên bản chạy của ứng dụng của bạn. Một Pod là một khái niệm trừu tượng của Kubernetes, đại diện cho một nhóm gồm một hoặc nhiều ứng dụng containers (ví dụ như Docker hoặc rkt) và một số tài nguyên được chia sẻ cho các containers đó. Những tài nguyên đó bao gồm:

  • Lưu trữ được chia sẻ, dưới dạng Volumes
  • Kết nối mạng, như một cluster IP duy nhất
  • Thông tin về cách chạy từng container, chẳng hạn như phiên bản container image hoặc các ports cụ thể để sử dụng

Một Pod mô phỏng một "máy chủ logic" dành riêng cho ứng dụng và có thể chứa các ứng dụng containers khác nhau được liên kết tương đối chặt chẽ. Ví dụ, một Pod có thể bao gồm cả container với ứng dụng Node.js của bạn cũng như một container khác cung cấp dữ liệu hiển thị bởi webserver của Node.js. Các containers trong một Pod chia sẻ một địa chỉ IP và port space, chúng luôn được đặt cùng vị trí, cùng lên lịch trình, và chạy trong ngữ cảnh được chia sẻ trên cùng một Node.

Pods là các đơn vị nguyên tử trên nền tảng Kubernetes. Khi chúng tôi tạo một kịch bản triển khai (Deployment) trên Kubernetes, kịch bản triển khai đó tạo ra các Pods với các containers bên trong chúng (trái ngược với việc tạo các containers trực tiếp). Mỗi Pod được gắn với Node nơi nó được lên lịch trình, và tiếp tục ở đó cho đến khi chấm dứt (theo chính sách khởi động lại). Trong trường hợp có lỗi ở Node, các Pods giống nhau được lên lịch trình trên các Nodes có sẵn khác trong cluster.

Tổng Kết:

  • Pods
  • Nodes
  • Những lệnh chính của Kubectl

Một Pod là một nhóm gồm một hoặc nhiều ứng dụng containers (như Docker hoặc rkt) và bao gồm lưu trữ được chia sẻ (dưới dạng volumes), địa chỉ IP và thông tin về cách chạy chúng.


Tổng quan về Pods


Nodes

Một Pod luôn chạy trên một Node. Một Node là một máy worker trong Kubernetes và có thể là máy ảo hoặc máy vật lý, tuỳ thuộc vào cluster. Mỗi Node được quản lí bởi Master. Một Node có thể chứa nhiều Pods và Kubernetes master tự động xử lí việc lên lịch trình các Pods thuộc các Nodes ở trong cluster. Việc lên lịch trình tự động của Master sẽ tính đến các tài nguyên có sẵn trên mỗi Node.

Mỗi Node ở Kubernetes chạy ít nhất:

  • Kubelet, một quy trình chịu trách nhiệm liên lạc giữa Kubernetes Master và Node; quản lí các Pods và các containers đang chạy trên cùng một máy.
  • Một container runtime (như Docker, rkt) chịu trách nhiệm lấy container image từ registry, giải nén container và chạy ứng dụng. Các containers chỉ nên được lên lịch trình cùng nhau trong một Pod duy nhất nếu chúng được liên kết chặt chẽ.

Các containers chỉ nên được lên lịch trình cùng nhau trong một Pod duy nhất nếu chúng được liên kết chặt chẽ và cần chia sẻ tài nguyên như disk.


Tổng quan về Node


Khắc phục sự cố với kubectl

Ở Module 2, bạn đã sử dụng giao diện dòng lệnh Kubectl. Bạn sẽ tiếp tục sử dụng nó trong Module 3 để nhận thông tin về các ứng dụng đã triển khai và môi trường của chúng. Các hoạt động phổ biến nhất có thể được thực hiện với các lệnh kubectl sau:

  • kubectl get - liệt kê các tài nguyên
  • kubectl describe - hiển thị thông tin chi tiết về một tài nguyên
  • kubectl logs - in các bản ghi (logs) từ một container trong một pod
  • kubectl exec - thực hiện một lệnh trên một container trong một pod

Bạn có thể sử dụng các lệnh này để xem khi nào các ứng dụng được triển khai, trạng thái hiện tại của chúng là gì, nơi chúng đang chạy và cấu hình của chúng là gì.

Bây giờ chúng ta đã biết thêm về các thành phần cluster và dòng lệnh, hãy khám phá ứng dụng của chúng tôi.

Một Node là một máy worker trong Kubernetes và có thể là máy ảo hoặc máy vật lý, tuỳ thuộc vào cluster. Nhiều Pods có thể chạy trên cùng một Node.


5.1.3.2 - Hướng dẫn tương tác - Khám phá ứng dụng


Để tương tác với Terminal, hãy sử dụng phiên bản dành cho desktop/tablet

5.1.4 - Công khai ứng dụng ra bên ngoài

5.1.4.1 - Sử dụng Service để công khai ứng dụng

Mục tiêu

  • Tìm hiểu về Service trong Kubernetes
  • Hiểu mối quan hệ giữa labels và selectors với Service
  • Công khai một ứng dụng ra bên ngoài Kubernetes cluster

Tổng quan về Service trong Kubernetes

Pods trong Kubernetes có tính tạm thời. Pods có một vòng đời nhất định. Khi một worker node ngừng hoạt động, các Pod đang chạy trên Node đó cũng bị mất. Một ReplicaSet có thể tự động điều chỉnh cluster về trạng thái mong muốn bằng cách tạo các Pod mới để giữ cho ứng dụng tiếp tục hoạt động. Ví dụ khác, hãy xem xét một backend xử lý container image với 3 bản sao. Những bản sao này có thể thay thế lẫn nhau; hệ thống frontend không cần quan tâm đến các bản sao backend hoặc việc một Pod bị mất và được tạo lại. Tuy nhiên, mỗi Pod trong Kubernetes cluster đều có một địa chỉ IP duy nhất, kể cả các Pod trên cùng một Node, vì vậy cần có cơ chế tự động điều phối các thay đổi giữa các Pod để ứng dụng có thể tiếp tục hoạt động.

Service trong Kubernetes là một lớp trừu tượng định nghĩa một tập hợp logic các Pod và chính sách truy cập cho chúng. Service cho phép các Pod phụ thuộc nhau có thể kết nối với nhau một cách "lỏng lẻo". Service được định nghĩa bằng YAML hoặc JSON, giống như tất cả các manifest đối tượng khác của Kubernetes. Tập hợp các Pod mà Service nhắm đến thường được xác định bằng một label selector (xem phần dưới để hiểu tại sao đôi khi bạn có thể muốn một Service mà không cần selector trong đặc tả).

Mặc dù mỗi Pod có một địa chỉ IP duy nhất, những IP này không được công khai ra bên ngoài cluster nếu không có Service. Service cho phép ứng dụng của bạn nhận lưu lượng truy cập từ bên ngoài. Service có thể được công khai theo nhiều cách khác nhau bằng cách chỉ định type trong phần spec của Service:

  • ClusterIP (mặc định) - Công khai Service trên một IP nội bộ trong cluster. Kiểu này chỉ cho phép Service có thể truy cập được từ bên trong cluster.

  • NodePort - Công khai Service trên cùng một port của mỗi Node được chọn trong cluster sử dụng NAT. Cho phép Service có thể truy cập được từ bên ngoài cluster thông qua <NodeIP>:<NodePort>. Là tập mở rộng của ClusterIP.

  • LoadBalancer - Tạo một bộ cân bằng tải bên ngoài trong cloud hiện tại (nếu được hỗ trợ) và gán một IP cố định bên ngoài cho Service. Là tập mở rộng của NodePort.

  • ExternalName - Ánh xạ Service với nội dung của trường externalName (ví dụ: foo.bar.example.com), bằng cách trả về một bản ghi CNAME với giá trị tương ứng. Không thiết lập bất kỳ proxy nào. Kiểu này yêu cầu phiên bản v1.7 trở lên của kube-dns hoặc CoreDNS phiên bản 0.0.8 trở lên.

Thông tin chi tiết hơn về các kiểu Service khác nhau có thể được tìm thấy trong hướng dẫn Sử dụng Source IP. Đồng thời xem thêm Kết nối ứng dụng với Services.

Ngoài ra, lưu ý rằng có một số trường hợp sử dụng Service mà không cần định nghĩa selector trong đặc tả. Service được tạo không có selector sẽ không tạo đối tượng Endpoints tương ứng. Điều này cho phép người dùng tự ánh xạ Service đến các endpoints cụ thể. Một trường hợp khác là khi bạn chỉ sử dụng type: ExternalName.

Service và Labels

Service định tuyến lưu lượng qua một tập hợp các Pod. Service là lớp trừu tượng cho phép các Pod có thể được tạo và xóa trong Kubernetes mà không ảnh hưởng đến ứng dụng. Việc service discovery và định tuyến giữa các Pod phụ thuộc nhau (như các thành phần frontend và backend trong một ứng dụng) được xử lý bởi Kubernetes Services.

Service khớp với một tập hợp các Pod sử dụng labels và selectors, một cơ chế nhóm cho phép thao tác logic trên các đối tượng trong Kubernetes. Labels là các cặp key/value được gắn vào đối tượng và có thể được sử dụng theo nhiều cách:

  • Chỉ định đối tượng cho môi trường development, test và production
  • Gắn thẻ phiên bản
  • Phân loại đối tượng bằng tags

Labels có thể được gắn vào đối tượng khi tạo hoặc sau đó và có thể được sửa đổi bất cứ lúc nào. Bây giờ hãy công khai ứng dụng của chúng ta bằng Service và áp dụng một số labels.

Bước 1: Tạo một Service mới

Đầu tiên, hãy kiểm tra xem ứng dụng của chúng ta có đang chạy không. Chúng ta sẽ sử dụng lệnh kubectl get để xem các Pod hiện có:

kubectl get pods

Nếu không có Pod nào đang chạy, điều đó có nghĩa là các đối tượng từ bài hướng dẫn trước đã được dọn dẹp. Trong trường hợp này, hãy quay lại và tạo lại deployment từ bài hướng dẫn Sử dụng kubectl để tạo Deployment. Vui lòng đợi vài giây và liệt kê lại các Pod. Bạn có thể tiếp tục khi thấy một Pod đang chạy.

Tiếp theo, hãy liệt kê các Service hiện có trong cluster:

kubectl get services

Bây giờ chúng ta có một Service đang chạy tên là kubernetes-bootcamp. Service này đã nhận được một cluster-IP duy nhất, một port nội bộ và một external-IP (IP của Node).

Để tìm hiểu port nào được mở ra bên ngoài (cho Service kiểu NodePort), chúng ta sẽ chạy lệnh con describe service:

kubectl describe services/kubernetes-bootcamp

Tạo một biến môi trường NODE_PORT với giá trị là Node port được gán:

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

Bây giờ chúng ta có thể kiểm tra xem ứng dụng đã được công khai ra ngoài cluster chưa bằng cách sử dụng curl, địa chỉ IP của Node và port được công khai ra bên ngoài:

curl http://"$(minikube ip):$NODE_PORT"

Lưu ý:

Nếu bạn đang chạy minikube với Docker Desktop làm container driver, bạn cần một minikube tunnel. Điều này là do các container trong Docker Desktop bị cô lập với máy host của bạn.

Trong một cửa sổ terminal riêng biệt, thực thi:

minikube service kubernetes-bootcamp --url

Kết quả sẽ như sau:

http://127.0.0.1:51082
!  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

Sau đó sử dụng URL được cung cấp để truy cập ứng dụng:

curl 127.0.0.1:51082

Và chúng ta nhận được phản hồi từ server. Service đã được công khai.

Bước 2: Sử dụng labels

Deployment đã tự động tạo một label cho Pod của chúng ta. Với lệnh con describe deployment, bạn có thể thấy tên (khóa) của label đó:

kubectl describe deployment

Hãy sử dụng label này để truy vấn danh sách Pod của chúng ta. Chúng ta sẽ sử dụng lệnh kubectl get pods với tham số -l, theo sau là giá trị của label:

kubectl get pods -l app=kubernetes-bootcamp

Bạn có thể làm tương tự để liệt kê các Service hiện có:

kubectl get services -l app=kubernetes-bootcamp

Lấy tên của Pod và lưu vào biến môi trường POD_NAME:

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo "Name of the Pod: $POD_NAME"

Để áp dụng một label mới, chúng ta sử dụng lệnh con label theo sau bởi loại đối tượng, tên đối tượng và label mới:

kubectl label pods "$POD_NAME" version=v1

Điều này sẽ áp dụng một label mới cho Pod của chúng ta (chúng ta đã gắn phiên bản ứng dụng vào Pod), và chúng ta có thể kiểm tra nó bằng lệnh describe pod:

kubectl describe pods "$POD_NAME"

Chúng ta thấy rằng label đã được gắn vào Pod của chúng ta. Và bây giờ chúng ta có thể truy vấn danh sách pod sử dụng label mới:

kubectl get pods -l version=v1

Và chúng ta thấy Pod đó.

Bước 3: Xóa một service

Để xóa Service, bạn có thể sử dụng lệnh con delete service. Labels cũng có thể được sử dụng ở đây:

kubectl delete service -l app=kubernetes-bootcamp

Xác nhận rằng Service đã bị xóa:

kubectl get services

Điều này xác nhận rằng Service của chúng ta đã được gỡ bỏ. Để xác nhận rằng route không còn được công khai nữa, bạn có thể thử curl tới IP và port đã được công khai trước đó:

curl http://"$(minikube ip):$NODE_PORT"

Điều này chứng minh rằng ứng dụng không còn có thể truy cập được từ bên ngoài cluster nữa. Bạn có thể xác nhận rằng ứng dụng vẫn đang chạy bằng cách curl từ bên trong pod:

kubectl exec -ti $POD_NAME -- curl http://localhost:8080

Chúng ta thấy rằng ứng dụng vẫn đang hoạt động. Điều này là do Deployment đang quản lý ứng dụng. Để tắt ứng dụng, bạn cần xóa cả Deployment.

Tiếp theo là gì

6 - Tài liệu tham khảo

Phần này chứa các tài liệu tham khảo của Kubernetes.

6.1 - Thuật ngữ chuẩn hóa

6.2 - kubectl Cheat Sheet

Xem thêm: Kubectl Overview và JsonPath Guide.

Trang này là trang tổng quan của lệnh kubectl.

kubectl - Cheat Sheet

Kubectl Autocomplete

BASH

source <(kubectl completion bash) # thiết lập autocomplete trong bash vào shell hiện tại, gói bash-completion nên được cài đặt trước tiên 
echo "source <(kubectl completion bash)" >> ~/.bashrc # thêm vĩnh viễn autocomplete vào trong bash shell

Bạn có thể dùng một alias cho kubectl cũng hoạt động với completion:

alias k=kubectl
complete -F __start_kubectl k

ZSH

source <(kubectl completion zsh)  # thiết lập autocomplete trong zsh vào shell hiện tại
echo "if [ $commands[kubectl] ]; then source <(kubectl completion zsh); fi" >> ~/.zshrc # thêm vĩnh viễn autocomplete vào trong zsh shell

Ngữ cảnh và cấu hình kubectl

Thiết lập cụm Kubernetes nào mà kubectl sẽ giao tiếp với và sửa đổi thông tin cấu hình. Xem tài liệu Xác thực giữa các cụm với kubeconfig để biết thông tin chi tiết của tệp cấu hình.

kubectl config view # Hiển thị các thiết lập kubeconfig đã được merged

# sử dụng nhiều tệp kubeconfig cùng một lúc và xem cấu hình hợp nhất
KUBECONFIG=~/.kube/config:~/.kube/kubconfig2 

kubectl config view

# lấy mật khẩu cho người dùng e2e
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'

kubectl config view -o jsonpath='{.users[].name}'    # hiển thị người dùng đầu tiên  
kubectl config view -o jsonpath='{.users[*].name}'   # lấy danh sách người dùng  
kubectl config get-contexts                          # hiển thị danh sách các ngữ cảnh 
kubectl config current-context                       # hiển thị ngữ cảnh hiện tại
kubectl config use-context my-cluster-name           # thiết lập ngữ cảnh mặc định cho my-cluster-name

# thêm một cụm mới vào kubeconf hỗ trợ xác thực cơ bản
kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword

# lưu vĩnh viễn namespace cho tất cả các lệnh kubectl tiếp theo trong ngữ cảnh đó
kubectl config set-context --current --namespace=ggckad-s2

# thiết lập ngữ cảnh sử dụng tên người dùng và namespace cụ thể
kubectl config set-context gce --user=cluster-admin --namespace=foo \
  && kubectl config use-context gce
 
kubectl config unset users.foo                       # xóa người dùng foo

Apply

apply quản lý các ứng dụng thông qua các tệp định nghĩa tài nguyên Kubernetes. Nó tạo và cập nhật các tài nguyên trong một cụm thông qua việc chạy kubectl apply. Đây là cách được đề xuất để quản lý các ứng dụng Kubernetes trong thực tế. Xem thêm Kubectl Book.

Tạo một đối tượng

Kubernetes manifests có thể được định nghĩa trong tệp json hoặc yaml. Phần mở rộng .yaml, .yml, và .json có thể được dùng.

kubectl apply -f ./my-manifest.yaml            # tạo tài nguyên
kubectl apply -f ./my1.yaml -f ./my2.yaml      # tạo từ nhiều tệp
kubectl apply -f ./dir                         # tạo tài nguyên từ tất cả các tệp manifest trong thư mục dir
kubectl apply -f https://git.io/vPieo          # tạo tài nguyên từ url
kubectl create deployment nginx --image=nginx  # tạo một deployment nginx
kubectl explain pods,svc                       # lấy thông tin pod và service manifest

# Tạo nhiều đối tượng YAML từ stdin
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep-less
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000"
EOF

# Tạo một secret với một số keys
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: $(echo -n "s33msi4" | base64 -w0)
  username: $(echo -n "jane" | base64 -w0)
EOF

Xem, tìm các tài nguyên

# Lệnh get với một số đầu ra cơ bản
kubectl get services                          # Liệt kê tất cả các services trong namespace
kubectl get pods --all-namespaces             # Liệt kê tất cả các pods trong tất cả các namespaces
kubectl get pods -o wide                      # Liệt kê tất cả các pods namespace, với nhiều thông tin hơn
kubectl get deployment my-dep                 # Liệt kê một deployment cụ thể
kubectl get pods                              # Liệt kê tất cả các pods trong namespace
kubectl get pod my-pod -o yaml                # Lấy thông tin của một pod ở dạng YAML
kubectl get pod my-pod -o yaml --export       # Lấy thông tin của một pod ở dạng YAML mà không có thông tin cụ thể về cụm

# Lệnh describe
kubectl describe nodes my-node
kubectl describe pods my-pod

# Liệt kê các services được sắp xếp theo tên
kubectl get services --sort-by=.metadata.name

# Liệt kê các pods được sắp xếp theo số lần khởi động lại
kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'

# Liệt kê các pods được sắp xếp theo dung lượng trong namespace có tên là test

kubectl get pods -n test --sort-by='.spec.capacity.storage'

# Lấy thông tin phiên bản của tất cả các pods có nhãn app=cassandra
kubectl get pods --selector=app=cassandra -o \
  jsonpath='{.items[*].metadata.labels.version}'

# Liệt kê tất cả các worker nodes (sử dụng một selector để loại trừ kết quả có một nhãn
# có tên 'node-role.kubernetes.io/master'  
kubectl get node --selector='!node-role.kubernetes.io/master'

# Liệt kê tất cả các pods đang chạy trong namespace
kubectl get pods --field-selector=status.phase=Running

# Liệt kê tất cả các ExternalIPs của tất cả các nodes
kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'

# Liệt kê tên của các pods thuộc về một RC nhất định
# Lệnh "jq" hữu ích cho các chuyển đổi quá mức phức tạp cho jsonpath, xem thêm tại https://stedolan.github.io/jq/
sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?}
echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name})

# Hiển thị nhãn của tất cả các pods (hoặc các đối tượng Kubernetes khác hỗ trợ gán nhãn)
kubectl get pods --show-labels

# Kiểm tra xem nodes nào đã sẵn sàng
JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
 && kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True"

# Liệt kê tất cả cá Secrets hiện đang sử dụng bởi một pod
kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq

# Liệt kê tất cả các sự kiện được sắp xếp theo thời gian
kubectl get events --sort-by=.metadata.creationTimestamp

Cập nhật các tài nguyên

Theo như phiên bản 1.11, rolling-update đã không còn được dùng nữa (xem CHANGELOG-1.11.md), sử dụng rollout thay thế.

kubectl set image deployment/frontend www=image:v2               # Cập nhận container "www" của deployment "frontend", cập nhật image
kubectl rollout history deployment/frontend                      # Kiểm tra lịch sử deployment bao gồm các sửa đổi
kubectl rollout undo deployment/frontend                         # Quay trở lại deployment trước đó
kubectl rollout undo deployment/frontend --to-revision=2         # Quay trở lại một phiên bản cụ thể
kubectl rollout status -w deployment/frontend                    # Xem trạng thái cập nhật của deployment "frontend" cho đến khi hoàn thành


# không còn được sử dụng kể từ phiên bản 1.11
kubectl rolling-update frontend-v1 -f frontend-v2.json           # (không dùng nữa) Cập nhật pods của frontend-v1
kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2  # (không dùng nữa) Đổi tên tài nguyên và cập nhật image 
kubectl rolling-update frontend --image=image:v2                 # (không dùng nữa) Cập nhật image của pod của frontend
kubectl rolling-update frontend-v1 frontend-v2 --rollback        # (không dùng nữa) Hủy bỏ tiến trình cập nhật hiện tại

cat pod.json | kubectl replace -f -                              # Thay thế một pod dựa trên JSON được truyền vào std

# Buộc thay thế, xóa và sau đó tạo lại tài nguyên, sẽ gây ra sự cố ngưng services
kubectl replace --force -f ./pod.json

# Tạo một services cho nginx, phục vụ trên công 80 và kết nối đến các container trên cổng 8000
kubectl expose rc nginx --port=80 --target-port=8000

# Cập nhật phiên bản image của một container đơn lẻ lên v4 
kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -

kubectl label pods my-pod new-label=awesome                      # Thêm một nhãn
kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq       # Thêm một chú thích
kubectl autoscale deployment foo --min=2 --max=10                # Tự động scale deployment "foo"

Vá các tài nguyên

# Cập nhật một phần một node
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'

# Cập nhật image của container; spec.containers[*].name là bắt buộc vì đó là khóa hợp nhất
kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'

# Cập nhật image của container sử dụng một bản vá json với các mảng vị trí
kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'

# Vô hiệu hóa một deployment livenessProbe sử dụng một bản vá json với các mảng vị trí
kubectl patch deployment valid-deployment  --type json   -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'

# Thêm một phần tử mới vào một mảng vị trí
kubectl patch sa default --type='json' -p='[{"op": "add", "path": "/secrets/1", "value": {"name": "whatever" } }]'

Chỉnh sửa các tài nguyên

Chỉnh sửa bất kì API tài nguyên nào trong trình soạn thảo ưa thích của bạn.

kubectl edit svc/docker-registry                      # Chỉnh sửa services có tên docker-registry
KUBE_EDITOR="nano" kubectl edit svc/docker-registry   # Sử dụng một trình soạn thảo thay thế

Scaling tài nguyên

kubectl scale --replicas=3 rs/foo                                 # Scale một replicaset có tên 'foo' thành 3
kubectl scale --replicas=3 -f foo.yaml                            # Scale một tài nguyên được xác định trong "foo.yaml" thành 3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql  # Nếu kích thước hiện tại của deployment mysql là 2, scale mysql thành 3
kubectl scale --replicas=5 rc/foo rc/bar rc/baz                   # Scale nhiều replication controllers

Xóa tài nguyên

kubectl delete -f ./pod.json                                              # Xóa một pod sử dụng loại và tên được xác định trong pod.json
kubectl delete pod,service baz foo                                        # Xóa pods và services có tên "baz" và "foo"
kubectl delete pods,services -l name=myLabel                              # Xóa pods và services có nhãn name=myLabel
kubectl -n my-ns delete pod,svc --all                                     # Xóa tất cả pods và services trong namespace my-ns,
# Xóa tất cả pods matching với pattern1 hoặc pattern2
kubectl get pods  -n mynamespace --no-headers=true | awk '/pattern1|pattern2/{print $1}' | xargs  kubectl delete -n mynamespace pod

Tương tác với các pods đang chạy

kubectl logs my-pod                                 # kết xuất logs của pod (stdout)
kubectl logs -l name=myLabel                        # kết xuất logs của pod có nhãn name=myLabel (stdout)
kubectl logs my-pod --previous                      # kết xuất logs của pod (stdout) cho khởi tạo trước của một container
kubectl logs my-pod -c my-container                 # kết xuất logs của container của pod (stdout, trường hợp có nhiều container)
kubectl logs -l name=myLabel -c my-container        # kết xuất logs của container có tên my-container và có nhãn name=myLabel (stdout)
kubectl logs my-pod -c my-container --previous      # kết xuất logs của container my-container của pod my-pod (stdout, trường hợp có nhiều container) cho khởi tạo trước của một container
kubectl logs -f my-pod                              # lấy logs của pod my-pod (stdout)
kubectl logs -f my-pod -c my-container              # lấy logs của container my-container trong pod my-pod (stdout, trường hợp nhiều container)
kubectl logs -f -l name=myLabel --all-containers    # lấy logs của tất cả các container của pod có nhãn name=myLabel (stdout)
kubectl run -i --tty busybox --image=busybox -- sh  # Chạy pod trong một shell tương tác
kubectl run nginx --image=nginx --restart=Never -n 
mynamespace                                         # Chạy pod nginx trong một namespace cụ thể
kubectl run nginx --image=nginx --restart=Never     # Chạy pod nginx và ghi spec của nó vào file có tên pod.yaml
--dry-run -o yaml > pod.yaml

kubectl attach my-pod -i                            # Đính kèm với container đang chạy
kubectl port-forward my-pod 5000:6000               # Lắng nghe trên cổng 5000 của máy local và chuyển tiếp sang cổng 6000 trên pod my-pod
kubectl exec my-pod -- ls /                         # Chạy lệnh trong một pod (trường hợp 1 container)
kubectl exec my-pod -c my-container -- ls /         # Chạy lệnh trong pod (trường hợp nhiều container)
kubectl top pod POD_NAME --containers               # Hiển thị số liệu của pod và container chạy trong nó

Tương tác với các nodes và cụm

kubectl cordon my-node                                                # Đánh dấu my-node là không thể lập lịch
kubectl drain my-node                                                 # Gỡ my-node ra khỏi cụm để chuẩn bị cho việc bảo trì
kubectl uncordon my-node                                              # Đánh dấu my-node có thể lập lịch trở lại
kubectl top node my-node                                              # Hiển thị số liệu của node
kubectl cluster-info                                                  # Hiển thị địa chỉ master và các services
kubectl cluster-info dump                                             # Kết xuất trạng thái hiện tại của cụm ra ngoài stdout
kubectl cluster-info dump --output-directory=/path/to/cluster-state   # Kết xuất trạng thái hiện tại của cụm vào /path/to/cluster-state

kubectl taint nodes foo dedicated=special-user:NoSchedule

Các loại tài nguyên

Liệt kê tất cả các loại tài nguyên được hỗ trợ cùng với tên viết tắt của chúng, API group, cho dù chúng là namespaced, và Kind:

kubectl api-resources

Các hoạt động khác để khám phá các tài nguyên API:

kubectl api-resources --namespaced=true      # Tất cả các tài nguyên được đặt tên
kubectl api-resources --namespaced=false     # Tất cả các tài nguyên không được đặt tên
kubectl api-resources -o name                # Tất cả các tài nguyên với đầu ra đơn giản (chỉ gồm tên tài nguyên)
kubectl api-resources -o wide                # Tất cả các tài nguyên với đầu ra mở rộng
kubectl api-resources --verbs=list,get       # Tất cả các tài nguyên hỗ trợ yêu cầu "list" và "get"
kubectl api-resources --api-group=extensions # Tất cả tài nguyên trong nhóm API "tiện ích mở rộng"

Định dạng đầu ra

Để xuất thông tin chi tiết ra cửa sổ terminal của bạn theo một định dạng cụ thể, bạn có thể thêm các cờ -o hoặc --output vào lệnh kubectl được hỗ trợ.

Định dạng đầu raMô tả
-o=custom-columns=<spec>In một bảng bằng danh sách, các cột tùy chỉnh được phân tách bằng dấu phẩy
-o=custom-columns-file=<filename>In một bảng bằng cách sử dụng mẫu cột tùy chỉnh trong tệp <filename>
-o=jsonXuất ra một đối tượng API theo định dạng JSON
-o=jsonpath=<template>In ra các trường được xác định trong jsonpath
-o=jsonpath-file=<filename>In ra các trường được xác định bởi jsonpath trong tệp <filename>
-o=nameChỉ in tên tài nguyên và không có gì khác
-o=wideXuất ra ở định dạng văn bản thuần với bất kì thông tin bổ sung nào và đối với pods, cần phải thêm tên node
-o=yamlXuất ra đối tượng API theo định dạng YAML

Kubectl output verbosity and debugging

Kubectl verbosity được kiểm soát bởi cờ -v or --v theo sau là một số nguyên biểu thị mức log. Các quy ước ghi logs của Kubernetes và các mức logs liên quan được mô tả ở đây.

VerbosityDescription
--v=0Hữu ích cho việc hiển thị cho các người vận hành cụm.
--v=1Một mức log mặc định hợp lý nếu bạn không muốn lấy quá nhiều logs.
--v=2Thông tin trạng thái về services và các thông điệp logs quan trọng có thể tương quan với những thay đổi quan trọng trong hệ thống. Đây là mức ghi logs mặc định được khuyến nghị cho hầu hết các hệ thống.
--v=3Thông tin mở rộng về những thay đổi.
--v=4Debug level verbosity.
--v=6Hiển thị tài nguyên được yêu cầu.
--v=7Hiển thị HTTP request headers.
--v=8Hiển thị nội dung HTTP request.
--v=9Hiển thị nội dung HTTP request mà không cắt ngắn nội dung.

Tiếp theo là gì

7 - Đóng góp cho Kubernetes

Có rất nhiều cách để đóng góp cho Kubernetes. Bạn có thể tham gia thiết kế cho các tính năng mới, viết tài liệu cho mã nguồn hiện có, hoặc viết cho blog của chúng tôi. Còn nhiều hơn nữa: bạn có thể triển khai các tính năng mới hoặc sửa lỗi. Bạn cũng có thể giúp mọi người tham gia vào cộng đồng những người đóng góp của chúng tôi, hoặc hỗ trợ những người đóng góp hiện tại.

Với tất cả những cách khác nhau để tạo ra sự khác biệt cho dự án, chúng tôi - Kubernetes - đã tạo ra một trang web riêng: https://k8s.dev/. Bạn có thể truy cập vào đó để tìm hiểu thêm về việc đóng góp cho Kubernetes.

Nếu bạn muốn tìm hiểu cụ thể về việc đóng góp cho tài liệu hoặc các phần khác của trang web này, hãy đọc Đóng góp cho tài liệu Kubernetes. Nếu bạn muốn giúp đỡ với blog chính thức của Kubernetes, hãy đọc Đóng góp cho blog Kubernetes.

Bạn cũng có thể đọc trang của CNCF về việc đóng góp cho Kubernetes.