Các thành phần cốt lõi của cụm Kubernetes

theanh

Administrator
Nhân viên
Kubernetes là một nền tảng nguồn mở để quản lý khối lượng công việc và dịch vụ được chứa trong container, tạo điều kiện cho cấu hình khai báo và tự động hóa. Tên Kubernetes bắt nguồn từ tiếng Hy Lạp, có nghĩa là người lái hoặc phi công. Nó vừa di động vừa có thể mở rộng và có hệ sinh thái phát triển nhanh chóng. Các dịch vụ và công cụ của Kubernetes có sẵn rộng rãi.

Trong bài viết này, chúng ta sẽ xem xét góc nhìn tổng quan 10.000 feet về các thành phần chính của Kubernetes, từ thành phần của từng container cho đến cách một container trong một pod được triển khai và lên lịch trên từng công nhân. Điều quan trọng là phải hiểu đầy đủ các thông tin chi tiết về cụm Kubernetes để có thể triển khai và thiết kế giải pháp dựa trên Kubernetes như một trình điều phối cho các ứng dụng được chứa trong container.

Sau đây là tóm tắt về những điều chúng ta sẽ đề cập trong bài viết này:
  • Các thành phần của bảng điều khiển
  • Các thành phần của công nhân Kubernetes
  • Pod là các khối xây dựng cơ bản
  • Các dịch vụ Kubernetes, bộ cân bằng tải và bộ điều khiển Ingress
  • Triển khai Kubernetes và Bộ Daemon
  • Lưu trữ liên tục trong Kubernetes

Mặt phẳng điều khiển Kubernetes​

Các nút chính Kubernetes là nơi các dịch vụ mặt phẳng điều khiển lõi tồn tại; không phải tất cả các dịch vụ đều phải nằm trên cùng một nút; tuy nhiên, để tập trung và thực tế, chúng thường được triển khai theo cách này. Điều này rõ ràng đặt ra các câu hỏi về tính khả dụng của dịch vụ; tuy nhiên, chúng có thể dễ dàng được khắc phục bằng cách có nhiều nút và cung cấp các yêu cầu cân bằng tải để đạt được một tập hợp các nút chính có tính khả dụng cao.

Các nút chính bao gồm bốn dịch vụ cơ bản:
  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager
  • cơ sở dữ liệu etcd
Các nút chính có thể chạy trên máy chủ bare metal, máy ảo hoặc đám mây riêng hoặc công cộng, nhưng không nên chạy khối lượng công việc container trên các nút này. Chúng ta sẽ xem thêm về vấn đề này sau.

Sơ đồ sau đây hiển thị các thành phần của nút chính Kubernetes:


kube-apiserver​

Máy chủ API là thứ liên kết mọi thứ lại với nhau. Đây là REST API frontend của cụm nhận manifest để tạo, cập nhật và xóa các đối tượng API như dịch vụ, pod, Ingress và các đối tượng khác.

Kube-apiserver là dịch vụ duy nhất mà chúng ta nên trao đổi; đây cũng là dịch vụ duy nhất ghi và trao đổi với etcdcơ sở dữ liệu để đăng ký trạng thái cụm. Với lệnh kubectl, chúng ta sẽ gửi lệnh để tương tác với nó. Đây sẽ là con dao đa năng của chúng tôi khi nói đến Kubernetes.

Kube-controller-manager​

Về cơ bản, kube-controller-managerdaemon là một tập hợp các vòng lặp điều khiển vô hạn được phân phối để đơn giản hóa trong một nhị phân duy nhất. Nó theo dõi trạng thái mong muốn đã xác định của cụm và đảm bảo rằng trạng thái đó được hoàn thành và thỏa mãn bằng cách di chuyển tất cả các bit và phần cần thiết để đạt được trạng thái đó. Kube-controller-manager không chỉ là một bộ điều khiển; nó chứa một số vòng lặp khác nhau để theo dõi các thành phần khác nhau trong cụm. Một số trong số chúng là bộ điều khiển dịch vụ, bộ điều khiển không gian tên, bộ điều khiển tài khoản dịch vụ và nhiều bộ điều khiển khác. Bạn có thể tìm thấy từng bộ điều khiển và định nghĩa của nó trong kho lưu trữ GitHub của Kubernetes: https://github.com/kubernetes/kubernetes/tree/master/pkg/controller.

Kube-scheduler​

Kube-scheduler lên lịch các pod mới tạo của bạn cho các node có đủ không gian để đáp ứng nhu cầu tài nguyên của các pod. Về cơ bản, nó lắng nghe kube-apiserver và kube-controller-manager để tìm các pod mới tạo được đưa vào hàng đợi và sau đó được lên lịch cho một node khả dụng bởi bộ lập lịch. Định nghĩa kube-scheduler có thể được tìm thấy tại đây: https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler.

Bên cạnh tài nguyên tính toán, kube-scheduler còn đọc các quy tắc về mối quan hệ và phản mối quan hệ của các nút để tìm ra liệu một nút có thể chạy pod đó hay không.

Cơ sở dữ liệu etcd​

Cơ sở dữ liệu etcd là kho lưu trữ khóa-giá trị nhất quán rất đáng tin cậy được sử dụng để lưu trữ trạng thái của cụm Kubernetes. Nó chứa trạng thái hiện tại của các pod mà nút đang chạy trên đó, số lượng nút mà cụm hiện có, trạng thái của các nút đó, số lượng bản sao triển khai đang chạy, tên dịch vụ và những thông tin khác.

Như đã đề cập trước đó, chỉ có kube-apiserver giao tiếp với cơ sở dữ liệu etcd. Nếu kube-controller-manager cần kiểm tra trạng thái của cụm, nó sẽ đi qua máy chủ API để lấy trạng thái từ cơ sở dữ liệu etcd, thay vì truy vấn trực tiếp etcdstore. Điều tương tự cũng xảy ra với kube-scheduler nếu trình lập lịch cần thông báo rằng một pod đã dừng hoặc được phân bổ cho một nút khác; nó sẽ thông báo cho máy chủ API và máy chủ API sẽ lưu trữ trạng thái hiện tại trong cơ sở dữ liệu etcd.

Với etcd, chúng ta đã đề cập đến tất cả các thành phần chính cho các nút chính Kubernetes của mình để chúng ta sẵn sàng quản lý cụm của mình. Nhưng một cụm không chỉ bao gồm các nút chính; chúng tôi vẫn cần các nút sẽ thực hiện các tác vụ nặng nề bằng cách chạy các ứng dụng của chúng tôi.

Nút công nhân Kubernetes​

Các nút công nhân thực hiện tác vụ này trong Kubernetes được gọi đơn giản là các nút. Trước đây, vào khoảng năm 2014, chúng được gọi là các minion, nhưng sau đó thuật ngữ này được thay thế chỉ bằng các nút, vì tên này gây nhầm lẫn với các thuật ngữ của Salt và khiến mọi người nghĩ rằng Salt đóng vai trò chính trong Kubernetes.

Các nút này là nơi duy nhất bạn sẽ chạy khối lượng công việc, vì không nên có các vùng chứa hoặc tải trên các nút chính, vì chúng cần phải khả dụng để quản lý toàn bộ cụm. Các nút rất đơn giản về mặt thành phần; chúng chỉ cần ba dịch vụ để hoàn thành nhiệm vụ của mình:
  • Kubelet
  • Kube-proxy
  • Container runtime
Chúng ta hãy cùng khám phá ba thành phần này sâu hơn một chút.

Kubelet​

Kubelet là một thành phần Kubernetes cấp thấp và là một trong những thành phần quan trọng nhất sau kube-apiserver; cả hai thành phần này đều cần thiết để cung cấp các pod/container trong cụm. Kubelet là một dịch vụ chạy trên các nút Kubernetes và lắng nghe máy chủ API để tạo pod. Kubelet chỉ chịu trách nhiệm khởi động/dừng và đảm bảo rằng các container trong pod hoạt động bình thường; kubelet sẽ không thể quản lý bất kỳ container nào không được tạo bởi nó.

Kubelet đạt được mục tiêu bằng cách giao tiếp với containerruntime thông qua giao diện thời gian chạy container (CRI). CRI cung cấp khả năng cắm vào kubelet thông qua một máy khách gRPC, có khả năng giao tiếp với các thời gian chạy container khác nhau. Như đã đề cập trước đó, Kubernetes hỗ trợ nhiều thời gian chạy container để triển khai container và đây là cách nó đạt được sự hỗ trợ đa dạng như vậy cho các công cụ khác nhau.

Bạn có thể kiểm tra mã nguồn của kubelet qua https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet.

kube-proxy​

kube-proxy là một dịch vụ nằm trên mỗi nút của cụm và là dịch vụ giúp liên lạc giữa các pod, container và nút trở nên khả thi. Dịch vụ này theo dõi kube-apiserver để biết những thay đổi trên các dịch vụ đã xác định (dịch vụ là một dạng bộ cân bằng tải logic trong Kubernetes; chúng ta sẽ tìm hiểu sâu hơn về serviceslateron trong bài viết này) và cập nhật mạng thông qua các quy tắc iptables chuyển tiếp lưu lượng đến đúng điểm cuối. Kube-proxy cũng thiết lập các quy tắc trong iptablesthực hiện cân bằng tải ngẫu nhiên trên các pod đằng sau một dịch vụ.

Sau đây là ví dụ về quy tắc iptablesdo kube-proxy tạo ra:

-A KUBE-SERVICES -d 10.0.162.61/32 -p tcp -m comment --comment "default/example: has no endpoints" -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable

Lưu ý rằng đây là một dịch vụ không có điểm cuối (không có pod nào đằng sau nó).

Thời gian chạy container​

Để có thể tạo container, chúng tôi yêu cầu thời gian chạy container. Đây là cơ sở sẽ tạo ra các container trong hạt nhân node để các pod của chúng ta chạy. Kubelet sẽ giao tiếp với thời gian chạy này và sẽ khởi động hoặc dừng các container của chúng ta theo yêu cầu.

Hiện tại, Kubernetes hỗ trợ bất kỳ containerruntime tuân thủ OCI nào, chẳng hạn như Docker,rkt,runc,runsc, v.v.

Bạn có thể tham khảo https://github.com/opencontainers/runtime-spec này để tìm hiểu thêm về tất cả các thông số kỹ thuật từ trang OCI Git-Hub.

Bây giờ chúng ta đã khám phá tất cả các thành phần cốt lõi tạo nên một cụm, hãy cùng xem những gì có thể thực hiện được với chúng và cách Kubernetes sẽ giúp chúng ta sắp xếp và quản lý các ứng dụng được chứa trong container của mình.

Đối tượng Kubernetes​

Đối tượng Kubernetes chính xác là như vậy: chúng là các đối tượng logic-persistent hoặc trừu tượng sẽ biểu diễn trạng thái của cụm của bạn. Bạn là người chịu trách nhiệm cho Kubernetes biết trạng thái mong muốn của đối tượng đó là gì để nó có thể hoạt động để duy trì trạng thái đó và đảm bảo rằng đối tượng đó tồn tại.

Để tạo một đối tượng, đối tượng cần có hai thứ: trạng thái và thông số kỹ thuật của đối tượng đó. Trạng thái do Kubernetes cung cấp và đó là trạng thái hiện tại của đối tượng. Kubernetes sẽ quản lý và cập nhật trạng thái đó khi cần để phù hợp với trạng thái mong muốn của bạn. Mặt khác, trường spec là những gì bạn cung cấp cho Kubernetes và là những gì bạn yêu cầu nó mô tả đối tượng mà bạn mong muốn. Ví dụ, hình ảnh mà bạn muốn container chạy, số lượng container của hình ảnh đó mà bạn muốn chạy, v.v.

Mỗi đối tượng có các trườngspeccụ thể cho loại tác vụ mà chúng thực hiện và bạn sẽ cung cấp các thông số kỹ thuật này trên tệp YAML được gửi đến kube-apiserver bằngkubectl, tệp này sẽ chuyển đổi tệp thành JSON và gửi dưới dạng yêu cầu API. Chúng ta sẽ đi sâu hơn vào từng đối tượng và các trường spec của đối tượng đó sau trong bài viết này.

Sau đây là ví dụ về tệp YAML được gửi đếnkubectl:

cat << EOF | kubectl create -f -kind: ServiceapiVersion: v1metadata: Name: frontend-servicespec: selector: web: frontend ports: - protocol: TCP port: 80 targetPort: 9256EOF

Các trường cơ bản của định nghĩa đối tượng là những trường đầu tiên và những trường này sẽ không thay đổi tùy theo đối tượng và rất dễ hiểu. Hãy cùng xem nhanh chúng:
  • kind: Trường kind cho Kubernetes biết loại đối tượng bạn đang định nghĩa: một pod, một dịch vụ, một triển khai, v.v.
  • apiVersion: Vì Kubernetes hỗ trợ nhiều phiên bản API, chúng ta cần chỉ định đường dẫn REST API mà chúng ta muốn gửi định nghĩa của mình tới
  • metadata: Đây là một trường lồng nhau, nghĩa là bạn có nhiều trường con hơn cho metadata, nơi bạn sẽ viết các định nghĩa cơ bản như tên đối tượng của mình, gán đối tượng đó cho một không gian tên cụ thể và cũng gắn nhãn cho đối tượng đó để liên kết đối tượng của bạn với các đối tượng Kubernetes khác
Vậy là chúng ta đã xem qua các trường được sử dụng nhiều nhất và nội dung của chúng; bạn có thể tìm hiểu thêm về các quy ước API Kuberntes tại https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md

Một số trường của đối tượng sau này có thể được sửa đổi sau khi đối tượng đã được tạo, nhưng điều đó sẽ phụ thuộc vào đối tượng và trường mà bạn muốn sửa đổi.

Sau đây là danh sách ngắn về các đối tượng Kubernetes khác nhau mà bạn có thể tạo:
  • Pod
  • Volume
  • Service
  • Deployment
  • Ingress
  • Secret
  • ConfigMap
Và còn nhiều hơn nữa.

Chúng ta hãy xem xét kỹ hơn từng đối tượng này items.

Pod – nền tảng của Kubernetes​

Pod là đối tượng cơ bản nhất trong Kubernetes và cũng là đối tượng quan trọng nhất. Mọi thứ đều xoay quanh chúng; chúng ta có thể nói rằng Kubernetes dành cho các pod! Tất cả các đối tượng khác đều ở đây để phục vụ chúng và tất cả các tác vụ mà chúng thực hiện là để các pod đạt được trạng thái mong muốn của bạn.

Vậy, apod là gì và tại sao các pod lại quan trọng như vậy?

Pod là đối tượng logic chạy một hoặc nhiều container cùng nhau trên cùng một không gian tên mạng, cùng một giao tiếp giữa các tiến trình (IPC) và đôi khi, tùy thuộc vào phiên bản Kubernetes, cùng một không gian tên ID tiến trình (PID). Lý do là vì chúng là những đối tượng sẽ chạy các container của chúng ta và do đó sẽ là tâm điểm chú ý. Toàn bộ mục đích của Kubernetes là trở thành một trình điều phối container và với các pod, chúng tôi có thể thực hiện việc điều phối.

Như đã đề cập trước đó, các container trên cùng một pod tồn tại trong một "bong bóng" nơi chúng có thể giao tiếp với nhau qua localhost vì chúng cục bộ với nhau. Một container trong pod có cùng địa chỉ IP với container kia vì chúng đang chia sẻ một không gian tên mạng, nhưng trong hầu hết các trường hợp, bạn sẽ chạy trên cơ sở một-một, nghĩa là, một container duy nhất cho mỗi pod. Nhiều container cho mỗi pod chỉ được sử dụng trong các tình huống rất cụ thể, chẳng hạn như khi một ứng dụng yêu cầu một trình trợ giúp như trình đẩy dữ liệu hoặc proxy cần giao tiếp theo cách nhanh chóng và linh hoạt với ứng dụng chính.

Cách bạn định nghĩa một pod cũng giống như cách bạn định nghĩa đối với bất kỳ đối tượng Kubernetes nào khác: thông qua YAML chứa tất cả các thông số kỹ thuật và định nghĩa của pod:

kind: PodapiVersion: v1metadata:name: hello-podlabels: hello: podspec: containers: - name: hello-container image: alpine args: - echo - "Hello World"

Chúng ta hãy cùng xem qua các định nghĩa pod cơ bản cần có trong trường spec để tạo pod của chúng ta:
  • Containers: Container là một mảng; do đó, chúng ta có một tập hợp gồm một số trường con bên dưới nó. Về cơ bản, đó là những gì xác định các container sẽ chạy trên pod. Chúng ta có thể chỉ định tên cho container, image sẽ là một spin-off từ đó và các đối số hoặc lệnh mà chúng ta cần nó chạy. Sự khác biệt giữa các đối số và lệnh giống như sự khác biệt giữa CMD và ENTRYPOINT. Lưu ý rằng tất cả các trường mà chúng ta vừa xem qua đều dành cho mảng container. Chúng không phải là một phần trực tiếp của thông số kỹ thuật của pod.
  • restartPolicy: Trường này chính xác là như vậy: nó cho Kubernetes biết phải làm gì với một container và nó áp dụng cho tất cả các container trong pod trong trường hợp mã thoát bằng không hoặc khác không. Bạn có thể chọn một trong hai tùy chọn, Never, OnFailure hoặc Always. Always sẽ là tùy chọn mặc định trong trường hợp restartPolicy không được xác định.
Đây là những thông số kỹ thuật cơ bản nhất mà bạn sẽ khai báo trên một pod; các thông số kỹ thuật khác sẽ yêu cầu bạn có thêm một chút kiến thức cơ bản về cách sử dụng chúng và cách chúng tương tác với nhiều đối tượng Kubernetes khác. Chúng ta sẽ xem xét lại chúng sau trong bài viết này; một số trong số chúng như sau:
  • Khối lượng
  • Môi trường
  • Cổng
  • dnsPolicy
  • initContainers
  • nodeSelector
  • Giới hạn tài nguyên và yêu cầu
Để xem các pod hiện đang chạy trong cụm của bạn, bạn có thể chạykubectl get pods:

dsala@MININT-IB3HUA8:~$ kubectl get podsNAME READY STATUS RESTARTS AGEbusybox 1/1 Running 120 5d

Ngoài ra, bạn có thể chạykubectl describe podsmà không cần chỉ định bất kỳ pod nào. Thao tác này sẽ in ra mô tả về mọi pod đang chạy trong cụm. Trong trường hợp này, chỉ có busyboxpod, vì đây là pod duy nhất hiện đang chạy:

dsala@MININT-IB3HUA8:~$ kubectl describe podsName: busyboxNamespace: defaultPriority: 0PriorityClassName: <none>Node: aks-agentpool-10515745-2/10.240.0.6Start Time: Wed, 19 Sep 2018 14:23:30 -0600Labels: <none>Annotations: <none>Status: RunningIP: 10.244.1.7Containers: busybox:[...] (Đầu ra bị cắt bớt để dễ đọc)Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Pulled 45 giây (x121 trong 5 ngày) kubelet, aks-agentpool-10515745-2 Ảnh container "busybox" đã có trên machineNormal Đã tạo 44 giây (x121 trong 5 ngày) kubelet, aks-agentpool-10515745-2 Đã tạo containerNormal Đã bắt đầu 44 giây (x121 trong 5 ngày) kubelet, aks-agentpool-10515745-2 Đã bắt đầu container

Pod là hữu hạn. Khi nó chết hoặc bị xóa, nó không thể được khôi phục. IP của nó và các container đang chạy trên nó sẽ biến mất; chúng hoàn toàn phù du. Dữ liệu trên các pod được gắn kết dưới dạng ổ đĩa có thể hoặc không thể tồn tại, tùy thuộc vào cách bạn thiết lập. Nếu các pod của chúng ta chết và chúng ta mất chúng, làm thế nào để chúng ta đảm bảo rằng tất cả các dịch vụ vi mô của mình đang chạy? Vâng, triển khai chính là câu trả lời.

Triển khai​

Bản thân Pod không hữu ích lắm vì không hiệu quả lắm khi có nhiều hơn một phiên bản ứng dụng của chúng ta chạy trong một pod duy nhất. Việc cung cấp hàng trăm bản sao ứng dụng của chúng ta trên các pod khác nhau mà không có phương pháp để tìm kiếm tất cả chúng sẽ nhanh chóng trở nên mất kiểm soát.

Đây là lúc triển khai phát huy tác dụng. Với triển khai, chúng ta có thể quản lý pod của mình bằng bộ điều khiển. Điều này cho phép chúng ta không chỉ quyết định số lượng pod muốn chạy mà còn có thể quản lý các bản cập nhật bằng cách thay đổi phiên bản hình ảnh hoặc chính hình ảnh mà container của chúng ta đang chạy. Triển khai là thứ bạn sẽ làm việc cùng hầu hết thời gian. Với các triển khai cũng như các pod và bất kỳ đối tượng nào khác mà chúng tôi đã đề cập trước đó, chúng có định nghĩa riêng bên trong tệp YAML:

apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: implementation: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80

Chúng ta hãy bắt đầu khám phá định nghĩa của chúng.

Ở đầu YAML, chúng ta có các trường tổng quát hơn, chẳng hạn nhưapiVersion,kind vàmetadata. Nhưng bên dưới speclà nơi chúng ta sẽ tìm thấy các tùy chọn cụ thể cho Đối tượng API này.

Trong spec, chúng ta có thể thêm các trường sau:

Selector: Với trường Selector, quá trình triển khai sẽ biết mục tiêu là pod nào khi áp dụng các thay đổi. Có hai trường mà bạn sẽ sử dụng trong selector:matchLabels vàmatchExpressions. VớimatchLabels, selector sẽ sử dụng nhãn của pod (cặp khóa/giá trị). Điều quan trọng cần lưu ý là tất cả các nhãn mà bạn chỉ định ở đây sẽ làANDed. Điều này có nghĩa là pod sẽ yêu cầu nó có tất cả các nhãn mà bạn chỉ định trongmatchLabels.

Replicas: Điều này sẽ nêu số lượng pod mà quá trình triển khai cần tiếp tục chạy thông qua bộ điều khiển sao chép; ví dụ, nếu bạn chỉ định ba bản sao và một trong các pod chết, bộ điều khiển sao chép sẽ theo dõi thông số kỹ thuật của bản sao là trạng thái mong muốn và thông báo cho trình lập lịch để lập lịch cho một pod mới, vì trạng thái hiện tại là 2 kể từ khi pod chết.

RevisionHistoryLimit: Mỗi khi bạn thực hiện thay đổi đối với triển khai, thay đổi này sẽ được lưu dưới dạng bản sửa đổi của triển khai, sau đó bạn có thể hoàn nguyên về trạng thái trước đó hoặc lưu lại bản ghi về những thay đổi đã thực hiện. Bạn có thể tham khảo lịch sử của mình bằng kubectlrollout history implementation/<name of deployment>. Với revisionHistoryLimit, bạn có thể thiết lập một con số cho biết số lượng bản ghi bạn muốn lưu.

Chiến lược: Điều này sẽ cho phép bạn quyết định cách bạn muốn xử lý bất kỳ bản cập nhật hoặc quy mô pod theo chiều ngang nào. Để ghi đè mặc định là rollingUpdate, bạn cần viết khóa loại, trong đó bạn có thể chọn giữa hai giá trị: recreate hoặc rollingUpdate.

Mặc dù recreate là cách nhanh chóng để cập nhật triển khai của bạn, nhưng nó sẽ xóa tất cả các pod và thay thế chúng bằng các pod mới, nhưng điều đó ngụ ý rằng bạn sẽ phải cân nhắc đến thời gian ngừng hoạt động của hệ thống đối với loại chiến lược này. Mặt khác, rollingUpdate mượt mà hơn và chậm hơn, lý tưởng cho các ứng dụng có trạng thái có thể cân bằng lại dữ liệu của chúng. rollingUpdatemở ra cánh cửa cho hai trường nữa, đó là maxSurgevà maxUnavailable.

Trường đầu tiên sẽ là số lượng pod vượt quá tổng số lượng bạn muốn khi thực hiện cập nhật; ví dụ, triển khai với 100 pod và 20%maxSurgesẽ tăng lên tối đa 120 pod trong khi cập nhật. Tùy chọn tiếp theo sẽ cho phép bạn chọn số lượng pod theo tỷ lệ phần trăm bạn muốn loại bỏ để thay thế chúng bằng những pod mới trong kịch bản 100 pod. Trong trường hợp có 20%maxUnavailable, chỉ có 20 pod sẽ bị hủy và thay thế bằng pod mới trước khi tiếp tục thay thế phần còn lại của triển khai.

Mẫu: Đây chỉ là trường thông số kỹ thuật pod lồng nhau, trong đó bạn sẽ bao gồm tất cả thông số kỹ thuật và siêu dữ liệu của pod mà triển khai sẽ quản lý.

Chúng ta đã thấy rằng, với các triển khai, chúng ta quản lý các pod của mình và chúng giúp chúng ta duy trì chúng ở trạng thái mà chúng ta mong muốn. Tất cả các pod này vẫn nằm trong thứ được gọi là mạng cụm, đây là mạng khép kín trong đó chỉ các thành phần cụm Kubernetes mới có thể giao tiếp với nhau, thậm chí có bộ dải IP riêng. Làm thế nào để chúng ta giao tiếp với các pod của mình từ bên ngoài? Làm thế nào để chúng ta tiếp cận ứng dụng của mình? Đây là nơi các dịch vụ phát huy tác dụng.

Dịch vụ:

Têndịch vụkhông mô tả đầy đủ những gì các dịch vụ thực sự làm trong Kubernetes. Các dịch vụ Kubernetes là những gì định tuyến lưu lượng truy cập đến các pod của chúng ta. Chúng ta có thể nói rằng các dịch vụ là những gì liên kết các pod với nhau.

Hãy tưởng tượng rằng chúng ta có một ứng dụng kiểu frontend/backend điển hình, trong đó chúng ta có các pod frontend giao tiếp với các pod backend thông qua địa chỉ IP của các pod. Nếu một pod trong backend bị hỏng, chúng ta sẽ mất liên lạc với backend của mình. Điều này không chỉ vì pod mới sẽ không có cùng địa chỉ IP với pod đã hỏng mà giờ đây chúng ta còn phải cấu hình lại ứng dụng của mình để sử dụng địa chỉ IP mới. Vấn đề này và các vấn đề tương tự được giải quyết bằng dịch vụ.

Aservice là một đối tượng logic yêu cầu kube-proxy tạo các quy tắc iptables dựa trên các pod nào nằm sau dịch vụ. Các dịch vụ cấu hình các điểm cuối của chúng, đó là cách các pod nằm sau aservice được gọi, giống như cách các triển khai biết pod nào cần kiểm soát, trường bộ chọn và nhãn của pod.

Sơ đồ này cho bạn thấy cách các dịch vụ sử dụng nhãn để quản lý lưu lượng:





Các dịch vụ không chỉ khiến kube-proxy tạo các quy tắc để định tuyến lưu lượng; nó cũng sẽ kích hoạt một thứ gọi là kube-dns.

Kube-dns là một tập hợp các pod với SkyDNScác container chạy trên cụm cung cấp máy chủ DNS và bộ chuyển tiếp, sẽ tạo các bản ghi cho các dịch vụ và đôi khi là các pod để dễ sử dụng. Bất cứ khi nào bạn tạo một dịch vụ, một bản ghi DNS trỏ đến địa chỉ IP cụm nội bộ của dịch vụ sẽ được tạo bằng biểu mẫu service-name.namespace.svc.cluster.local. Bạn có thể tìm hiểu thêm về thông số kỹ thuật DNS của Kubernetes tại đây:https://github.com/kubernetes/dns/blob/master/docs/specification.md.

Quay lại ví dụ của chúng ta, bây giờ chúng ta chỉ cần cấu hình ứng dụng của mình để giao tiếp với dịch vụtên miền đủ điều kiện (FQDN)để giao tiếp với các pod phụ trợ của chúng ta. Theo cách này, địa chỉ IP của các pod và dịch vụ sẽ không quan trọng. Nếu một pod phía sau dịch vụ bị hỏng, dịch vụ sẽ xử lý mọi thứ bằng cách sử dụng bản ghi A, vì chúng ta sẽ có thể yêu cầu giao diện người dùng của mình định tuyến tất cả lưu lượng truy cập đến my-svc. Logic của dịch vụ sẽ xử lý mọi thứ khác.

Có một số loại dịch vụ mà bạn có thể tạo bất cứ khi nào bạn khai báo đối tượng sẽ được tạo trong Kubernetes. Hãy cùng xem xét chúng để xem loại nào phù hợp nhất với loại công việc chúng ta cần:

ClusterIP: Đây là dịch vụ mặc định. Bất cứ khi nào bạn tạo dịch vụ ClusterIP, nó sẽ tạo một dịch vụ có địa chỉ IP nội bộ cụm chỉ có thể định tuyến bên trong cụm Kubernetes. Loại này lý tưởng cho các pod chỉ cần giao tiếp với nhau và không đi ra ngoài cụm.

NodePort: Khi bạn tạo loại dịch vụ này, theo mặc định, một cổng ngẫu nhiên từ30000đến32767sẽ được phân bổ để chuyển tiếp lưu lượng đến các pod điểm cuối của dịch vụ. Bạn có thể ghi đè hành vi này bằng cách chỉ định một cổng nút trong mảng ports. Sau khi xác định được điều này, bạn sẽ có thể truy cập các pod của mình qua <Nodes-IP>:<Node-Port>. Điều này hữu ích để truy cập các pod của bạn từ bên ngoài cụm thông qua địa chỉ IP của Node.

LoadBalancer: Hầu hết thời gian, bạn sẽ chạy Kubernetes trên nhà cung cấp đám mây. Kiểu LoadBalancer lý tưởng cho những tình huống này, vì bạn sẽ có thể phân bổ địa chỉ IP công khai cho dịch vụ của mình thông qua API của nhà cung cấp đám mây. Đây là dịch vụ lý tưởng khi bạn muốn giao tiếp với các pod của mình từ bên ngoài cụm. Với LoadBalancer, bạn sẽ không chỉ có thể phân bổ địa chỉ IP công khai mà còn có thể phân bổ địa chỉ IP riêng từ mạng riêng ảo của mình bằng Azure. Vì vậy, bạn có thể nói chuyện với các pod của mình từ internet hoặc nội bộ trên mạng con riêng của bạn.

Hãy cùng xem lại định nghĩa dịch vụ của YAML:

apiVersion: v1kind: Servicemetadata: name: my-servicespec: selector: app: front-end type: NodePort ports: - name: http port: 80 targetPort: 8080 nodePort: 30024 protocol: TCP

YAML của dịch vụ rất đơn giản và các thông số kỹ thuật sẽ khác nhau tùy thuộc vào loại dịch vụ bạn đang tạo. Nhưng điều quan trọng nhất bạn phải lưu ý là định nghĩa cổng. Hãy cùng xem xét những điều sau:
  • port: Đây là cổng dịch vụ được hiển thị
  • targetPort: Đây là cổng trên các pod nơi dịch vụ đang gửi lưu lượng truy cập
  • nodePort: Đây là cổng sẽ được hiển thị
Mặc dù hiện tại chúng ta đã hiểu cách giao tiếp với các pod trong cụm của mình, nhưng chúng ta vẫn cần hiểu cách quản lý vấn đề mất dữ liệu mỗi khi apodis chấm dứt. Đây là lúc Persistent Volume (PV) được sử dụng.

Kubernetes và lưu trữ liên tục​

Lưu trữ liên tục trong thế giới container là một vấn đề nghiêm trọng. Lưu trữ duy nhất liên tục trên các lần chạy container là các lớp của hình ảnh và chúng chỉ đọc. Lớp nơi container chạy là đọc/ghi, nhưng tất cả dữ liệu trong lớp này sẽ bị xóa khi container dừng lại. Với pod, điều này cũng tương tự. Khi một container chết, dữ liệu được ghi vào nó sẽ biến mất.

Kubernetes có một tập hợp các đối tượng để xử lý lưu trữ trên các pod. Đối tượng đầu tiên mà chúng ta sẽ thảo luận là các khối lượng.

Khối lượng​

Volumesgiải quyết một trong những vấn đề lớn nhất khi nói đến lưu trữ liên tục. Trước hết, volume không thực sự là đối tượng, mà là định nghĩa về spec của pod. Khi bạn tạo một pod, bạn có thể định nghĩa một volume trong trường spec của pod. Các container trong pod này sẽ có thể gắn volume vào không gian tên mount của chúng và volume sẽ khả dụng khi container khởi động lại hoặc gặp sự cố. Tuy nhiên, volume được liên kết với pod và nếu pod bị xóa, volume cũng sẽ biến mất. Dữ liệu trên volume lại là một câu chuyện khác; datapersistence sẽ phụ thuộc vào phần phụ trợ của volume đó.

Kubernetes hỗ trợ một số loại volume hoặc nguồn volume và cách chúng được gọi trong các thông số kỹ thuật API, bao gồm từ bản đồ hệ thống tệp từ nút cục bộ, đĩa ảo của nhà cung cấp đám mây và volume được lưu trữ được xác định bằng phần mềm. Gắn hệ thống tệp cục bộ là loại phổ biến nhất mà bạn sẽ thấy khi nói đến các volume thông thường. Điều quan trọng cần lưu ý là nhược điểm của việc sử dụng hệ thống tệp nút cục bộ là dữ liệu sẽ không khả dụng trên tất cả các nút của cụm và chỉ khả dụng trên nút nơi pod được lên lịch.

Hãy cùng xem xét cách pod có ổ đĩa được định nghĩa trong YAML:

apiVersion: v1kind: Podmetadata: name: test-pdspec: containers: - image: k8s.gcr.io/test-webserver name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume hostPath: path: /data type: Directory

Lưu ý rằng có một trường có tên làvolumesunderspecand sau đó có một trường khác có tên làvolumeMounts.

Trường đầu tiên (ổ đĩa) là nơi bạn định nghĩa ổ đĩa mà bạn muốn tạo cho pod đó. Trường này sẽ luôn yêu cầu tên và sau đó là nguồn ổ đĩa. Tùy thuộc vào nguồn, các yêu cầu sẽ khác nhau. Trong ví dụ này, nguồn sẽ là hostPath, là hệ thống tệp cục bộ của một nút. hostPath hỗ trợ một số loại ánh xạ, từ thư mục, tệp, thiết bị khối và thậm chí cả ổ cắm Unix.

Trong trường thứ hai, volumeMounts, chúng ta có mountPath, là nơi bạn xác định đường dẫn bên trong vùng chứa nơi bạn muốn gắn khối lượng của mình vào. Tham số name là cách bạn chỉ định cho pod khối lượng nào sẽ sử dụng. Điều này quan trọng vì bạn có thể có nhiều loại khối lượng được xác định bên dưới khối lượng và tên sẽ là cách duy nhất để pod biết được loại nào

Bạn có thể tìm hiểu thêm về các loại khối lượng khác nhau tại đây https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes và trong tài liệu tham khảo API Kubernetes (https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#volume-v1-core).

Việc để các ổ đĩa chết cùng với các pod không phải là lý tưởng. Chúng tôi yêu cầu lưu trữ liên tục và đây là cách nhu cầu về PV ra đời.

Persistent Volume, Persistent Volume Claims và Storage Classes​

Sự khác biệt chính giữa volume và PV là, không giống như volume, PV thực sự là các đối tượng API Kubernetes, do đó, bạn có thể quản lý chúng riêng lẻ như các thực thể riêng biệt và do đó, chúng vẫn tồn tại ngay cả sau khi một pod bị xóa.

Bạn có thể tự hỏi tại sao tiểu mục này lại có PV, persistent volume (PVC) và storage class được trộn lẫn vào nhau. Lý do là vì tất cả chúng đều phụ thuộc vào nhau và điều quan trọng là phải hiểu cách chúng tương tác với nhau để cung cấp dung lượng lưu trữ cho pod của chúng ta.

Chúng ta hãy bắt đầu với PV và PVC. Giống như các ổ đĩa, PV có một nguồn lưu trữ, do đó cơ chế tương tự mà các ổ đĩa có được áp dụng ở đây. Bạn sẽ có một cụm lưu trữ được xác định bằng phần mềm cung cấp một số đơn vị logic (LUN), một nhà cung cấp đám mây cung cấp đĩa ảo hoặc thậm chí là một hệ thống tệp cục bộ cho nút Kubernetes, nhưng ở đây, thay vì được gọi là các nguồn ổ đĩa, chúng được gọi là các loại ổ đĩa liên tục.

PV khá giống với LUN trong một mảng lưu trữ: bạn tạo chúng, nhưng không có ánh xạ; chúng chỉ là một nhóm lưu trữ được phân bổ đang chờ được sử dụng. PVC giống như các ánh xạ LUN: chúng được sao lưu hoặc liên kết với một PV và cũng là những gì bạn thực sự xác định, liên kết và cung cấp cho pod mà sau đó nó có thể sử dụng cho các vùng chứa của mình.

Cách bạn sử dụng PVC trên pod hoàn toàn giống với các ổ đĩa thông thường. Bạn có hai trường: một trường để chỉ định PVC nào bạn muốn sử dụng và trường còn lại để cho pod biết sử dụng PVC đó trên container nào.

Định nghĩa đối tượng API YAML cho aPVC phải có mã sau:

apiVersion: v1kind: PersistentVolumeClaimmetadata: name: gluster-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi

YAML cho pod phải có mã sau:

kind: PodapiVersion: v1metadata: name: mypodspec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: "/mnt/gluster" name: volume volumes: - name: volume persistentVolumeClaim: claimName: gluster-pvc

Khi quản trị viên Kubernetes tạo PVC, có hai cách để đáp ứng yêu cầu này:
  • Tĩnh: Một số PV đã được tạo và sau đó khi người dùng tạo PVC, bất kỳ PV khả dụng nào có thể đáp ứng các yêu cầu sẽ được liên kết với PVC đó.
  • Động: Một số loại PV có thể tạo PV dựa trên định nghĩa PVC. Khi PVC được tạo, kiểu PV sẽ tạo động một đối tượng PV và phân bổ dung lượng lưu trữ ở phần phụ trợ; đây là cung cấp động. Điểm đáng lưu ý với cung cấp động là bạn cần một loại đối tượng lưu trữ Kubernetes thứ ba, được gọi là lớp lưu trữ.
Các lớp lưu trữ giống như một cách phân tầng dung lượng lưu trữ của bạn. Bạn có thể tạo một lớp cung cấp các ổ đĩa lưu trữ chậm hoặc một lớp khác có ổ SSD siêu nhanh. Tuy nhiên, các lớp lưu trữ phức tạp hơn một chút so với chỉ phân tầng. Như chúng tôi đã đề cập trong hai cách tạo PVC, các lớp lưu trữ là thứ giúp cung cấp động trở nên khả thi. Khi làm việc trên môi trường đám mây, bạn không muốn tự tay tạo mọi đĩa phụ trợ cho mọi PV. Các lớp lưu trữ sẽ thiết lập một thứ được gọi là trình cung cấp, trình này sẽ gọi trình cắm thêm dung lượng cần thiết để giao tiếp với API của nhà cung cấp đám mây của bạn. Mỗi nhà cung cấp đều có các thiết lập riêng để có thể giao tiếp với nhà cung cấp đám mây hoặc nhà cung cấp lưu trữ được chỉ định.

Bạn có thể cung cấp các lớp lưu trữ theo cách sau; đây là ví dụ về lớp lưu trữ sử dụng Azure-disk làm nhà cung cấp đĩa:

kind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: my-storage-classprovisioner: kubernetes.io/azure-diskparameters: storageaccounttype: Standard_LRS kind: Shared

Mỗi nhà cung cấp lớp lưu trữ và loại PV sẽ có các yêu cầu và tham số khác nhau, cũng như các khối lượng và chúng ta đã có tổng quan chung về cách chúng hoạt động và những gì chúng ta có thể sử dụng chúng. Việc tìm hiểu về các lớp lưu trữ và loại PV cụ thể sẽ tùy thuộc vào môi trường của bạn; bạn có thể tìm hiểu thêm về từng loại bằng cách nhấp vào các liên kết sau:
Trong bài viết này, chúng ta đã tìm hiểu về Kubernetes là gì, các thành phần của nó và những gì lợi thế của việc sử dụng dàn nhạc là. Với điều này, việc xác định từng đối tượng API Kubernetes, mục đích và trường hợp sử dụng của chúng sẽ trở nên dễ dàng. Bây giờ, bạn sẽ có thể hiểu cách các nút chính kiểm soát cụm và lập lịch cho các vùng chứa trong các nút công nhân.

Nếu bạn thấy bài viết này hữu ích, thì 'Hands-On Linux for Architects' sẽ hữu ích với bạn. Với cuốn sách này, bạn sẽ đề cập đến mọi thứ từ các thành phần và chức năng của Linux đến hỗ trợ phần cứng và phần mềm, giúp bạn triển khai và điều chỉnh các giải pháp hiệu quả dựa trên Linux. Bạn sẽ được hướng dẫn qua tổng quan về phương pháp thiết kế Linux và các khái niệm cốt lõi của việc thiết kế giải pháp. Nếu bạn là quản trị viên hệ thống Linux, kỹ sư hỗ trợ Linux, kỹ sư DevOps, chuyên gia tư vấn Linux hoặc bất kỳ ai muốn tìm hiểu hoặc mở rộng kiến thức về kiến trúc, thì cuốn sách này là dành cho bạn.
 
Back
Bên trên