EKS - ngày 1

Table of contents

Syllabus

  • Sáng: Giới thiệu Kubernetes: Kubernetes là gì? Tại sao sử dụng nó? Các khái niệm cốt lõi (Pod, Service, Deployment, ReplicaSet,..).

  • Chiều: Kiến trúc và thành phần của Kubernetes (Master node, Worker node, etcd, kube-apiserver).

  • Bài tập:

    1. Cài đặt Minikube (môi trường Kubernetes cục bộ) và triển khai ứng dụng "Hello World" cơ bản.

    2. Thử nghiệm mở rộng quy mô ứng dụng.

    3. Khám phá bảng điều khiển Kubernetes để trực quan cluster

Nội dung

Giới thiệu Kubernetes: Kubernetes là gì? Tại sao sử dụng nó? Các khái niệm cốt lõi

K8s là gì?

  • K8s: Open source platform để quản lý các containerized workloads và services.

  • K8s: 8 ký tự từ K tới s

  • Container orchestration: quá trình tự động hóa triển khai, quản lý và mở rộng, kết nối các container. Các nhiệm vụ chính: lifecycle management, scaling, load balancing, resource management, service discovery, configuration and secret management, monitoring và loging.

  • K8s là một container orchestrator

Tại sao sử dụng K8s?

  • Cách triển khai truyền thống: Chạy ứng dụng trên server vật lý, không có cách nào để định nghĩa các resource boundary cho apps, dẫn tới các vấn đề về phân bổ nguồn lực, các vấn đề về scale, chi phí đắt đỏ

  • Triển khai virtualization: Lúc này đã có thể chạy nhiều VM trên 1 CPU server vật lý. Virtualization cho phép tạo ra các VMs tách biệt nhau để deploy app, giảm cost, tăng mức độ linh hoạt. Tuy nhiên, mỗi VM sẽ bao gồm tất cả các components của nó, bao gồm cả OS.

  • Container deployment: Containers tương tự như VM, nhưng sẽ chia sẻ kernel với host (không bao gồm OS), vì thế nên nhẹ nhàng hơn VMs.

  • K8s là một container orchestrator, nên cung cấp đầy đủ các chức năng container orchestration như: service discovery và load balancing, storage orchestration, tự động hóa rollbacks và rollouts, sell-healing, secret and configuration management, batch execution, horizontal scaling, hỗ trợ IPv4/IPv6 dual-stack, được thiết kế để có khả năng mở rộng.

Các objects trong K8s

Trong Kubernetes (K8s), các đối tượng (objects) là các thực thể bền vững đại diện cho trạng thái mong muốn của cụm Kubernetes. Chúng mô tả các tài nguyên mà ứng dụng của bạn cần, cách chúng nên tương tác và các chính sách quản lý chúng. Một số đối tượng Kubernetes phổ biến:

  1. Pod: Đơn vị triển khai nhỏ nhất trong Kubernetes, đại diện cho một hoặc nhiều container chạy trên một nút (node). Các container trong một pod chia sẻ tài nguyên mạng và lưu trữ.

  2. Service: Cung cấp một điểm truy cập ổn định cho một tập hợp các pod, cho phép kết nối mạng giữa các pod và các dịch vụ bên ngoài.

  3. Deployment: Mô tả trạng thái mong muốn cho một tập hợp các pod, bao gồm số bản sao (replicas), bản cập nhật và chiến lược triển khai.

  4. ReplicaSet: Đảm bảo rằng số lượng bản sao pod đã chỉ định đang chạy tại mọi thời điểm.

  5. ConfigMap: Lưu trữ dữ liệu cấu hình phi bí mật dưới dạng cặp khóa-giá trị, có thể được sử dụng bởi pod như biến môi trường, đối số dòng lệnh hoặc tệp cấu hình.

  6. Secret: Tương tự như ConfigMap, nhưng được sử dụng để lưu trữ thông tin nhạy cảm như mật khẩu, mã thông báo và khóa.

  7. Namespace: Cung cấp một cơ chế để phân vùng tài nguyên Kubernetes thành các nhóm riêng biệt, cho phép nhiều nhóm và dự án tồn tại trong cùng một cụm.

  8. PersistentVolume (PV) và PersistentVolumeClaim (PVC): PV là một phần lưu trữ trong cụm, trong khi PVC là yêu cầu lưu trữ của người dùng. Kubernetes kết nối PVC với PV thích hợp để cung cấp lưu trữ bền vững cho pod.

  9. StatefulSet: Dùng để quản lý các ứng dụng trạng thái (stateful), đảm bảo rằng mỗi pod có một định danh duy nhất và ổn định.

  10. DaemonSet: Đảm bảo rằng một bản sao của pod đang chạy trên mỗi nút (hoặc một tập hợp con của các nút) trong cụm, hữu ích cho các tác vụ như thu thập nhật ký và giám sát.

Những đối tượng này làm việc cùng nhau để xác định và duy trì trạng thái mong muốn của ứng dụng trong cụm Kubernetes. Chúng ta tương tác với chúng bằng cách sử dụng Kubernetes API, thường thông qua công cụ dòng lệnh kubectl.

Object spec and status

Trong Kubernetes, mỗi đối tượng (object) có hai trường (field) chính: specstatus.

  1. Object Spec:

    • spec định nghĩa trạng thái mong muốn (desired state) của đối tượng, nghĩa là cách bạn muốn đối tượng hoạt động.

    • Khi bạn tạo một đối tượng Kubernetes, bạn thiết lập spec để mô tả các thuộc tính và cấu hình mong muốn của nó.

    • Ví dụ: trong spec của một Deployment, bạn xác định số bản sao (replicas) của pod, mẫu pod (pod template), và chiến lược triển khai (deployment strategy).

    • Kubernetes sẽ cố gắng đảm bảo rằng trạng thái thực tế của đối tượng khớp với spec đã định nghĩa.

    • spec được thiết lập bởi người dùng hoặc công cụ quản lý cấu hình cao hơn như Helm.

  2. Object Status:

    • status mô tả trạng thái hiện tại (current state) của đối tượng tại một thời điểm.

    • Kubernetes cập nhật trường status để phản ánh trạng thái thực tế của đối tượng trong cụm.

    • Ví dụ: status của một Deployment bao gồm số bản sao đang chạy, số bản sao đã sẵn sàng, và thông tin về các triển khai trước đó.

    • status được cập nhật bởi các thành phần Kubernetes như kubelet và điều khiển viên (controller), chứ không phải bởi người dùng.

    • Bạn có thể theo dõi status để hiểu trạng thái hiện tại của đối tượng và xác định xem nó có hoạt động như mong muốn hay không.

Mối quan hệ giữa specstatus:

  • Kubernetes liên tục làm việc để đảm bảo rằng trạng thái thực tế (status) của một đối tượng khớp với trạng thái mong muốn (spec).

  • Nếu có sự khác biệt giữa specstatus, các điều khiển viên Kubernetes sẽ thực hiện các hành động để đưa trạng thái thực tế về trạng thái mong muốn.

  • Ví dụ: nếu spec của một Deployment xác định 5 bản sao, nhưng status cho thấy chỉ có 3 bản sao đang chạy, điều khiển viên Deployment sẽ tạo thêm 2 bản sao pod để đáp ứng spec.

Mô tả 1 K8s object

Trong Kubernetes, để làm việc với các đối tượng (objects), bạn cần mô tả chúng bằng cách sử dụng định dạng YAML hoặc JSON, được gọi là manifest. Các tệp mô tả đối tượng này chứa các thông tin cần thiết để tạo và cấu hình đối tượng trong cụm Kubernetes.

Dưới đây là một cấu trúc cơ bản của pod manifest:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: my-app
spec:
  containers:
  - name: my-container
    image: my-image:latest
    ports:
    - containerPort: 80

Các thành phần bắt buộc của manifest:

  1. apiVersion: Chỉ định phiên bản API Kubernetes được sử dụng để tạo đối tượng. Phiên bản API khác nhau cho các đối tượng khác nhau.

  2. kind: Xác định loại đối tượng Kubernetes đang được mô tả, chẳng hạn như Pod, Deployment, Service, v.v.

  3. metadata: Chứa siêu dữ liệu (metadata) về đối tượng, bao gồm:

    • name: Tên của đối tượng, phải là duy nhất trong cùng một namespace.

    • labels: Các cặp khóa-giá trị được sử dụng để tổ chức và chọn các đối tượng.

    • Các trường tùy chọn khác như namespace, annotations, v.v.

  4. spec: Định nghĩa trạng thái mong muốn (desired state) của đối tượng. Nội dung của spec thay đổi tùy thuộc vào loại đối tượng: Đối với một Pod, spec xác định các container, volumes, và cài đặt khác. Đối với một Deployment, spec xác định số bản sao, mẫu pod, và chiến lược triển khai. Đối với một Service, spec xác định cổng, bộ chọn (selector), và loại dịch vụ.

status: (Không phải thành phần bắt buộc) Kubernetes tự động cập nhật trường status để phản ánh trạng thái hiện tại của đối tượng. Bạn không bao gồm status khi tạo hoặc cập nhật đối tượng.

Để áp dụng một tệp mô tả đối tượng vào cụm Kubernetes của bạn, bạn sử dụng lệnh kubectl apply -f object.yaml. Kubernetes sẽ đọc tệp và tạo hoặc cập nhật các đối tượng tương ứng.

Bạn cũng có thể sử dụng kubectl để lấy, cập nhật và xóa các đối tượng bằng cách tham chiếu đến chúng theo tên và loại.

Ví dụ khác về 1 file manifest mô tả các trường và object spec cho 1 K8s deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Server side field validation

Bắt đầu từ Kubernetes v1.25, API server cung cấp tính năng xserver-side field validation để phát hiện các trường không được công nhận hoặc trùng lặp trong một đối tượng. Nó cung cấp tất cả các chức năng của kubectl --validate trên phía máy chủ.

Công cụ kubectl sử dụng cờ --validate để thiết lập mức độ xác thực trường. Nó chấp nhận các giá trị ignore, warnstrict, đồng thời cũng chấp nhận các giá trị true (tương đương với strict) và false (tương đương với ignore). Cài đặt xác thực mặc định cho kubectl--validate=true.

  • Strict: Xác thực trường nghiêm ngặt, báo lỗi khi xác thực thất bại.

  • Warn: Xác thực trường được thực hiện, nhưng lỗi được hiển thị dưới dạng cảnh báo thay vì làm cho yêu cầu thất bại.

  • Ignore: Không thực hiện xác thực trường phía máy chủ.

Khi kubectl không thể kết nối với API server hỗ trợ field validation, nó sẽ quay lại sử dụng client-side validation. Kubernetes 1.27 và các phiên bản mới hơn luôn server-side validation; các phiên bản Kubernetes cũ hơn có thể không hỗ trợ.

Quản lý objects trong k8s

Kubernetes Object Management (Quản lý đối tượng Kubernetes) đề cập đến các kỹ thuật và công cụ khác nhau được sử dụng để quản lý vòng đời của các đối tượng Kubernetes, chẳng hạn như tạo, cập nhật, xóa và truy vấn các đối tượng như Pods, Deployments, Services, v.v.

Dưới đây là một số phương pháp và công cụ chính được sử dụng để quản lý đối tượng Kubernetes:

  1. Imperative commands:

    • Sử dụng các lệnh kubectl để tạo, cập nhật và xóa các đối tượng Kubernetes một cách tương tác.

    • Ví dụ: kubectl create deployment, kubectl delete pod, kubectl edit service.

    • Phương pháp này thích hợp cho việc thử nghiệm, khắc phục sự cố hoặc thực hiện các thay đổi một lần.

    • Ví dụ: Chạy câu lệnh sau để tạo deployement: kubectl create deployment nginx --image nginx

    • Ưu điểm:

      • Các lệnh được biểu thị dưới dạng một từ hành động đơn lẻ.

      • Các lệnh chỉ yêu cầu một bước duy nhất để thực hiện các thay đổi đối với cụm.

    • Nhược điểm:

      • Các lệnh không tích hợp với quy trình đánh giá thay đổi.

      • Các lệnh không cung cấp audit trail liên quan đến các thay đổi.

      • Các lệnh không cung cấp source of records ngoại trừ những gì đang hoạt động.

      • Các lệnh không cung cấp một template để tạo các đối tượng mới.

  2. Imperative object configuration:

    • Định nghĩa các đối tượng Kubernetes bằng cách sử dụng tệp cấu hình (thường là YAML) và áp dụng chúng bằng lệnh kubectl apply -f.

    • Cho phép quản lý phiên bản và theo dõi các thay đổi đối với cấu hình đối tượng.

    • Thích hợp cho các triển khai đơn giản hoặc các môi trường có số lượng đối tượng hạn chế.

    • Ví dụ:

      • Tạo một object được định nghĩa trong configuration file: kubectl create -f nginx.yaml

      • Tạo các object được định nghĩa ở 2 file configuration: kubectl delete -f nginx.yaml -f redis.yaml

      • Update các object được định nghĩa trong configuration file bằng cách overwrite các live configuration: kubectl replace -f nginx.yaml

    • Ưu điểm:

      • Cấu hình đối tượng có thể được lưu trữ trong một hệ thống quản lý mã nguồn như Git.

      • Cấu hình đối tượng có thể tích hợp với các quy trình như xem xét các thay đổi trước khi push và audit trails.

      • Cấu hình đối tượng cung cấp một template để tạo các đối tượng mới.

    • Nhược điểm so với các lệnh mệnh lệnh (imperative):

      • Cấu hình đối tượng yêu cầu hiểu biết cơ bản về object schema.

      • Cấu hình đối tượng yêu cầu bước bổ sung là viết tệp YAML.

  3. Declarative object configuration:

    • Tương tự như cấu hình đối tượng mệnh lệnh (imperative), nhưng sử dụng kubectl apply -f với một thư mục chứa nhiều tệp cấu hình.

    • Kubernetes tự động xác định các thay đổi và áp dụng chúng, đồng thời hợp nhất các cập nhật nếu có xung đột.

    • Thích hợp cho các triển khai phức tạp hơn với nhiều đối tượng và mối quan hệ giữa chúng.

Ví dụ:

Xử lý tất cả các tệp cấu hình đối tượng trong thư mục configs và tạo hoặc patch các đối tượng đang hoạt động. Trước tiên, bạn có thể sử dụng diff để xem những thay đổi nào sẽ được thực hiện, sau đó áp dụng:

    kubectl diff -f configs/
    kubectl apply -f configs/

Xử lý đệ quy các thư mục:

    kubectl diff -R -f configs/
    kubectl apply -R -f configs/
  • Ưu điểm:

    • Các thay đổi được thực hiện trực tiếp đối với các đối tượng đang hoạt động sẽ được giữ lại, ngay cả khi chúng không được merged back vào các tệp cấu hình.

    • Declarative object configuration hỗ trợ tốt hơn cho việc hoạt động trên các thư mục và tự động detect operation types (create, patch, delete) cho mỗi đối tượng.

  1. Helm:

    • Một trình quản lý gói cho Kubernetes, cho phép đóng gói, cấu hình và triển khai các ứng dụng và dịch vụ.

    • Sử dụng biểu đồ (charts) để định nghĩa, cài đặt và nâng cấp các ứng dụng phức tạp.

    • Hỗ trợ quản lý phiên bản, tùy chỉnh và chia sẻ các gói ứng dụng.

  2. Operators:

    • Mở rộng Kubernetes API để tự động hóa việc triển khai, vận hành và quản lý các ứng dụng phức tạp.

    • Đóng gói kiến thức vận hành và quản lý ứng dụng chuyên biệt, chẳng hạn như mở rộng cơ sở dữ liệu, sao lưu, phục hồi, v.v.

    • Sử dụng bộ điều khiển tùy chỉnh (custom controller) và CRDs để cung cấp khả năng tự phục hồi và đảm bảo trạng thái mong muốn.

  3. GitOps:

    • Một cách tiếp cận để quản lý cấu hình và triển khai ứng dụng sử dụng Git làm source of truth.

    • Git repository chứa trạng thái mong muốn của ứng dụng và cơ sở hạ tầng.

    • Các công cụ tự động hóa, chẳng hạn như Flux hoặc ArgoCD, đồng bộ trạng thái cluster với Git repository và triển khai các thay đổi.

Việc lựa chọn phương pháp quản lý nào, phụ thuộc vào quy mô, độ phức tạp và yêu cầu cụ thể của triển khai Kubernetes của bạn. Nhiều tổ chức sử dụng kết hợp các phương pháp khác nhau để đáp ứng nhu cầu của họ và áp dụng các phương pháp hay nhất cho việc quản lý cơ sở hạ tầng của họ.

Management techniqueOperates onRecommended environmentSupported writersLearning curve
Imperative commandsLive objectsDevelopment projects1+Lowest
Imperative object configurationIndividual filesProduction projects1Moderate
Declarative object configurationDirectories of filesProduction projects1+Highest

Object Names and IDs

  • Mỗi đối tượng trong cụm Kubernetes có một tên (Name) duy nhất cho loại tài nguyên đó. Mỗi đối tượng cũng có một UID duy nhất trong toàn bộ cụm.

  • Tên chỉ có thể có một đối tượng của một loại tại một thời điểm. Nếu đối tượng bị xóa, bạn có thể tạo một đối tượng mới với cùng tên.

  • Tên phải duy nhất trên tất cả các phiên bản API của cùng một tài nguyên.

  • Có bốn loại ràng buộc tên phổ biến cho tài nguyên: DNS Subdomain Names, RFC 1123 Label Names, RFC 1035 Label Names và Path Segment Names.

    1. DNS Subdomain Names:

      • Tối đa 253 ký tự

      • Chỉ chứa các ký tự chữ và số thường, '-' hoặc '.'

      • Bắt đầu và kết thúc bằng ký tự chữ hoặc số

    2. RFC 1123 Label Names:

      • Tối đa 63 ký tự

      • Chỉ chứa các ký tự chữ và số thường hoặc '-'

      • Bắt đầu và kết thúc bằng ký tự chữ hoặc số

    3. RFC 1035 Label Names:

      • Tối đa 63 ký tự

      • Chỉ chứa các ký tự chữ và số thường hoặc '-'

      • Bắt đầu bằng ký tự chữ cái thường và kết thúc bằng ký tự chữ hoặc số

      • Khác biệt duy nhất so với RFC 1123 là không được bắt đầu bằng chữ số

    4. Path Segment Names:

      • Không được là "." hoặc ".."

      • Không được chứa "/" hoặc "%"

  • UID là một chuỗi do hệ thống Kubernetes tạo ra để xác định duy nhất các đối tượng. Mỗi đối tượng được tạo trong suốt vòng đời của cụm có một UID riêng biệt.

  • UID của Kubernetes là universally unique identifiers (UUID) và được chuẩn hóa theo ISO/IEC 9834-8 và ITU-T X.667.

Labels và selectors

  • Labels là các cặp key/value được gắn vào các đối tượng như Pods, được sử dụng để chỉ định các thuộc tính nhận dạng có ý nghĩa và liên quan đến người dùng.

  • Labels cho phép truy vấn và theo dõi hiệu quả, lý tưởng để sử dụng trong UI và CLI. Thông tin không nhận dạng nên được ghi lại bằng annotations.

  • Label selectors được sử dụng để xác định một tập hợp các đối tượng. Có hai loại selectors:

    • Equality-based selectors: Cho phép lọc theo keys và values của labels. Các đối tượng khớp phải thỏa mãn tất cả các ràng buộc label được chỉ định. Các toán tử được hỗ trợ: =, ==, !=.

    • Set-based selectors: Cho phép lọc keys theo một tập hợp các values. Các toán tử được hỗ trợ: in, notin, exists.

  • Services và ReplicationControllers sử dụng equality-based requirement selectors, trong khi các tài nguyên mới hơn như Job, Deployment, ReplicaSet và DaemonSet hỗ trợ cả set-based requirements.

  • Labels có thể được sử dụng để giới hạn tập hợp các nodes mà một pod có thể lên lịch.

  • Nên sử dụng nhiều labels để phân biệt các tập hợp tài nguyên với nhau, ví dụ như trong ứng dụng nhiều tầng (multi-tier).

  • Kubectl có thể được sử dụng để cập nhật labels của các pods và tài nguyên hiện có.

  • Annotations là các cặp key/value không dùng để xác định và chọn đối tượng. Chúng có thể chứa thông tin lớn hơn và cấu trúc phức tạp hơn labels.

Ví dụ về annotations:

apiVersion: v1
kind: Pod
metadata:
  name: annotations-demo
  annotations:
    example.com/description: "A sample annotation"
    example.com/creator: "John Doe"
    example.com/contact: |
      {
        "email": "john@example.com",
        "phone": "123-456-7890"
      }
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

So sánh Labels và Annotations:

LabelsAnnotations
Sử dụng để xác định và chọn đối tượngKhông sử dụng để xác định và chọn đối tượng
Cặp key/value đơn giảnCó thể chứa thông tin lớn hơn và cấu trúc phức tạp hơn
Dùng để tổ chức và lựa chọn các tập con của đối tượngDùng để ghi lại thông tin mô tả, không ảnh hưởng đến hệ thống
Được sử dụng bởi các selectors của KubernetesKhông được sử dụng trực tiếp bởi Kubernetes
Giới hạn về độ dài và ký tự của key và valueKhông có giới hạn cụ thể về độ dài và ký tự của key và value
Ví dụ: app=frontend, env=productionVí dụ: description="A sample annotation", creator="John Doe"

Ví dụ về equality-based selectors:

  • environment = production

  • tier != frontend

Ví dụ về set-based selectors:

  • environment in (production, qa)

  • tier notin (frontend, backend)

  • partition

  • !partition

Namespaces

  • Namespaces cung cấp một cơ chế để cô lập các nhóm tài nguyên trong một cụm duy nhất. Tên của tài nguyên cần phải là duy nhất trong một namespace, nhưng không cần phải là duy nhất trên toàn bộ các namespaces. Để xem các namespaces, sử dụng câu lệnh: kubectl get namespace

  • Namespaces được sử dụng trong các môi trường có nhiều người dùng trải rộng trên nhiều nhóm hoặc dự án. Đối với các cụm có ít người dùng, bạn không cần phải tạo hoặc suy nghĩ về namespaces.

  • Namespaces cung cấp một phạm vi cho tên. Các namespaces không thể lồng vào nhau và mỗi tài nguyên Kubernetes chỉ có thể thuộc về một namespace.

  • Namespaces là một cách để phân chia tài nguyên cụm giữa nhiều người dùng (thông qua hạn ngạch tài nguyên).

  • Kubernetes bắt đầu với bốn namespaces ban đầu:

    • default

    • kube-node-lease

    • kube-public

    • kube-system

  • Để thiết lập namespace cho một yêu cầu hiện tại, sử dụng cờ --namespace. Ví dụ:

      kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
      kubectl get pods --namespace=<insert-namespace-name-here>
    
  • Bạn có thể lưu vĩnh viễn namespace cho tất cả các lệnh kubectl tiếp theo trong ngữ cảnh đó bằng cách sử dụng:

      kubectl config set-context --current --namespace=<insert-namespace-name-here>
    
  • Không phải tất cả các đối tượng đều nằm trong một namespace. Ví dụ, các tài nguyên cấp thấp như nodes và persistentVolumes không thuộc về bất kỳ namespace nào.

  • Namespaces và DNS trong Kubernetes:

    • Khi một Service được tạo, nó tạo ra một entry DNS tương ứng có dạng <service-name>.<namespace-name>.svc.cluster.local.

    • Nếu một container chỉ sử dụng <service-name>, nó sẽ resolve đến service trong cùng namespace.

    • Để truy cập services trên các namespaces khác, cần sử dụng fully qualified domain name (FQDN).

    • Tên của namespaces phải là các nhãn DNS hợp lệ theo RFC 1123.

    • Việc tạo các namespaces có tên trùng với các public top-level domains có thể gây ra xung đột với các bản ghi DNS public. Để giảm thiểu điều này, hãy giới hạn quyền tạo namespaces và có thể sử dụng các biện pháp bảo mật bổ sung.

  • Automatic labelling: Kubernetes control plane thiết lập một nhãn bất biến kubernetes.io/metadata.name trên tất cả các namespaces, với giá trị là tên của namespace.

Anotations

  • Bạn có thể sử dụng annotations để đính kèm non-identifying metadata vào các đối tượng. Các client như công cụ và thư viện có thể truy xuất metadata.

  • Annotations, giống như labels, là các cặp khóa/giá trị (key/value).

  • Khóa và giá trị trong annotations phải là chuỗi. Bạn không thể sử dụng các kiểu dữ liệu khác như số, boolean, danh sách, v.v.

Ví dụ về thông tin có thể được ghi lại trong annotations:

  • Các trường được quản lý bởi lớp cấu hình khai báo.

  • Thông tin về bản dựng, phát hành hoặc hình ảnh như dấu thời gian, ID phát hành, nhánh git, số PR, hàm băm hình ảnh và địa chỉ registry.

  • Con trỏ đến kho lưu trữ ghi log, giám sát, phân tích hoặc kiểm toán.

  • Thông tin về thư viện hoặc công cụ client có thể được sử dụng cho mục đích gỡ lỗi.

  • Thông tin về người dùng hoặc công cụ/hệ thống, chẳng hạn như URL của các đối tượng liên quan từ các thành phần hệ sinh thái khác.

Cú pháp và bộ ký tự của annotations:

  • Khóa hợp lệ của annotations có hai phân đoạn: một tiền tố tùy chọn và tên, được phân tách bằng dấu gạch chéo (/).

  • Phân đoạn tên là bắt buộc và phải có 63 ký tự trở xuống, bắt đầu và kết thúc bằng một ký tự chữ hoặc số.

  • Tiền tố là tùy chọn. Nếu được chỉ định, tiền tố phải là một tên miền phụ DNS.

Ví dụ về manifest cho một Pod có chứa annotation imageregistry:https://hub.docker.com/:

apiVersion: v1
kind: Pod
metadata:
  name: annotations-demo
  annotations:
    imageregistry: "https://hub.docker.com/"
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Field selectors

Field selectors cho phép bạn chọn các đối tượng Kubernetes dựa trên giá trị của một hoặc nhiều trường tài nguyên. Dưới đây là một số ví dụ về truy vấn field selector:

  • metadata.name=my-service

  • metadata.namespace!=default

  • status.phase=Pending

Ví dụ, lệnh kubectl sau đây chọn tất cả các Pod có giá trị của trường status.phaseRunning:

kubectl get pods --field-selector status.phase=Running

Field selectors về cơ bản là các bộ lọc tài nguyên. Theo mặc định, không có bộ chọn/bộ lọc nào được áp dụng, có nghĩa là tất cả các tài nguyên của loại được chỉ định sẽ được chọn.

Các trường được hỗ trợ cho field selectors khác nhau tùy thuộc vào loại tài nguyên Kubernetes. Tất cả các loại tài nguyên đều hỗ trợ các trường metadata.namemetadata.namespace.

Danh sách các trường được hỗ trợ:

KindFields
Podspec.nodeName, spec.restartPolicy, spec.schedulerName, spec.serviceAccountName, spec.hostNetwork, status.phase, status.podIP, status.nominatedNodeName
EventinvolvedObject.kind, involvedObject.namespace, involvedObject.name, involvedObject.uid, involvedObject.apiVersion, involvedObject.resourceVersion, involvedObject.fieldPath, reason, reportingComponent, source, type
Secrettype
Namespacestatus.phase
ReplicaSetstatus.replicas
ReplicationControllerstatus.replicas
Jobstatus.successful
Nodespec.unschedulable
CertificateSigningRequestspec.signerName

Bạn có thể sử dụng các toán tử =, ==!= với field selectors (=== có cùng ý nghĩa). Ví dụ, lệnh kubectl sau đây chọn tất cả các Service Kubernetes không nằm trong namespace default:

kubectl get services --all-namespaces --field-selector metadata.namespace!=default

Các bộ chọn field selector cũng có thể được kết hợp với nhau dưới dạng một danh sách phân tách bằng dấu phẩy. Ví dụ, lệnh kubectl sau đây chọn tất cả các Pod có status.phase không bằng Running và trường spec.restartPolicy bằng Always:

kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

Bạn cũng có thể sử dụng field selectors trên nhiều loại tài nguyên. Ví dụ, lệnh kubectl sau đây chọn tất cả các Statefulset và Service không nằm trong namespace default:

kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default

Finalizers

Finalizers là các khóa (keys) có phạm vi giới hạn (namespaced) cho Kubernetes biết phải đợi cho đến khi các điều kiện cụ thể được đáp ứng trước khi xóa hoàn toàn các tài nguyên được đánh dấu để xóa. Finalizers cảnh báo các controller dọn dẹp các tài nguyên mà đối tượng đã xóa sở hữu.

Cách finalizers hoạt động:

  1. Khi tạo một tài nguyên bằng tệp manifest, bạn có thể chỉ định các finalizers trong trường metadata.finalizers.

  2. Khi bạn cố gắng xóa tài nguyên, API server xử lý yêu cầu xóa và nhận thấy các giá trị trong trường finalizers. Nó sẽ:

    • Sửa đổi đối tượng để thêm trường metadata.deletionTimestamp với thời gian bạn bắt đầu xóa.

    • Ngăn chặn việc xóa đối tượng cho đến khi tất cả các mục trong trường metadata.finalizers được xóa.

    • Trả về mã trạng thái 202 (HTTP "Accepted").

  3. Controller quản lý finalizer đó nhận thấy việc cập nhật đối tượng thiết lập metadata.deletionTimestamp, cho biết việc xóa đối tượng đã được yêu cầu.

  4. Controller cố gắng đáp ứng các yêu cầu của các finalizers được chỉ định cho tài nguyên đó.

  5. Mỗi khi một điều kiện finalizer được đáp ứng, controller sẽ xóa khóa đó khỏi trường finalizers của tài nguyên.

  6. Khi trường finalizers trống, đối tượng có trường deletionTimestamp được thiết lập sẽ tự động bị xóa.

Một ví dụ phổ biến về finalizer là kubernetes.io/pv-protection, ngăn chặn việc xóa nhầm các đối tượng PersistentVolume. Khi một đối tượng PersistentVolume đang được sử dụng bởi một Pod, Kubernetes thêm finalizer pv-protection. Nếu bạn cố gắng xóa PersistentVolume, nó sẽ chuyển sang trạng thái Terminating, nhưng controller không thể xóa nó vì finalizer tồn tại. Khi Pod ngừng sử dụng PersistentVolume, Kubernetes xóa finalizer pv-protection và controller xóa volume.

Lưu ý:

  • Khi bạn XÓA một đối tượng, Kubernetes thêm dấu thời gian xóa cho đối tượng đó và ngay lập tức bắt đầu hạn chế các thay đổi đối với trường .metadata.finalizers cho đối tượng đang chờ xóa. Bạn có thể xóa các finalizers hiện có nhưng không thể thêm finalizer mới. Bạn cũng không thể sửa đổi deletionTimestamp cho một đối tượng sau khi nó được thiết lập.

  • Sau khi xóa được yêu cầu, bạn không thể khôi phục lại đối tượng này. Cách duy nhất là xóa nó và tạo một đối tượng tương tự mới.

  • Trong một số trường hợp, finalizers có thể chặn việc xóa các đối tượng phụ thuộc, có thể khiến đối tượng chủ sở hữu mục tiêu tồn tại lâu hơn dự kiến mà không bị xóa hoàn toàn. Trong những tình huống này, bạn nên kiểm tra finalizers và owner references trên chủ sở hữu mục tiêu và các đối tượng phụ thuộc để khắc phục sự cố.

  • Trong các trường hợp các đối tượng bị mắc kẹt ở trạng thái đang xóa, tránh xóa thủ công các finalizers để cho phép việc xóa tiếp tục. Finalizers thường được thêm vào tài nguyên vì một lý do, vì vậy việc xóa chúng một cách cưỡng bức có thể dẫn đến các vấn đề trong cụm của bạn. Điều này chỉ nên được thực hiện khi mục đích của finalizer được hiểu và được thực hiện theo cách khác (ví dụ: dọn dẹp thủ công một số đối tượng phụ thuộc).

Owners and Dependents

  1. Trong Kubernetes, một số đối tượng là chủ sở hữu của các đối tượng khác. Ví dụ, một ReplicaSet là chủ sở hữu của một tập hợp các Pod. Các đối tượng được sở hữu này là các phụ thuộc của chủ sở hữu của chúng.

  2. Các đối tượng phụ thuộc có trường metadata.ownerReferences tham chiếu đến đối tượng chủ sở hữu của chúng. Một tham chiếu chủ sở hữu hợp lệ bao gồm tên đối tượng và UID trong cùng một namespace với đối tượng phụ thuộc.

  3. Kubernetes tự động thiết lập giá trị của trường này cho các đối tượng phụ thuộc của các đối tượng khác như ReplicaSets, DaemonSets, Deployments, Jobs, CronJobs và ReplicationControllers. Bạn cũng có thể định cấu hình các mối quan hệ này theo cách thủ công bằng cách thay đổi giá trị của trường này.

  4. Các đối tượng phụ thuộc cũng có trường ownerReferences.blockOwnerDeletion nhận giá trị boolean và kiểm soát việc các phụ thuộc cụ thể có thể chặn garbage collection xóa đối tượng chủ sở hữu của chúng hay không.

  5. Một trình điều khiển admission của Kubernetes kiểm soát quyền truy cập của người dùng để thay đổi trường này cho các tài nguyên phụ thuộc, dựa trên quyền xóa của chủ sở hữu. Điều này ngăn người dùng không được phép trì hoãn việc xóa đối tượng chủ sở hữu.

Lưu ý:

  • Theo thiết kế, Cross-namespace owner references không được cho phép. Các phụ thuộc có namespace có thể chỉ định các chủ sở hữu phạm vi cụm (cluster-scoped) hoặc phạm vi namespace. Một chủ sở hữu có namespace phải tồn tại trong cùng namespace với phụ thuộc. Nếu không, tham chiếu chủ sở hữu được coi là không tồn tại và phụ thuộc sẽ bị xóa khi tất cả các chủ sở hữu được xác minh là không tồn tại.

  • Các phụ thuộc phạm vi cụm chỉ có thể chỉ định các chủ sở hữu phạm vi cụm. Trong phiên bản 1.20+, nếu một phụ thuộc phạm vi cụm chỉ định một loại có namespace là chủ sở hữu, nó sẽ được coi là có một tham chiếu chủ sở hữu không thể giải quyết và không thể được garbage collected.

  1. Khi bạn yêu cầu Kubernetes xóa một tài nguyên, API server cho phép trình điều khiển quản lý xử lý bất kỳ quy tắc finalizer nào cho tài nguyên đó. Finalizers ngăn chặn việc xóa nhầm các tài nguyên mà cụm của bạn có thể vẫn cần để hoạt động chính xác.

  2. Kubernetes cũng thêm các finalizers vào một tài nguyên chủ sở hữu khi bạn sử dụng xóa theo chuỗi (cascading deletion) kiểu foreground hoặc orphan. Trong trường hợp xóa kiểu foreground, nó thêm finalizer kiểu foreground để trình điều khiển phải xóa các tài nguyên phụ thuộc cũng có ownerReferences.blockOwnerDeletion=true trước khi nó xóa chủ sở hữu. Nếu bạn chỉ định một chính sách xóa orphan, Kubernetes thêm finalizer orphan để trình điều khiển bỏ qua các tài nguyên phụ thuộc sau khi nó xóa đối tượng chủ sở hữu.

Kubernetes khuyến nghị sử dụng một tập hợp các labels chung để cho phép các công cụ hoạt động cùng nhau và mô tả các đối tượng theo cách mà tất cả các công cụ đều có thể hiểu được. Các labels được khuyến nghị này mô tả các ứng dụng theo cách có thể được truy vấn.

Các labels được khuyến nghị chia sẻ một tiền tố chung: app.kubernetes.io. Labels không có tiền tố là riêng tư đối với người dùng. Tiền tố chung đảm bảo rằng các labels được chia sẻ không gây trở ngại cho các labels tùy chỉnh của người dùng.

Bảng các labels được khuyến nghị:

KeyDescriptionExampleType
app.kubernetes.io/nameTên của ứng dụngmysqlstring
app.kubernetes.io/instanceTên duy nhất xác định phiên bản của ứng dụngmysql-abcxyzstring
app.kubernetes.io/versionPhiên bản hiện tại của ứng dụng (ví dụ: SemVer 1.0, mã băm sửa đổi, v.v.)5.7.21string
app.kubernetes.io/componentThành phần trong kiến trúcdatabasestring
app.kubernetes.io/part-ofTên của ứng dụng cấp cao hơn mà ứng dụng này là một phần củawordpressstring
app.kubernetes.io/managed-byCông cụ được sử dụng để quản lý hoạt động của ứng dụngHelmstring

Ví dụ về một đối tượng StatefulSet sử dụng các labels này:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: mysql-abcxyz
    app.kubernetes.io/version: "5.7.21"
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
    app.kubernetes.io/managed-by: Helm

Ví dụ về một ứng dụng web đơn giản sử dụng cơ sở dữ liệu, được cài đặt bằng Helm:

Đối tượng Deployment cho WordPress:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: wordpress
    app.kubernetes.io/instance: wordpress-abcxyz
    app.kubernetes.io/version: "4.9.4"
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: server
    app.kubernetes.io/part-of: wordpress

Đối tượng StatefulSet cho MySQL:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: mysql-abcxyz
    app.kubernetes.io/version: "5.7.21"
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress

Với StatefulSet và Service của MySQL, bạn sẽ nhận thấy thông tin về cả MySQL và WordPress, ứng dụng lớn hơn mà nó thuộc về, đều được bao gồm trong các labels.

K8s components

Components of Kubernetes

Khi bạn triển khai Kubernetes, bạn sẽ có một cụm (cluster).

Một cụm Kubernetes bao gồm một tập hợp các worker nodes, được gọi là các nút (nodes), chạy các ứng dụng được đóng gói trong container. Mỗi cụm có ít nhất một worker node.

Các worker node chứa các Pod, là các thành phần của application workload. Control plane quản lý các worker node và các Pod trong cluster. Trong môi trường production, control plane thường chạy trên nhiều máy tính và một cụm thường chạy nhiều nodes, cung cấp khả năng chịu lỗi và tính khả dụng cao.

Control Plane components

Control plane của Kubernetes bao gồm các thành phần sau:

  1. kube-apiserver:

    • Là thành phần của Kubernetes control plane, expose Kubernetes API.

    • Là front end cho Kubernetes control plane.

    • Được thiết kế để scale theo chiều ngang bằng cách triển khai nhiều instance.

  2. etcd:

    • Là một key-value store nhất quán và có tính khả dụng cao, được sử dụng làm backing store cho tất cả dữ liệu của cụm Kubernetes.

    • Cần có kế hoạch sao lưu dữ liệu nếu sử dụng etcd làm backing store.

  3. kube-scheduler:

    • Thành phần của control plane, theo dõi các Pod mới được tạo mà chưa được gán node và chọn một node để chúng chạy trên đó.

    • Các yếu tố được xem xét khi ra quyết định lên lịch bao gồm: yêu cầu tài nguyên, ràng buộc phần cứng/phần mềm/chính sách, đặc tả affinity và anti-affinity, vị trí dữ liệu, interference giữa các workload và thời hạn.

  4. kube-controller-manager:

    • Thành phần của control plane, chạy các controller process.

    • Mỗi controller về logic là một tiến trình riêng biệt, nhưng để giảm sự phức tạp, chúng được biên dịch thành một binary duy nhất và chạy trong một tiến trình.

    • Có nhiều loại controller khác nhau, ví dụ như Node controller, Job controller, EndpointSlice controller, ServiceAccount controller, v.v.

  5. cloud-controller-manager:

    • Thành phần Kubernetes control plane, nhúng logic điều khiển đặc thù cho cloud.

    • Cho phép liên kết cụm của bạn với API của nhà cung cấp cloud và tách biệt các thành phần tương tác với nền tảng cloud khỏi các thành phần chỉ tương tác với cụm của bạn.

    • Chỉ chạy các controller đặc thù cho nhà cung cấp cloud của bạn.

    • Kết hợp một số vòng lặp điều khiển độc lập về mặt logic thành một binary duy nhất mà bạn chạy như một tiến trình duy nhất, tương tự như kube-controller-manager.

    • Có thể scale theo chiều ngang để cải thiện hiệu suất hoặc dung nạp lỗi.

Các thành phần trên hoạt động cùng nhau để cung cấp các chức năng và tính năng của Kubernetes control plane.

Node components

Node components chạy trên mỗi node, duy trì các pod đang chạy và cung cấp môi trường thời gian chạy (runtime environment) của Kubernetes. Các thành phần chính của node bao gồm:

  1. kubelet:

    • Là một agent chạy trên mỗi node trong cụm.

    • Đảm bảo rằng các container đang chạy trong một Pod.

    • Lấy một tập hợp các PodSpecs được cung cấp thông qua các cơ chế khác nhau và đảm bảo rằng các container được mô tả trong các PodSpecs đó đang chạy và khỏe mạnh.

    • Không quản lý các container không được tạo bởi Kubernetes.

  2. kube-proxy:

    • Là một network proxy chạy trên mỗi node trong cụm của bạn, triển khai một phần của khái niệm Kubernetes Service.

    • Duy trì các quy tắc mạng trên các node. Các quy tắc mạng này cho phép giao tiếp mạng với các Pod của bạn từ các phiên mạng bên trong hoặc bên ngoài cụm của bạn.

    • Sử dụng operating system packet filtering layer nếu có và nếu nó khả dụng. Nếu không, kube-proxy sẽ tự forwards traffic.

  3. Container runtime:

    • Là một thành phần cơ bản giúp Kubernetes chạy các container một cách hiệu quả.

    • 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ỳ triển khai nào khác của Kubernetes CRI (Container Runtime Interface).

Các thành phần này hoạt động trên mỗi node để đảm bảo rằng các pod và container được quản lý và chạy đúng cách trong môi trường Kubernetes.

Addons

Addons sử dụng các tài nguyên của Kubernetes (DaemonSet, Deployment, v.v.) để triển khai các tính năng của cluster. Vì các tài nguyên này cung cấp các tính năng cấp cluster, nên các tài nguyên có namespace của addons thuộc về namespace kube-system.

Dưới đây là mô tả về một số addons được chọn:

  1. DNS:

    • Mặc dù các addons khác không hoàn toàn bắt buộc, nhưng tất cả các cluster Kubernetes nên có DNS của cluster, vì nhiều ví dụ phụ thuộc vào nó.

    • DNS của cluster là một máy chủ DNS, bổ sung cho (các) máy chủ DNS khác trong môi trường của bạn, phục vụ các bản ghi DNS cho các service của Kubernetes.

    • Các container được khởi động bởi Kubernetes tự động bao gồm máy chủ DNS này trong tìm kiếm DNS của chúng.

  2. Web UI (Dashboard):

    • Dashboard là một giao diện người dùng dựa trên web có mục đích chung cho các cluster Kubernetes.

    • Nó cho phép người dùng quản lý và khắc phục sự cố các ứng dụng đang chạy trong cluster, cũng như chính cluster.

  3. Container Resource Monitoring:

    • Container Resource Monitoring ghi lại các số liệu thời gian chung về các container vào một cơ sở dữ liệu trung tâm và cung cấp một giao diện người dùng để duyệt qua dữ liệu đó.
  4. Cluster-level Logging:

    • Cơ chế ghi log cấp cluster chịu trách nhiệm lưu trữ log container vào một kho lưu trữ log trung tâm với giao diện tìm kiếm/duyệt.
  5. Network Plugins:

    • Network plugins là các thành phần phần mềm triển khai đặc tả container network interface (CNI).

    • Chúng chịu trách nhiệm cấp địa chỉ IP cho các pod và cho phép chúng giao tiếp với nhau trong cluster.

Các addons này mở rộng và cải thiện chức năng của cluster Kubernetes, cung cấp các tính năng bổ sung như DNS, giám sát tài nguyên, ghi log và kết nối mạng cho các container.

K8s API

Tóm tắt về Kubernetes API:

  1. API server là thành phần cốt lõi của Kubernetes control plane. Nó cung cấp một HTTP API cho phép người dùng cuối, các phần khác nhau của cluster và các thành phần bên ngoài giao tiếp với nhau.

  2. Kubernetes API cho phép truy vấn và thao tác trạng thái của các API objects trong Kubernetes (ví dụ: Pods, Namespaces, ConfigMaps và Events).

  3. Mỗi cluster Kubernetes công bố đặc tả của các API mà cluster phục vụ thông qua hai cơ chế: Discovery API và Kubernetes OpenAPI Document.

  4. Discovery API:

    • Cung cấp thông tin về các API của Kubernetes: tên API, tài nguyên, phiên bản và các hoạt động được hỗ trợ.

    • Có sẵn ở dạng tổng hợp (aggregated) và không tổng hợp (unaggregated).

    • Ví dụ về Unaggregated discovery API:

        {
          "kind": "APIGroupList",
          "apiVersion": "v1",
          "groups": [
            {
              "name": "apiregistration.k8s.io",
              "versions": [
                {
                  "groupVersion": "apiregistration.k8s.io/v1",
                  "version": "v1"
                }
              ],
              "preferredVersion": {
                "groupVersion": "apiregistration.k8s.io/v1",
                "version": "v1"
              }
            },
            ...
          ]
        }
      
  5. Kubernetes OpenAPI Document:

    • Cung cấp lược đồ OpenAPI v2.0 và v3.0 đầy đủ cho tất cả các điểm cuối API của Kubernetes.

    • OpenAPI v3 là phương thức được ưu tiên để truy cập OpenAPI vì nó cung cấp một cái nhìn toàn diện và chính xác hơn về API.

    • Ví dụ về OpenAPI v3:

        {
          "paths": {
            "api/v1": {
              "serverRelativeURL": "/openapi/v3/api/v1?hash=..."
            },
            "apis/admissionregistration.k8s.io/v1": {
              "serverRelativeURL": "/openapi/v3/apis/admissionregistration.k8s.io/v1?hash=..."
            },
            ...
          }
        }
      
  6. Kubernetes hỗ trợ nhiều phiên bản API, mỗi phiên bản ở một đường dẫn API khác nhau (ví dụ: /api/v1 hoặc /apis/rbac.authorization.k8s.io/v1alpha1) để dễ dàng loại bỏ các trường hoặc tái cấu trúc biểu diễn tài nguyên.

  7. Kubernetes cam kết duy trì khả năng tương thích cho các API chính thức khi chúng đạt đến tình trạng generally available (GA), thường là ở phiên bản API v1.

  8. API của Kubernetes có thể được mở rộng bằng cách sử dụng Custom Resources hoặc triển khai một lớp tổng hợp (aggregation layer).

Lưu ý:

  • Mặc dù Kubernetes cũng nhằm mục đích duy trì khả năng tương thích cho các phiên bản API alpha, trong một số trường hợp điều này là không thể. Nếu bạn sử dụng bất kỳ phiên bản API alpha nào, hãy kiểm tra release notes của Kubernetes khi nâng cấp cluster của bạn, trong trường hợp API đã thay đổi theo cách không tương thích yêu cầu xóa tất cả các đối tượng alpha hiện có trước khi nâng cấp

Kiến trúc và thành phần của Kubernetes

Components of Kubernetes

Kubernetes cluster architecture

Nodes

Tổng quan về Nodes trong Kubernetes

  • Kubernetes chạy workload của bạn bằng cách đặt các containers vào Pods để chạy trên Nodes.

  • Một Node 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 control plane và chứa các dịch vụ cần thiết để chạy Pods.

  • Thông thường, bạn có nhiều Nodes trong một cluster; trong môi trường học tập hoặc giới hạn tài nguyên, bạn có thể chỉ có một Node.

Các thành phần trên một Node bao gồm:

  • kubelet

  • container runtime

  • kube-proxy

Quản lý Nodes

Thêm Nodes vào API server:
  1. Self-register: kubelet trên một node tự đăng ký với control plane.

  2. Manually add: Bạn (hoặc người dùng khác) thêm một Node object thủ công.

Quy trình kiểm tra Node object mới:
  • Kubernetes tạo một Node object nội bộ và kiểm tra xem kubelet có đăng ký với API server trùng với metadata.name của Node hay không.

  • Nếu Node healthy (tất cả dịch vụ cần thiết đang chạy), nó đủ điều kiện chạy Pod. Nếu không, Node bị bỏ qua cho đến khi healthy.

Lưu ý: Kubernetes giữ object của Node không hợp lệ và tiếp tục kiểm tra xem nó có trở nên healthy hay không. Bạn hoặc một controller phải xóa Node object để ngừng health check.

Tính duy nhất của tên Node
  • Hai Nodes không thể có cùng tên tại cùng một thời điểm.

  • Kubernetes giả định rằng tài nguyên cùng tên là cùng một object, dẫn đến không nhất quán nếu một instance được sửa đổi mà không thay đổi tên.

Self-registration của Nodes

  • Khi kubelet flag --register-node là true (mặc định), kubelet sẽ tự động đăng ký với API server.

  • Các tùy chọn khi khởi động kubelet:

    • --kubeconfig: Đường dẫn đến credentials để xác thực với API server.

    • --cloud-provider: Cách để nói chuyện với cloud provider để đọc metadata về bản thân.

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

    • --register-with-taints: Đăng ký node với danh sách taints đã cho.

    • --node-ip: Danh sách IP addresses của node.

    • --node-labels: Labels để thêm khi đăng ký node trong cluster.

    • --node-status-update-frequency: Tần suất kubelet gửi trạng thái của node đến API server.

Lưu ý: Khi Node configuration cần được cập nhật, nên tái đăng ký node với API server để đảm bảo tất cả Pods sẽ được drain và re-scheduled đúng cách.

Quản lý Node thủ công
  • Tạo và sửa Node objects sử dụng kubectl.

  • Khi tạo Node objects thủ công, set flag --register-node=false.

  • Bạn có thể sửa Node objects bất kể cài đặt của --register-node.

Trạng thái Node

  • Trạng thái của một Node chứa thông tin về: Addresses, Conditions, Capacity and Allocatable, Info.

  • Sử dụng kubectl describe node để xem trạng thái và chi tiết của Node.

Heartbeats của Node

  • Có hai dạng heartbeats:

    • Cập nhật .status của Node.

    • Lease objects trong namespace kube-node-lease.

Node controller

  • Node controller có nhiều vai trò trong vòng đời của node, bao gồm:

    • Gán CIDR block cho node khi đăng ký.

    • Cập nhật danh sách nodes nội bộ của node controller với danh sách machines từ cloud provider.

    • Giám sát sức khỏe của nodes, và thực hiện eviction khi cần thiết.

Rate limits on eviction:
  • Node controller giới hạn tốc độ eviction theo --node-eviction-rate.

  • Khi một zone có ít nhất --unhealthy-zone-threshold nodes không khỏe mạnh, tốc độ eviction giảm.

Resource capacity tracking

  • Node objects theo dõi thông tin về dung lượng tài nguyên của node.

  • Kubernetes scheduler đảm bảo đủ tài nguyên cho tất cả Pods trên Node.

Node topology

  • Nếu kích hoạt TopologyManager, kubelet có thể sử dụng topology hints khi đưa ra quyết định gán tài nguyên.

Swap memory management

  • Để bật swap trên node, cần bật NodeSwap feature gate và set flag --fail-swap-on=false.

  • Cấu hình memorySwap.swapBehavior để xác định cách node sử dụng swap memory.

  • Swap chỉ được hỗ trợ với cgroup v2.

Lưu ý: Khi bật tính năng swap memory, dữ liệu Kubernetes như nội dung của Secret objects có thể được swap lên đĩa.

Giao tiếp giữa Nodes và Control Plane trong Kubernetes

Giao tiếp từ Node đến Control Plane

Kubernetes sử dụng mô hình API "hub-and-spoke". Tất cả các API từ nodes (hoặc các pods chúng chạy) đều kết thúc tại API server. Các thành phần khác của control plane không được thiết kế để cung cấp dịch vụ từ xa. API server được cấu hình để lắng nghe các kết nối từ xa trên cổng HTTPS bảo mật (thường là cổng 443) với một hoặc nhiều hình thức xác thực khách hàng được bật. Cần bật ít nhất một hoặc nhiều hình thức uỷ quyền, đặc biệt nếu cho phép các yêu cầu ẩn danh hoặc tokens của service account.

Bảo mật kết nối

  • Nodes cần được trang bị chứng chỉ gốc công khai của cluster để kết nối an toàn với API server cùng với các credentials khách hàng hợp lệ.

  • Kubelet TLS bootstrapping: Tự động cung cấp chứng chỉ khách hàng cho kubelet.

  • Pods muốn kết nối với API server có thể làm điều này an toàn bằng cách sử dụng service account. Kubernetes sẽ tự động chèn chứng chỉ gốc công khai và bearer token hợp lệ vào pod khi nó được khởi tạo.

  • Dịch vụ Kubernetes (trong namespace mặc định) được cấu hình với địa chỉ IP ảo được chuyển hướng (qua kube-proxy) đến endpoint HTTPS trên API server.

Kết nối từ control plane đến node

Có hai đường giao tiếp chính từ control plane (API server) đến nodes:

  1. Từ API server đến tiến trình kubelet chạy trên mỗi node trong cluster.

  2. Từ API server đến bất kỳ node, pod, hoặc dịch vụ nào thông qua chức năng proxy của API server.

API server đến kubelet

Các kết nối từ API server đến kubelet được sử dụng để:

  • Truy xuất logs cho pods.

  • Kết nối (thường qua kubectl) đến các pods đang chạy.

  • Cung cấp chức năng port-forwarding của kubelet.

Những kết nối này kết thúc tại endpoint HTTPS của kubelet. Mặc định, API server không xác minh chứng chỉ dịch vụ của kubelet, khiến kết nối có thể bị tấn công man-in-the-middle và không an toàn để chạy qua mạng không đáng tin cậy hoặc công khai.

Lưu ý: Để xác minh kết nối này, sử dụng flag --kubelet-certificate-authority để cung cấp cho API server gói chứng chỉ gốc để xác minh chứng chỉ dịch vụ của kubelet. Nếu không thể, sử dụng SSH tunneling giữa API server và kubelet để tránh kết nối qua mạng không đáng tin cậy hoặc công khai. Cuối cùng, nên bật xác thực và/hoặc ủy quyền kubelet để bảo mật API kubelet.

API server đến nodes, pods, và services

Các kết nối từ API server đến một node, pod, hoặc dịch vụ mặc định là các kết nối HTTP thuần túy và do đó không được xác thực hoặc mã hóa. Có thể chạy qua kết nối HTTPS bảo mật bằng cách thêm tiền tố https: vào tên node, pod, hoặc dịch vụ trong URL API, nhưng sẽ không xác minh chứng chỉ được cung cấp bởi endpoint HTTPS cũng như không cung cấp credentials khách hàng. Vì vậy, mặc dù kết nối được mã hóa, nhưng không cung cấp bất kỳ đảm bảo nào về tính toàn vẹn. Các kết nối này hiện không an toàn để chạy qua mạng không đáng tin cậy hoặc công khai.

SSH tunnels

  • Kubernetes hỗ trợ SSH tunnels để bảo vệ các đường giao tiếp từ control plane đến nodes. Trong cấu hình này, API server khởi tạo một SSH tunnel đến mỗi node trong cluster và chuyển tất cả traffic đến kubelet, node, pod, hoặc service qua tunnel. Tunnel này đảm bảo traffic không bị lộ ra ngoài mạng mà nodes đang chạy.

Lưu ý: SSH tunnels hiện đang bị deprecate, vì vậy không nên sử dụng trừ khi thực sự cần. Konnectivity service là sự thay thế cho kênh giao tiếp này.

Konnectivity service

Trạng thái tính năng: Kubernetes v1.18 [beta]
  • Konnectivity service cung cấp proxy cấp TCP cho giao tiếp từ control plane đến cluster, bao gồm hai phần: Konnectivity server trong mạng control plane và Konnectivity agents trong mạng nodes. Các agents thiết lập kết nối với server và duy trì các kết nối mạng. Sau khi bật Konnectivity service, tất cả traffic từ control plane đến nodes sẽ đi qua các kết nối này.

Thực hiện: Thực hiện theo hướng dẫn thiết lập Konnectivity service trong cluster: https://kubernetes.io/docs/tasks/extend-kubernetes/setup-konnectivity/

Controllers

  • Control loop: Một vòng lặp không kết thúc, điều chỉnh trạng thái của hệ thống. Ví dụ: Thermostat trong một phòng, điều chỉnh nhiệt độ phòng theo nhiệt độ mong muốn.

  • Trong Kubernetes, các controllers là các vòng lặp điều khiển theo dõi trạng thái của cluster và thực hiện hoặc yêu cầu các thay đổi khi cần thiết.

Controller pattern

  • Controller theo dõi ít nhất một loại tài nguyên Kubernetes. Các object này có trường spec đại diện cho trạng thái mong muốn.

  • Controller chịu trách nhiệm đưa trạng thái hiện tại gần hơn với trạng thái mong muốn.

  • Controller có thể tự thực hiện hành động hoặc gửi thông điệp đến API server để có các tác động hữu ích.

Control qua API server

  • Job controller: Một ví dụ về controller tích hợp sẵn của Kubernetes. Job là một tài nguyên Kubernetes chạy một hoặc nhiều Pods để thực hiện một nhiệm vụ và sau đó dừng lại.

  • Khi Job controller thấy một nhiệm vụ mới, nó đảm bảo rằng kubelets trên một tập hợp các Nodes đang chạy đúng số lượng Pods để hoàn thành công việc.

  • Job controller không tự chạy bất kỳ Pods hay containers nào, thay vào đó, nó yêu cầu API server tạo hoặc xóa Pods.

  • Sau khi tạo một Job mới, trạng thái mong muốn là hoàn thành Job. Job controller cập nhật trạng thái hiện tại của Job gần hơn với trạng thái mong muốn bằng cách tạo các Pods thực hiện công việc.

  • Lưu ý: Controller cũng cập nhật các object cấu hình của chúng. Ví dụ: Sau khi hoàn thành công việc cho một Job, Job controller cập nhật Job object để đánh dấu là Finished.

Direct control

  • Một số controllers cần thực hiện các thay đổi đối với những thứ bên ngoài cluster.

  • Ví dụ: Một controller đảm bảo đủ Nodes trong cluster sẽ cần một hệ thống bên ngoài để thiết lập các Nodes mới khi cần.

  • Controllers này tìm trạng thái mong muốn từ API server, sau đó giao tiếp trực tiếp với hệ thống bên ngoài để đưa trạng thái hiện tại gần hơn với trạng thái mong muốn.

Desired vs Current State

  • Kubernetes có khả năng xử lý sự thay đổi liên tục và cluster có thể thay đổi bất kỳ lúc nào khi công việc diễn ra và các vòng lặp điều khiển tự động sửa lỗi.

  • Miễn là các controllers trong cluster đang chạy và có thể thực hiện các thay đổi hữu ích, không cần thiết phải đạt trạng thái ổn định tổng thể.

Thiết kế

  • Kubernetes sử dụng nhiều controllers, mỗi cái quản lý một khía cạnh cụ thể của trạng thái cluster. Mỗi vòng lặp điều khiển (controller) sử dụng một loại tài nguyên như trạng thái mong muốn và quản lý một loại tài nguyên khác để thực hiện trạng thái mong muốn đó.

  • Ví dụ: Job controller theo dõi Job objects để phát hiện công việc mới và Pod objects để chạy các Job và sau đó kiểm tra khi công việc hoàn thành.

  • Lưu ý: Có thể có nhiều controllers tạo hoặc cập nhật cùng một loại object. Các controllers chỉ chú ý đến các tài nguyên liên kết với tài nguyên điều khiển của chúng.

Cách chạy controllers

  • Kubernetes đi kèm với một tập hợp các controllers tích hợp sẵn chạy bên trong kube-controller-manager, cung cấp các hành vi cốt lõi quan trọng.

  • Deployment controllerJob controller là các ví dụ về controllers tích hợp sẵn của Kubernetes. Kubernetes cho phép bạn chạy một control plane có khả năng chịu lỗi, vì vậy nếu bất kỳ controller tích hợp sẵn nào bị lỗi, một phần khác của control plane sẽ tiếp nhận công việc.

  • Bạn có thể tìm thấy controllers chạy bên ngoài control plane để mở rộng Kubernetes hoặc tự viết một controller mới. Bạn có thể chạy controller của mình dưới dạng một tập hợp các Pods hoặc bên ngoài Kubernetes tùy thuộc vào những gì controller đó thực hiện.

Leases

Leases trong hệ thống phân tán

Leases cung cấp cơ chế lock shared resources và điều phối hoạt động giữa các thành viên trong một set. Trong Kubernetes, khái niệm lease được đại diện bởi các đối tượng Lease trong nhóm API coordination.k8s.io, được sử dụng cho các khả năng quan trọng của hệ thống như node heartbeatsleader election cấp độ thành phần (component-level).

Node heartbeats

  • Kubernetes sử dụng API Lease để giao tiếp kubelet node heartbeats với API server của Kubernetes.

  • Đối với mỗi Node, có một Lease object có tên tương ứng trong namespace kube-node-lease.

  • Mỗi heartbeat của kubelet là một yêu cầu cập nhật đến Lease object này, cập nhật trường spec.renewTime cho Lease.

  • Control plane của Kubernetes sử dụng dấu thời gian của trường này để xác định tính sẵn sàng của Node.

Lưu ý: Xem chi tiết Node Lease objects để biết thêm thông tin.

Leader election

  • Kubernetes sử dụng Leases để đảm bảo chỉ có một instance của một thành phần đang chạy tại bất kỳ thời điểm nào. Điều này được sử dụng bởi các thành phần control plane như kube-controller-managerkube-scheduler trong các cấu hình HA.

  • Ví dụ, trong cấu hình HA, chỉ một instance của thành phần này nên hoạt động trong khi các instance khác ở chế độ chờ.

API server identity

Trạng thái tính năng: Kubernetes v1.26 [beta]
  • Bắt đầu từ Kubernetes v1.26, mỗi kube-apiserver sử dụng API Lease để công bố danh tính của mình cho phần còn lại của hệ thống.

  • Điều này cung cấp một cơ chế để các clients phát hiện có bao nhiêu instance của kube-apiserver đang vận hành control plane của Kubernetes.

  • Bạn có thể kiểm tra Leases do mỗi kube-apiserver sở hữu bằng cách kiểm tra các đối tượng lease trong namespace kube-system với tên kube-apiserver- hoặc sử dụng label selector apiserver.kubernetes.io/identity=kube-apise..:

kubectl -n kube-system get lease -l apiserver.kubernetes.io/identity=kube-apiserver
  • Mã hash SHA256 trong tên lease được tạo dựa trên hostname của OS như được thấy bởi API server đó.

  • Mỗi kube-apiserver nên được cấu hình để sử dụng hostname duy nhất trong cluster. Các instance mới của kube-apiserver sử dụng cùng hostname sẽ tiếp quản các Leases hiện có sử dụng holder identity mới, thay vì tạo ra các Lease objects mới.

  • Bạn có thể kiểm tra hostname được sử dụng bởi kube-apiserver bằng cách kiểm tra giá trị của label kubernetes.io/hostname:

kubectl -n kube-system get lease apiserver-07a5ea9b9b072c4a5f3d1c3702 -o yaml
  • Các leases đã hết hạn từ các kube-apiserver không còn tồn tại sẽ được garbage collected bởi các kube-apiserver mới sau 1 giờ.

  • Bạn có thể tắt các leases cho danh tính API server bằng cách tắt tính năng APIServerIdentity feature gate.

Workloads

  • Workloads của bạn có thể tự định nghĩa cách sử dụng Leases của riêng nó.

  • Ví dụ, bạn có thể chạy một custom controller mà một thành viên chính hoặc leader thực hiện các hoạt động mà các đồng nghiệp không làm. Bạn định nghĩa một Lease để các bản sao của controller có thể chọn hoặc bầu chọn một leader, sử dụng API của Kubernetes để điều phối.

  • Nếu bạn sử dụng Lease, nên định nghĩa một tên cho Lease rõ ràng liên kết với sản phẩm hoặc thành phần. Ví dụ: nếu bạn có một thành phần tên là Example Foo, sử dụng một Lease tên là example-foo.

  • Nếu một cluster operator hoặc người dùng khác có thể triển khai nhiều instance của một thành phần, chọn một tiền tố tên và chọn một cơ chế (như hash của tên Deployment) để tránh xung đột tên cho các Leases.

  • Bạn có thể sử dụng một phương pháp khác miễn là đạt được kết quả tương tự: các sản phẩm phần mềm khác nhau không xung đột với nhau.

Cloud Controller Manager

Kubernetes components

Tổng quan về Cloud Controller Manager

  • Cloud infrastructure technologies cho phép chạy Kubernetes trên public, private, và hybrid clouds.

  • Cloud-controller-manager là một thành phần control plane của Kubernetes, tích hợp logic điều khiển đặc thù của cloud.

  • Nó cho phép kết nối cluster của bạn vào API của nhà cung cấp cloud, tách biệt các thành phần tương tác với nền tảng cloud khỏi các thành phần chỉ tương tác với cluster.

  • Việc tách biệt logic tương tác này giúp các nhà cung cấp cloud phát hành các tính năng với tốc độ khác nhau so với dự án Kubernetes chính.

Thiết kế

  • Cloud-controller-manager chạy trong control plane như một tập hợp các tiến trình được sao chép (thường là các container trong Pods).

  • Mỗi cloud-controller-manager triển khai nhiều controllers trong một tiến trình duy nhất.

Lưu ý: Bạn cũng có thể chạy cloud-controller-manager như một Kubernetes addon thay vì là một phần của control plane.

Các chức năng của Cloud Controller Manager

Node Controller
  • Cập nhật Node objects khi các server mới được tạo trong cơ sở hạ tầng cloud.

  • Thực hiện các chức năng:

    • Cập nhật Node object với identifier duy nhất của server từ API của nhà cung cấp cloud.

    • Ghi chú và gắn nhãn Node object với thông tin cụ thể của cloud.

    • Lấy hostname và địa chỉ mạng của node.

    • Kiểm tra sức khỏe của node và xoá Node object khỏi cluster nếu node bị xóa khỏi cloud.

Một số nhà cung cấp cloud chia thành phần này thành node controllernode lifecycle controller riêng biệt.

Route Controller
  • Cấu hình các route trong cloud để các containers trên các nodes khác nhau trong Kubernetes cluster có thể giao tiếp với nhau.

  • Tùy thuộc vào nhà cung cấp cloud, route controller có thể phân bổ các blocks địa chỉ IP cho mạng Pod.

Service Controller
  • Tích hợp với các thành phần hạ tầng cloud như managed load balancers, địa chỉ IP, network packet filtering, và kiểm tra sức khỏe target.

  • Service controller tương tác với API của nhà cung cấp cloud để thiết lập load balancers và các thành phần hạ tầng khác khi bạn khai báo một Service resource yêu cầu chúng.

Authorization

Node Controller
  • Chỉ làm việc với Node objects, yêu cầu quyền truy cập đầy đủ để đọc và sửa đổi Node objects.
v1/Node:
  - get
  - list
  - create
  - update
  - patch
  - watch
  - delete
Route Controller
  • Nghe sự kiện tạo Node object và cấu hình routes phù hợp, yêu cầu quyền Get Node objects.
v1/Node:
  - get
Service Controller
  • Giám sát các sự kiện tạo, cập nhật, và xóa Service objects và cấu hình Endpoints cho các Services đó.

  • Yêu cầu quyền list và watch Services, cập nhật Services yêu cầu quyền patch và update.

  • Thiết lập Endpoints resources cho Services yêu cầu quyền create, list, get, watch, và update.

v1/Service:
  - list
  - get
  - watch
  - patch
  - update
Khác
  • Cần quyền truy cập để tạo Event objects và ServiceAccounts để đảm bảo hoạt động bảo mật.
v1/Event:
  - create
  - patch
  - update

v1/ServiceAccount:
  - create
RBAC ClusterRole cho Cloud Controller Manager
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

cgroup v2

  • Control groups (cgroups) trên Linux giới hạn tài nguyên được phân bổ cho các tiến trình.

  • Kubeletcontainer runtime cần tương tác với cgroups để thực thi quản lý tài nguyên cho pods và containers, bao gồm các yêu cầu và giới hạn về CPU/memory cho workloads containerized.

cgroup v2

  • cgroup v2 là phiên bản tiếp theo của API cgroup trên Linux, cung cấp hệ thống kiểm soát hợp nhất với khả năng quản lý tài nguyên được nâng cao.

  • cgroup v2 có nhiều cải tiến so với cgroup v1 như:

    • Thiết kế hệ thống phân cấp hợp nhất trong API.

    • Phân cấp dưới cây an toàn hơn cho containers.

    • Các tính năng mới như Pressure Stall Information.

    • Quản lý và cô lập tài nguyên nâng cao qua nhiều loại tài nguyên khác nhau.

Một số tính năng của Kubernetes chỉ sử dụng cgroup v2 để quản lý và cô lập tài nguyên nâng cao. Ví dụ, tính năng MemoryQoS cải thiện chất lượng dịch vụ bộ nhớ và dựa vào các nguyên thủy của cgroup v2.

Sử dụng cgroup v2

Cách tốt nhất để sử dụng cgroup v2 là sử dụng một bản phân phối Linux kích hoạt và sử dụng cgroup v2 mặc định.

Yêu cầu
  • Bản phân phối OS hỗ trợ cgroup v2.

  • Phiên bản Linux Kernel từ 5.8 trở lên.

  • Container runtime hỗ trợ cgroup v2, ví dụ:

    • containerd v1.4 và sau đó.

    • cri-o v1.20 và sau đó.

  • Kubelet và container runtime được cấu hình để sử dụng systemd cgroup driver.

Hỗ trợ cgroup v2 trên các bản phân phối Linux

Một số bản phân phối Linux sử dụng cgroup v2 mặc định:

  • Container Optimized OS (từ M97).

  • Ubuntu (từ 21.10, 22.04+ được khuyến nghị).

  • Debian GNU/Linux (từ Debian 11 bullseye).

  • Fedora (từ 31).

  • Arch Linux (từ tháng 4 năm 2021).

  • RHEL và các bản phân phối giống RHEL (từ 9).

Kiểm tra phiên bản cgroup
  • Để kiểm tra phiên bản cgroup trên hệ thống của bạn, chạy lệnh:
stat -fc %T /sys/fs/cgroup/
  • Đầu ra là cgroup2fs cho cgroup v2.

  • Đầu ra là tmpfs cho cgroup v1.

Chuyển đổi sang cgroup v2
  • Để chuyển đổi sang cgroup v2, đảm bảo rằng bạn đáp ứng các yêu cầu, sau đó nâng cấp lên phiên bản kernel kích hoạt cgroup v2 mặc định.

  • Kubelet tự động phát hiện hệ điều hành đang chạy trên cgroup v2 và hoạt động tương ứng mà không cần cấu hình thêm.

  • Nếu có bất kỳ ứng dụng nào truy cập trực tiếp vào hệ thống tệp cgroup, chúng cần được cập nhật để hỗ trợ cgroup v2.

Ví dụ, các agent giám sát và bảo mật của bên thứ ba có thể phụ thuộc vào hệ thống tệp cgroup. Cập nhật các agent này lên phiên bản hỗ trợ cgroup v2.

Các ứng dụng Java nên sử dụng các phiên bản hỗ trợ cgroup v2 đầy đủ:

  • OpenJDK / HotSpot: jdk8u372, 11.0.16, 15 và sau đó.

  • IBM Semeru Runtimes: 8.0.382.0, 11.0.20.0, 17.0.8.0, và sau đó.

  • IBM Java: 8.0.8.6 và sau đó.

Nếu bạn đang sử dụng gói uber-go/automaxprocs, đảm bảo rằng phiên bản bạn sử dụng là v1.5.1 hoặc cao hơn.

Container Runtime Interface (CRI)

Tổng quan về CRI

  • Container Runtime Interface (CRI) là giao diện plugin cho phép kubelet sử dụng nhiều container runtimes khác nhau mà không cần biên dịch lại các thành phần cluster.

  • Cần có một container runtime hoạt động trên mỗi Node trong cluster để kubelet có thể khởi chạy Pods và containers của chúng.

API của CRI

  • Kubelet hoạt động như một client khi kết nối với container runtime thông qua gRPC.

  • Các endpoint của dịch vụ runtime và image phải có sẵn trong container runtime và có thể được cấu hình riêng trong kubelet bằng cách sử dụng các command line flags --image-service-endpoint.

Kubernetes v1.30

  • Kubelet ưa thích sử dụng CRI v1. Nếu container runtime không hỗ trợ CRI v1, kubelet sẽ cố gắng đàm phán với bất kỳ phiên bản cũ nào được hỗ trợ.

  • Kubelet v1.30 cũng có thể đàm phán với CRI v1alpha2, nhưng phiên bản này được coi là lỗi thời. Nếu kubelet không thể đàm phán với bất kỳ phiên bản CRI nào được hỗ trợ, nó sẽ không đăng ký như một node.

Nâng cấp

  • Khi nâng cấp Kubernetes, kubelet cố gắng tự động chọn phiên bản CRI mới nhất khi khởi động lại thành phần.

  • Nếu thất bại, kubelet sẽ quay lại như đã đề cập ở trên.

  • Nếu cần thực hiện gRPC re-dial vì container runtime đã được nâng cấp, container runtime cũng phải hỗ trợ phiên bản ban đầu được chọn hoặc việc re-dial dự kiến sẽ thất bại. Điều này yêu cầu khởi động lại kubelet.

Garbage Collection

Giới thiệu về Garbage Collection

Garbage collection là thuật ngữ chung cho các cơ chế mà Kubernetes sử dụng để dọn dẹp các tài nguyên trong cluster. Điều này bao gồm việc dọn dẹp các tài nguyên như:

  • Pods đã kết thúc.

  • Jobs đã hoàn thành.

  • Các objects không có owner references.

  • Containers và container images không sử dụng.

  • PersistentVolumes được cung cấp động với chính sách reclaim của StorageClass là Delete.

  • CertificateSigningRequests (CSRs) cũ hoặc hết hạn.

  • Nodes bị xóa trong các trường hợp sau:

    • Trên đám mây khi cluster sử dụng cloud controller manager.

    • On-premises khi cluster sử dụng addon tương tự cloud controller manager.

  • Node Lease objects.

Chủ sở hữu và phụ thuộc

Nhiều objects trong Kubernetes liên kết với nhau thông qua owner references. Các owner references cho biết control plane các đối tượng nào phụ thuộc vào đối tượng khác. Kubernetes sử dụng owner references để cung cấp cho control plane và các API clients khác cơ hội để dọn dẹp các tài nguyên liên quan trước khi xóa một object. Kubernetes quản lý owner references tự động trong hầu hết các trường hợp.

Ownership khác với cơ chế labels và selectors mà một số tài nguyên cũng sử dụng. Ví dụ: một Service tạo các EndpointSlice objects, Service sử dụng labels để control plane xác định các EndpointSlice objects được sử dụng cho Service đó. Mỗi EndpointSlice được quản lý thay mặt cho một Service cũng có một owner reference.

Lưu ý: Các owner references giữa namespace khác nhau bị cấm theo thiết kế. Các phụ thuộc trong namespace có thể chỉ định chủ sở hữu ở cấp cluster hoặc cùng namespace. Một chủ sở hữu trong namespace phải tồn tại trong cùng namespace với phụ thuộc. Nếu không, owner reference được coi là không tồn tại và phụ thuộc sẽ bị xóa sau khi tất cả chủ sở hữu được xác minh là không tồn tại.

Cascading deletion

Kubernetes kiểm tra và xóa các objects không còn owner references, như các pods còn lại khi bạn xóa một ReplicaSet. Khi bạn xóa một object, bạn có thể kiểm soát việc Kubernetes tự động xóa các phụ thuộc của object đó, quá trình này gọi là cascading deletion. Có hai loại cascading deletion:

  1. Foreground cascading deletion

  2. Background cascading deletion

Bạn cũng có thể kiểm soát cách và khi nào garbage collection xóa các tài nguyên có owner references bằng cách sử dụng Kubernetes finalizers.

Foreground cascading deletion

Trong foreground cascading deletion, object chủ sở hữu bạn đang xóa trước tiên vào trạng thái deletion in progress. Trong trạng thái này:

  • API server của Kubernetes đặt trường metadata.deletionTimestamp của object vào thời gian object được đánh dấu để xóa.

  • API server cũng đặt trường metadata.finalizers thành foregroundDeletion.

  • Object vẫn hiển thị qua API Kubernetes cho đến khi quá trình xóa hoàn tất.

Sau khi object chủ sở hữu vào trạng thái deletion in progress, controller xóa các đối tượng phụ thuộc. Sau khi xóa tất cả các đối tượng phụ thuộc, controller xóa object chủ sở hữu. Tại thời điểm này, object không còn hiển thị trong API Kubernetes.

Trong quá trình foreground cascading deletion, chỉ các đối tượng phụ thuộc có trường ownerReference.blockOwnerDeletion=true mới chặn việc xóa chủ sở hữu.

Background cascading deletion

Trong background cascading deletion, API server của Kubernetes xóa object chủ sở hữu ngay lập tức và controller dọn dẹp các đối tượng phụ thuộc trong nền. Mặc định, Kubernetes sử dụng background cascading deletion trừ khi bạn thủ công sử dụng foreground deletion hoặc chọn orphan các đối tượng phụ thuộc.

Orphaned dependents

Khi Kubernetes xóa một object chủ sở hữu, các đối tượng phụ thuộc còn lại được gọi là orphan objects. Mặc định, Kubernetes xóa các đối tượng phụ thuộc. Để ghi đè hành vi này, xem Delete owner objects and orphan dependents.

Garbage collection cho containers và images không sử dụng

Kubelet thực hiện garbage collection trên các images không sử dụng mỗi hai phút và trên các containers không sử dụng mỗi phút. Bạn nên tránh sử dụng các công cụ garbage collection bên ngoài, vì chúng có thể phá vỡ hành vi của kubelet và xóa các containers mà lẽ ra phải tồn tại.

Để cấu hình các tùy chọn cho garbage collection containers và images không sử dụng, tinh chỉnh kubelet bằng cách sử dụng tệp cấu hình và thay đổi các tham số liên quan đến garbage collection sử dụng KubeletConfiguration resource type.

Vòng đời container image

Kubernetes quản lý vòng đời của tất cả các images thông qua image manager, là một phần của kubelet, với sự hợp tác của cadvisor. Kubelet xem xét các giới hạn sử dụng đĩa sau khi thực hiện các quyết định garbage collection:

  • HighThresholdPercent

  • LowThresholdPercent

Sử dụng đĩa trên giá trị HighThresholdPercent cấu hình kích hoạt garbage collection, xóa các images theo thứ tự dựa trên lần cuối cùng chúng được sử dụng, bắt đầu từ cái cũ nhất. Kubelet xóa các images cho đến khi sử dụng đĩa đạt giá trị LowThresholdPercent.

Garbage collection cho container images không sử dụng

  • Bạn có thể chỉ định thời gian tối đa mà một image cục bộ không được sử dụng, bất kể sử dụng đĩa.

  • Cấu hình này là một thiết lập kubelet mà bạn cấu hình cho mỗi node.

  • Để cấu hình thiết lập, bật ImageMaximumGCAge feature gate cho kubelet và đặt giá trị cho trường ImageMaximumGCAge trong tệp cấu hình kubelet.

Ví dụ: bạn có thể đặt trường cấu hình thành 3d12h, nghĩa là 3 ngày và 12 giờ.

Lưu ý: Tính năng này không theo dõi việc sử dụng image qua các lần khởi động lại kubelet. Nếu kubelet khởi động lại, tuổi của image được theo dõi bị đặt lại, khiến kubelet chờ toàn bộ thời gian ImageMaximumGCAge trước khi đủ điều kiện cho garbage collection dựa trên tuổi image.

Container garbage collection

Kubelet thực hiện garbage collection trên các containers không sử dụng dựa trên các biến sau mà bạn có thể định nghĩa:

  • MinAge: độ tuổi tối thiểu tại đó kubelet có thể garbage collect một container. Vô hiệu hóa bằng cách đặt thành 0.

  • MaxPerPodContainer: số lượng tối đa containers chết mỗi Pod có thể có. Vô hiệu hóa bằng cách đặt ít hơn 0.

  • MaxContainers: số lượng tối đa containers chết toàn cầu mà cluster có thể có. Vô hiệu hóa bằng cách đặt ít hơn 0.

Ngoài các biến này, kubelet garbage collect các containers không xác định và đã bị xóa, thường bắt đầu với cái cũ nhất.

Lưu ý: Kubelet chỉ garbage collect các containers mà nó quản lý.

Cấu hình garbage collection

Bạn có thể tinh chỉnh garbage collection của các tài nguyên bằng cách cấu hình các tùy chọn cụ thể cho các controllers quản lý các tài nguyên đó. Các trang sau chỉ cho bạn cách cấu hình garbage collection:

Mixed Version Proxy

Tổng quan về Mixed Version Proxy

  • Mixed Version Proxy là một tính năng alpha trong Kubernetes 1.30 cho phép một API Server proxy các yêu cầu tài nguyên đến các peer API servers khác. Điều này hữu ích khi có nhiều API servers chạy các phiên bản Kubernetes khác nhau trong cùng một cluster, ví dụ, trong quá trình nâng cấp dài hạn.

  • Tính năng này giúp quản trị viên cấu hình các clusters có độ khả dụng cao và nâng cấp an toàn hơn, bằng cách điều hướng các yêu cầu tài nguyên đến đúng kube-apiserver, ngăn người dùng gặp lỗi 404 không mong muốn trong quá trình nâng cấp.

Kích hoạt Mixed Version Proxy

Đảm bảo rằng UnknownVersionInteroperabilityProxy feature gate được kích hoạt khi bạn khởi động API Server:

kube-apiserver \
--feature-gates=UnknownVersionInteroperabilityProxy=true \
--peer-ca-file=<path to kube-apiserver CA cert> \
--proxy-client-cert-file=<path to aggregator proxy cert> \
--proxy-client-key-file=<path to aggregator proxy key> \
--requestheader-client-ca-file=<path to aggregator CA cert> \
--requestheader-allowed-names=<valid Common Names to verify proxy client cert against> \
--peer-advertise-ip=`IP của kube-apiserver này dùng để proxy yêu cầu` \
--peer-advertise-port=`port của kube-apiserver này dùng để proxy yêu cầu`

Proxy transport và xác thực giữa các API servers

  • Kube-apiserver nguồn sử dụng các flags --proxy-client-cert-file--proxy-client-key-file hiện có để trình bày danh tính sẽ được xác minh bởi peer (kube-apiserver đích). Kube-apiserver đích xác minh kết nối peer dựa trên cấu hình bạn chỉ định bằng --requestheader-client-ca-file.

  • Để xác thực chứng chỉ dịch vụ của server đích, cấu hình một bundle chứng chỉ của authority bằng cách chỉ định flag --peer-ca-file cho kube-apiserver nguồn.

Cấu hình kết nối peer API server

Để đặt vị trí mạng của kube-apiserver mà peers sẽ sử dụng để proxy yêu cầu, sử dụng các flags --peer-advertise-ip--peer-advertise-port hoặc chỉ định các trường này trong tệp cấu hình API server. Nếu không đặt các flags này, peers sẽ sử dụng giá trị từ --advertise-address hoặc --bind-address. Nếu các giá trị này cũng không được đặt, giao diện mặc định của host sẽ được sử dụng.

Mixed version proxying

Khi kích hoạt mixed version proxying, lớp aggregation tải một bộ lọc đặc biệt với các chức năng sau:

  • Khi một yêu cầu tài nguyên đến một API server không thể phục vụ API đó (vì nó ở phiên bản trước khi API được giới thiệu hoặc API bị tắt), API server sẽ cố gắng gửi yêu cầu đến một peer API server có thể phục vụ API được yêu cầu. Nó thực hiện bằng cách xác định các nhóm API / phiên bản / tài nguyên mà server cục bộ không nhận diện được và cố gắng proxy các yêu cầu đó đến một peer API server có thể xử lý yêu cầu.

  • Nếu peer API server không phản hồi, API server nguồn trả về lỗi 503 ("Service Unavailable").

How it works under the hood

  • Khi một API Server nhận yêu cầu tài nguyên, nó đầu tiên kiểm tra các API servers có thể phục vụ tài nguyên được yêu cầu. Việc kiểm tra này sử dụng StorageVersion API nội bộ.

    • Nếu tài nguyên được biết đến bởi API server nhận yêu cầu (ví dụ, GET /api/v1/pods/some-pod), yêu cầu được xử lý nội bộ.

    • Nếu không tìm thấy đối tượng StorageVersion nội bộ cho tài nguyên được yêu cầu (ví dụ, GET /my-api/v1/my-resource) và APIService được cấu hình để proxy đến một extension API server, proxying xảy ra theo luồng thông thường cho các extension APIs.

    • Nếu tìm thấy đối tượng StorageVersion nội bộ hợp lệ cho tài nguyên được yêu cầu (ví dụ, GET /batch/v1/jobs) và API server đang xử lý yêu cầu (handling API server) đã tắt batch API, thì handling API server tìm các peer API servers phục vụ nhóm API / phiên bản / tài nguyên liên quan (api/v1/batch trong trường hợp này) bằng cách sử dụng thông tin trong đối tượng StorageVersion đã lấy. Handling API server sau đó proxy yêu cầu đến một trong các kube-apiserver peer phù hợp nhận diện tài nguyên được yêu cầu.

      • Nếu không biết peer nào cho nhóm API / phiên bản / tài nguyên đó, handling API server chuyển yêu cầu đến chuỗi xử lý của nó và cuối cùng trả về lỗi 404 ("Not Found").

      • Nếu handling API server đã xác định và chọn một peer API server, nhưng peer đó không phản hồi (do các vấn đề như sự cố kết nối mạng, hoặc data race giữa yêu cầu được nhận và controller đăng ký thông tin peer vào control plane), thì handling API server trả về lỗi 503 ("Service Unavailable").

Bài tập

  1. Cài đặt Minikube (môi trường Kubernetes cục bộ) và triển khai ứng dụng "Hello World" cơ bản.

  2. Thử nghiệm mở rộng quy mô ứng dụng.

  3. Khám phá bảng điều khiển Kubernetes để trực quan cluster

Giải bài tập

Bài 1

Cài đặt Minikube:

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

Cài đặt docker:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo systemctl start docker

Cài đặt kubectl:

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

kubectl version --client

Khởi động minikube:

minikube start

Lưu ý: Nếu như bị lỗi, vì minikube không được phép khởi động với quyền root của docker thì bạn hãy khởi động non root hoặc --force (không được recommend, tuy nhiên nếu bạn muốn thì câu lệnh sẽ là minikube start --driver=docker --force)

Tạo ứng dụng đơn giản:

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Hello World</title>
</head>
<body>
  <h1>Hello World</h1>
</body>
</html>

Dockerfile:

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html

Build Docker image:

docker build -t hello-world-app .

Tạo deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello-world
        image: hello-world-app
        ports:
        - containerPort: 80

Triển khai Deployment:

kubectl apply -f deployment.yaml

Kiểm tra:

kubectl get deployments
kubectl get pods

Tạo service để truy cập ứng dụng service.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-world-service
spec:
  type: NodePort
  selector:
    app: hello-world
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30007

Triển khai service:

kubectl apply -f service.yaml

Kiểm tra service:

kubectl get services

Lấy địa chỉ IP của app:

minikube ip

Thử truy cập app:

curl http://<Minikube_IP>:30007

Bài 2 & Bài 3

Kiểm tra số lượng nodes hiện tại:

kubectl get deployments

Scale lên 5:

kubectl scale deployment hello-world --replicas=5

Kiểm tra:

kubectl get pods

Bật dashboard addons:

minikube addons enable dashboard

Mở dashboard:

minikube dashboard

Từ đây, có thể khám phá, kiểm tra các cấu phần của cluster trong dashboard.