Skip to content

[GCP ACE Masterclass] Toàn tập về Google Kubernetes Engine (GKE): Từ Kiến trúc đến Vận hành Production

Chào mừng bạn đến với cẩm nang toàn diện về Google Kubernetes Engine. Trong thế giới cloud-native, Kubernetes đã trở thành một tiêu chuẩn de-facto để điều phối container. Và GKE không chỉ là "một phiên bản Kubernetes" – nó là phiên bản được tôi luyện, bảo mật, và tự động hóa bởi chính những kỹ sư đã tạo ra Kubernetes tại Google.

Tài liệu này sẽ là người bạn đồng hành, giúp bạn đi từ việc hiểu các khái niệm cơ bản đến việc tự tin thiết kế, triển khai và vận hành các ứng dụng có tính sẵn sàng cao, khả năng mở rộng và an toàn trên GKE.


MỤC LỤC

Phần 1: Nền tảng và Kiến trúc Cốt lõi

Phần 2: Các Khái niệm Kubernetes Thiết yếu trong GKE

Phần 3: Mở rộng và Tính sẵn sàng Cao (Scaling & High Availability)

Phần 4: Quản lý Lưu trữ cho Ứng dụng Stateful

Phần 5: Mạng Nâng cao (Advanced Networking)

Phần 6: Bảo mật Toàn diện (The Hardened Cluster)

Phần 7: Vận hành, Giám sát và CI/CD (Day 2 Operations)

Phần 8: Lời kết của Chuyên gia và Tầm nhìn Tương lai


Phần 1: Nền tảng và Kiến trúc Cốt lõi

1.1. Tại sao lại là Containers và Kubernetes? Vấn đề cần giải quyết

Hãy quay lại quá khứ. Trước đây, chúng ta triển khai ứng dụng trên các máy chủ vật lý, rồi đến máy ảo (VMs). Vấn đề của VM là:

  • Lãng phí tài nguyên: Mỗi VM chạy một hệ điều hành đầy đủ, tiêu tốn CPU và RAM đáng kể.
  • Chậm khởi động: Khởi động một VM mất vài phút.
  • Vấn đề "It works on my machine": Môi trường dev, staging, prod không bao giờ giống hệt nhau, gây ra lỗi khó lường.

Containers (ví dụ: Docker) ra đời để giải quyết điều này.

  • Đóng gói tất cả trong một: Một container đóng gói mã nguồn ứng dụng và tất cả các thư viện, dependencies của nó vào một gói duy nhất, có thể chạy được.
  • Nhẹ và nhanh: Container chia sẻ nhân (kernel) của HĐH máy chủ, không cần HĐH riêng, khởi động trong vài giây.
  • Tính nhất quán: Container chạy y hệt nhau ở mọi nơi: trên laptop của developer, trên server test, và trên production.

Nhưng khi bạn có hàng trăm, hàng nghìn container, một vấn đề mới nảy sinh: Làm thế nào để quản lý, kết nối, mở rộng và tự phục hồi chúng? Đó là lúc Kubernetes (K8s) xuất hiện. Kubernetes là một hệ thống điều phối container (container orchestrator), nó là "bộ não" tự động hóa mọi thứ.

1.2. GKE là gì? Sức mạnh của Kubernetes "Được quản lý"

Bạn có thể tự cài đặt Kubernetes trên các máy ảo (GCE VMs). Nhưng bạn sẽ phải tự mình:

  • Cài đặt và cấu hình control plane (etcd, API server...).
  • Quản lý việc nâng cấp phiên bản Kubernetes.
  • Đảm bảo control plane có tính sẵn sàng cao.
  • Xử lý các bản vá bảo mật cho control plane.

Google Kubernetes Engine (GKE) loại bỏ toàn bộ gánh nặng này. GKE là một dịch vụ Kubernetes được quản lý (managed Kubernetes).

  • Google quản lý Control Plane: Google đảm bảo control plane của bạn luôn hoạt động, được vá lỗi, nâng cấp và có tính sẵn sàng cao. Bạn không bao giờ phải SSH vào một master node.
  • Tích hợp sâu với GCP: GKE tích hợp liền mạch với các dịch vụ GCP khác như IAM, VPC, Cloud Logging, Cloud Monitoring, Load Balancing...
  • Tự động hóa nâng cao: GKE cung cấp các tính năng tự động hóa độc quyền như Autopilot, nâng cấp node tự động, tự sửa chữa node...

Góc nhìn Chuyên gia: Sử dụng GKE không phải là "outsourcing" Kubernetes. Đó là quyết định chiến lược để team của bạn tập trung vào việc xây dựng ứng dụng thay vì quản lý hạ tầng Kubernetes phức tạp. Chi phí bạn trả cho GKE là chi phí cho sự ổn định, an toàn và thời gian quý báu của đội ngũ kỹ sư.

1.3. Giải phẫu một Cụm GKE: Control Plane vs. Data Plane

Một cụm (cluster) GKE được chia làm hai phần chính:

  • Control Plane (Mặt phẳng Điều khiển):

    • Là bộ não của cụm, được Google quản lý hoàn toàn.
    • Thành phần chính:
      • API Server: Cổng giao tiếp duy nhất để tương tác với cụm (qua kubectl hoặc các client khác).
      • etcd: Một kho lưu trữ key-value bền vững, lưu trữ toàn bộ trạng thái của cụm (bạn có bao nhiêu Pods, Deployments, Services...). Đây là trái tim của control plane.
      • Scheduler: Quyết định xem một Pod mới sẽ được chạy trên Node nào dựa trên tài nguyên yêu cầu và các ràng buộc khác.
      • Controller Manager: Chạy các vòng lặp điều khiển để đưa trạng thái hiện tại của cụm về trạng thái mong muốn (ví dụ: đảm bảo một Deployment luôn có đủ số lượng replicas).
  • Data Plane (Mặt phẳng Dữ liệu):

    • Là nơi ứng dụng của bạn thực sự chạy, bao gồm các máy ảo mà bạn quản lý và trả tiền.
    • Thành phần chính:
      • Nodes: Các máy ảo Google Compute Engine (VMs) làm việc.
      • Kubelet: Một agent chạy trên mỗi Node, giao tiếp với API Server để nhận lệnh và báo cáo trạng thái của Node và các Pod trên đó.
      • Kube-proxy: Một proxy mạng chạy trên mỗi Node, quản lý các rule mạng để cho phép giao tiếp giữa các Pod và Services.
      • Container Runtime: Phần mềm chịu trách nhiệm chạy container (ví dụ: containerd).

1.4. Chế độ Vận hành: Autopilot vs. Standard – Cuộc chiến Cân não

Đây là quyết định quan trọng đầu tiên khi tạo một cụm GKE.

Tiêu chíGKE StandardGKE Autopilot
Mô hình quản lýBạn quản lý và trả tiền cho các Nodes (VMs).Bạn không thấy/quản lý Nodes. Bạn chỉ định nghĩa Pods và trả tiền cho tài nguyên (CPU, RAM) mà Pods của bạn yêu cầu.
Mức độ kiểm soátToàn quyền kiểm soát. Bạn có thể chọn loại máy, HĐH, SSH vào node, chạy DaemonSets...Kiểm soát hạn chế. Google quản lý Nodes cho bạn. Không thể SSH, không thể tùy chỉnh sâu HĐH.
Tối ưu hóa chi phíBạn chịu trách nhiệm. Cần kỹ thuật "bin packing" (xếp Pod vào Node) để tránh lãng phí.Google chịu trách nhiệm. Google tự động "bin pack" Pods của bạn một cách hiệu quả nhất. Tiềm năng tiết kiệm cao nếu workload biến động.
Bảo mậtBạn chia sẻ trách nhiệm bảo mật cho Nodes.Bảo mật cao hơn. Bề mặt tấn công nhỏ hơn vì Google quản lý Nodes theo các best practice.
Phù hợp choWorkload cần tùy chỉnh sâu về HĐH, chạy các agent đặc biệt, hoặc khi bạn muốn kiểm soát tối đa việc bin packing.Hầu hết các workload stateless, các ứng dụng web, API. Lý tưởng để bắt đầu và cho các team muốn tập trung 100% vào ứng dụng.

Lời khuyên của Mentor: Hãy bắt đầu với Autopilot. Nó thực thi rất nhiều best practice về bảo mật và hiệu quả chi phí ngay từ đầu. Chỉ chuyển sang Standard nếu bạn gặp một yêu cầu cụ thể mà Autopilot không thể đáp ứng (ví dụ: cần một kernel module đặc biệt).


Phần 2: Các Khái niệm Kubernetes Thiết yếu trong GKE

Phần này sẽ đi kèm các ví dụ YAML, ngôn ngữ của Kubernetes.

2.1. Triển khai Ứng dụng Đầu tiên: Pods, Deployments, và ReplicaSets

  • Pod: Là đơn vị nhỏ nhất có thể triển khai trong Kubernetes. Nó là một lớp trừu tượng bao bọc một hoặc nhiều container. Các container trong cùng một Pod chia sẻ chung network namespace và có thể giao tiếp qua localhost.
    • Analogy: Một Pod giống như một "căn hộ", các container bên trong là các "phòng".
  • ReplicaSet: Đảm bảo rằng một số lượng bản sao (replicas) của một Pod luôn chạy. Nếu một Pod chết, ReplicaSet sẽ tạo ra một cái mới để thay thế.
  • Deployment: Là một lớp trừu tượng cấp cao hơn, quản lý các ReplicaSet. Deployments cho phép bạn thực hiện các chiến lược cập nhật ứng dụng một cách an toàn như Rolling Update (cập nhật từ từ từng Pod một) hoặc Blue/Green.
    • Analogy: Nếu Pod là căn hộ, Deployment là "chủ nhà" quyết định có bao nhiêu căn hộ được cho thuê và làm thế nào để sửa chữa, nâng cấp chúng.

Ví dụ: Triển khai một web server Nginx Tạo file nginx-deployment.yaml:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3 # Yêu cầu 3 bản sao của ứng dụng luôn chạy
  selector:
    matchLabels:
      app: nginx
  template: # Đây là "khuôn mẫu" cho các Pod sẽ được tạo
    metadata:
      labels:
        app: nginx # Gán nhãn cho Pod, để selector có thể tìm thấy
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6 # Image sẽ được kéo từ Docker Hub
        ports:
        - containerPort: 80

Triển khai bằng kubectl:

bash
kubectl apply -f nginx-deployment.yaml

2.2. Kết nối và Phơi bày Ứng dụng: Services (ClusterIP, NodePort, LoadBalancer)

Bây giờ bạn có 3 Pod Nginx đang chạy. Nhưng các Pod là tạm thời, địa chỉ IP của chúng có thể thay đổi. Làm thế nào để các ứng dụng khác (hoặc người dùng bên ngoài) có thể truy cập chúng một cách ổn định? Đó là nhiệm vụ của Service.

Một Service cung cấp một điểm cuối (endpoint) mạng ổn định cho một nhóm các Pod.

  • ClusterIP (Mặc định):

    • Tạo ra một địa chỉ IP nội bộ bên trong cụm.
    • Chỉ có thể truy cập từ bên trong cụm.
    • Usecase: Cho phép một "frontend" Pod giao tiếp với một "backend" Pod.
  • NodePort:

    • Mở một cổng tĩnh (static port) trên tất cả các Node trong cụm.
    • Lưu lượng đến [Node_IP]:[Node_Port] sẽ được chuyển đến Service.
    • Usecase: Dùng để test nhanh hoặc khi bạn cần phơi bày một dịch vụ TCP/UDP không phải HTTP. Không nên dùng cho production web traffic.
  • LoadBalancer:

    • Đây là cách chuẩn để phơi bày dịch vụ ra Internet trên GKE.
    • Tự động tạo ra một Google Cloud Load Balancer (Network Load Balancer - L4) và trỏ nó đến Service.
    • Cung cấp một địa chỉ IP public duy nhất.

Ví dụ: Phơi bày Nginx Deployment ra ngoài Tạo file nginx-service.yaml:

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer # Yêu cầu một Google Cloud Load Balancer
  selector:
    app: nginx # Tìm tất cả các Pod có nhãn này để gửi lưu lượng đến
  ports:
  - protocol: TCP
    port: 80 # Cổng mà Service lắng nghe
    targetPort: 80 # Cổng mà container trong Pod đang lắng nghe

Triển khai:

bash
kubectl apply -f nginx-service.yaml
# Chờ vài phút, sau đó chạy lệnh sau để lấy IP public
kubectl get service nginx-service

2.3. Định tuyến Thông minh với Ingress: Cổng vào cho Thế giới Bên ngoài

Sử dụng Service type LoadBalancer sẽ tạo ra một Load Balancer cho mỗi Service. Điều này rất tốn kém và khó quản lý. Ingress là giải pháp tốt hơn cho các ứng dụng HTTP(S).

  • Ingress là một đối tượng K8s hoạt động như một "bộ định tuyến thông minh" ở lớp 7 (HTTP).
  • Nó cho phép bạn định nghĩa các quy tắc định tuyến dựa trên host (ví dụ: api.example.com, shop.example.com) hoặc path (ví dụ: /api, /images).
  • Một Ingress duy nhất, được hỗ trợ bởi một Google Cloud HTTP(S) Load Balancer duy nhất, có thể định tuyến lưu lượng đến nhiều Service khác nhau.

Ví dụ: Định tuyến cho 2 dịch vụ

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    # Các annotation này rất quan trọng để cấu hình Cloud Load Balancer
    kubernetes.io/ingress.class: "gce"
    # Tự động tạo và quản lý chứng chỉ SSL
    networking.gke.io/managed-certificates: "my-ssl-cert" 
spec:
  rules:
  - host: shop.mydomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: shop-frontend-service # Gửi đến service của shop
            port:
              number: 80
  - host: api.mydomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-backend-service # Gửi đến service của API
            port:
              number: 8080

Góc nhìn Chuyên gia: Luôn luôn sử dụng Ingress thay vì Service LoadBalancer để phơi bày các ứng dụng HTTP(S). Nó rẻ hơn, mạnh mẽ hơn, và tích hợp với các tính năng cao cấp của Google Cloud như Managed SSL Certificates, Cloud Armor (WAF), và Cloud CDN.

2.4. Quản lý Cấu hình và Dữ liệu Nhạy cảm: ConfigMaps và Secrets

Không bao giờ hardcode chuỗi kết nối database hay API key vào trong Docker image. Đó là một cơn ác mộng về bảo mật và vận hành.

  • ConfigMap: Dùng để lưu trữ dữ liệu cấu hình không nhạy cảm (ví dụ: URL của một dịch vụ, cờ tính năng...).
  • Secret: Dùng để lưu trữ dữ liệu nhạy cảm (API keys, mật khẩu, chứng chỉ TLS...). Dữ liệu trong Secret được lưu trữ dưới dạng base64 encoded (không phải mã hóa, chỉ là mã hóa để truyền tải) và có thể được tích hợp với các hệ thống mã hóa bên ngoài.

Cả hai đều có thể được đưa vào Pod dưới dạng biến môi trường (environment variables) hoặc file được mount vào volume.

Ví dụ: Đưa API key vào Pod

  1. Tạo một Secret:
bash
kubectl create secret generic api-keys --from-literal=my-api-key='SUPER_SECRET_VALUE_123'
  1. Tham chiếu Secret trong Deployment:
yaml
# ... trong phần template.spec.containers ...
      containers:
      - name: my-app
        image: my-app:1.0
        env:
        - name: EXTERNAL_API_KEY # Tên biến môi trường trong container
          valueFrom:
            secretKeyRef:
              name: api-keys # Tên của Secret
              key: my-api-key # Key bên trong Secret

Bây giờ, ứng dụng của bạn có thể đọc API key từ biến môi trường EXTERNAL_API_KEY.


Chắc chắn rồi. Cảm ơn bạn đã phản hồi. Chúng ta sẽ điều chỉnh lại nhịp độ, tập trung sâu hơn vào việc giải thích các khái niệm cơ bản nhất một cách trực quan, dễ hiểu cho người mới bắt đầu, trước khi đi vào các chủ đề phức tạp. Tôi sẽ dùng nhiều ví dụ so sánh đời thực hơn để làm rõ các khái niệm trừu tượng.


[Tiếp tục Tài liệu]

Phần 2: Các Khái niệm Kubernetes Thiết yếu trong GKE (Phiên bản Giải thích cho Người mới bắt đầu)

Hãy tưởng tượng bạn đang xây dựng một thành phố lego khổng lồ. Kubernetes chính là bản quy hoạch và các quy tắc của thành phố đó, còn GKE là công ty xây dựng chuyên nghiệp giúp bạn thực thi bản quy hoạch này. Phần này sẽ giải thích các "vật liệu xây dựng" cơ bản nhất.

2.1. Triển khai Ứng dụng Đầu tiên: Pods, Deployments và ReplicaSets

2.1.1. Pod: Ngôi nhà cho Ứng dụng của bạn

  • Khái niệm: Trong thế giới thực, ứng dụng của bạn không thể "trôi nổi" tự do. Nó cần một nơi để "sống". Trong Kubernetes, nơi đó được gọi là Pod. Pod là đơn vị cơ bản và nhỏ nhất bạn có thể tạo.
  • Ví dụ so sánh: Hãy nghĩ về một Pod như một căn hộ nhỏ trong một tòa chung cư. Căn hộ này có thể chỉ có một "phòng" (một container ứng dụng chính, ví dụ container chạy web server của bạn), nhưng cũng có thể có thêm các "phòng" phụ trợ (các container phụ, ví dụ một container chuyên thu thập log từ container chính).
  • Điểm mấu chốt:
    • Tất cả các container trong cùng một Pod (cùng một căn hộ) dùng chung một địa chỉ IP (cùng một địa chỉ nhà) và có thể "nói chuyện" với nhau rất dễ dàng, như thể chúng đang ở trên cùng một máy tính.
    • Pods là phù du (ephemeral). Giống như một căn hộ thuê, nó có thể bị "dọn đi" (xóa) và thay thế bất cứ lúc nào (ví dụ khi Node chứa nó bị hỏng). Bạn không bao giờ nên phụ thuộc vào sự tồn tại của một Pod cụ thể.

2.1.2. ReplicaSet: Người Quản lý Đảm bảo Số lượng

  • Vấn đề: Nếu Pod là phù du, điều gì xảy ra khi Pod chứa website của bạn đột nhiên "biến mất"? Website của bạn sẽ sập! Chúng ta cần một ai đó đảm bảo rằng luôn có đủ số lượng Pod chạy.
  • Khái niệm: ReplicaSet chính là người quản lý đó. Nhiệm vụ duy nhất của nó là đảm bảo rằng một số lượng bản sao (replicas) của một Pod luôn luôn tồn tại.
  • Ví dụ so sánh: Hãy tưởng tượng bạn là chủ một chuỗi cửa hàng cà phê và bạn yêu cầu người quản lý (ReplicaSet) rằng: "Tôi muốn lúc nào cũng phải có đúng 3 cửa hàng cà phê (Pods) mở cửa". Nếu một cửa hàng vì lý do nào đó phải đóng cửa (Pod bị lỗi), người quản lý sẽ ngay lập tức tìm một mặt bằng mới và mở một cửa hàng y hệt để thay thế.

2.1.3. Deployment: Vị Kiến trúc sư Trưởng

  • Vấn đề: ReplicaSet rất giỏi trong việc duy trì số lượng, nhưng nó khá "cơ bản". Nó không biết làm thế nào để cập nhật ứng dụng của bạn lên phiên bản mới một cách an toàn. Nếu bạn chỉ xóa ReplicaSet cũ và tạo cái mới, website sẽ bị gián đoạn.
  • Khái niệm: Deployment là một khái niệm cấp cao hơn, là vị "Kiến trúc sư trưởng". Nó quản lý các ReplicaSet. Khi bạn muốn cập nhật ứng dụng, bạn chỉ cần nói với Deployment: "Đây là phiên bản mới của ứng dụng". Deployment sẽ tự động thực hiện một Rolling Update (Cập nhật Cuốn chiếu) một cách thông minh.
  • Cách Rolling Update hoạt động:
    1. Deployment tạo ra một ReplicaSet mới cho phiên bản mới của ứng dụng, nhưng ban đầu với số lượng Pod là 0.
    2. Nó từ từ tăng số lượng Pod mới lên 1, đồng thời giảm số lượng Pod cũ đi 1.
    3. Nó chờ cho Pod mới sẵn sàng hoạt động rồi mới tiếp tục quá trình.
    4. Quá trình này lặp lại cho đến khi tất cả các Pod cũ đã được thay thế bằng Pod mới.
    • Kết quả: Ứng dụng của bạn được cập nhật mà không có bất kỳ thời gian chết (zero downtime) nào. Người dùng cuối không hề nhận ra sự thay đổi.
  • Mối quan hệ: Bạn (Developer) -> Tương tác với Deployment -> Deployment quản lý ReplicaSet -> ReplicaSet quản lý Pods. Trong 99% trường hợp, bạn sẽ chỉ làm việc trực tiếp với Deployment.

Tổng kết bằng YAML: Hãy xem lại file nginx-deployment.yaml.

yaml
apiVersion: apps/v1
kind: Deployment # 1. Bạn nói bạn muốn một Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3 # 2. Bạn yêu cầu Deployment đảm bảo luôn có 3 bản sao
  selector:
    matchLabels:
      app: nginx # 4. Deployment sẽ tìm các Pod có nhãn này để quản lý
  template: # 3. Đây là "bản thiết kế" cho các Pod
    metadata:
      labels:
        app: nginx # Pod được sinh ra sẽ có nhãn này
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6 # Chạy container từ image Nginx
        ports:
        - containerPort: 80

Khi bạn apply file này, Deployment sẽ tạo ra một ReplicaSet, và ReplicaSet đó sẽ tạo ra 3 Pods dựa trên bản thiết kế (template) bạn cung cấp.

2.2. Kết nối và Phơi bày Ứng dụng: Services

  • Vấn đề: Bây giờ bạn có một nhóm các Pod đang chạy. Nhưng mỗi Pod có một địa chỉ IP riêng, và các IP này có thể thay đổi liên tục. Nếu một ứng dụng "frontend" muốn nói chuyện với một ứng dụng "backend", nó không thể dùng IP của một Pod cụ thể được. Nó cần một địa chỉ ổn định.
  • Khái niệm: Service là một "tấm biển chỉ dẫn" cố định cho một nhóm các Pod. Nó có một địa chỉ IP và một tên DNS không đổi. Bất kỳ ai muốn nói chuyện với nhóm Pod đó, chỉ cần gửi yêu cầu đến địa chỉ của Service. Service sẽ tự động chuyển tiếp yêu cầu đến một trong những Pod đang khỏe mạnh.
  • Ví dụ so sánh: Hãy nghĩ về số tổng đài của một công ty pizza (ví dụ: 1900-1111). Bạn không cần biết số điện thoại cá nhân của từng nhân viên giao hàng (Pods). Bạn chỉ cần gọi đến số tổng đài (Service). Tổng đài sẽ tự động kết nối cuộc gọi của bạn đến một nhân viên đang rảnh rỗi. Dù một nhân viên nghỉ việc và có người mới thay thế (Pod chết và được tạo lại), số tổng đài vẫn không đổi.

Các loại "Tấm biển chỉ dẫn" (Types of Services)

  1. ClusterIP:

    • Loại biển: Một tấm biển chỉ đường bên trong khu phố của bạn.
    • Mô tả: Tạo ra một địa chỉ IP chỉ có thể được truy cập từ bên trong cụm Kubernetes.
    • Khi nào dùng: Dùng cho giao tiếp nội bộ. Ví dụ, Pod "web frontend" gọi đến Service của Pod "user database". Người đi đường bên ngoài khu phố không thể thấy tấm biển này.
  2. NodePort:

    • Loại biển: Dán một tờ thông báo lên cửa nhà của tất cả các tòa nhà trong khu phố.
    • Mô tả: Mở một cổng (port) cụ thể trên mỗi máy chủ (Node) trong cụm. Bất kỳ ai từ bên ngoài có thể truy cập vào [Địa_chỉ_IP_của_bất_kỳ_Node_nào]:[Cổng_đó].
    • Khi nào dùng: Rất hiếm khi dùng trong production. Chủ yếu để các developer test nhanh, vì nó không linh hoạt và khó quản lý bảo mật.
  3. LoadBalancer:

    • Loại biển: Dựng một tấm biển quảng cáo khổng lồ, có đèn neon, ngay trên đường cao tốc dẫn vào thành phố.
    • Mô tả: Đây là cách chuẩn để "mời gọi" traffic từ Internet vào. Khi bạn tạo Service loại này trên GKE, GKE sẽ tự động tạo ra một Google Cloud Load Balancer thật ở bên ngoài, với một địa chỉ IP public duy nhất, và trỏ nó vào cụm của bạn.
    • Khi nào dùng: Khi bạn muốn ứng dụng của mình được truy cập công khai từ Internet.

Tổng kết bằng YAML: File nginx-service.yaml

yaml
apiVersion: v1
kind: Service # 1. Bạn nói bạn muốn một Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer # 2. Bạn muốn loại "biển quảng cáo" to nhất
  selector:
    app: nginx # 3. Service này sẽ chỉ đường cho tất cả các Pod có nhãn "app: nginx"
  ports:
  - protocol: TCP
    port: 80       # 4. Biển quảng cáo sẽ nhận khách ở cổng 80
    targetPort: 80 # 5. Và sẽ dẫn khách đến các căn hộ (Pod) cũng ở cổng 80

2.3. Định tuyến Thông minh với Ingress: Lễ tân của Tòa nhà

  • Vấn đề: Dùng Service LoadBalancer giống như thuê một người gác cửa riêng cho mỗi cửa hàng trong một trung tâm thương mại. Rất lãng phí! Sẽ tốt hơn nếu có một quầy lễ tân chung ở cửa chính, và lễ tân sẽ chỉ dẫn khách hàng đến đúng cửa hàng họ cần.
  • Khái niệm: Ingress chính là "quầy lễ tân" đó. Nó là một bộ quy tắc định tuyến thông minh cho lưu lượng truy cập HTTP và HTTPS. Thay vì tạo nhiều Load Balancer, bạn chỉ cần một Load Balancer duy nhất ở cửa (do Ingress tạo ra), và Ingress sẽ xem xét yêu cầu của khách hàng (dựa trên tên miền hoặc đường dẫn URL) để quyết định gửi họ đến Service nào.
  • Ví dụ so sánh:
    • Một khách hàng đến và hỏi: "Cho tôi đến cửa hàng giày (shoes.mydomain.com)". Lễ tân Ingress sẽ chỉ họ đến shoe-service.
    • Khách hàng khác hỏi: "Cho tôi đến quầy đồ ăn (food.mydomain.com)". Lễ tân Ingress sẽ chỉ họ đến food-service.
    • Và một khách hàng khác nữa hỏi: "Tôi muốn đến khu vực thanh toán (mydomain.com/checkout)". Lễ tân Ingress sẽ chỉ họ đến payment-service.
  • Điểm mấu chốt: Một Ingress duy nhất, một địa chỉ IP public duy nhất, quản lý lưu lượng cho toàn bộ ứng dụng của bạn. Đây là cách làm hiệu quả và tiết kiệm chi phí nhất.

2.4. Quản lý Cấu hình và Dữ liệu Nhạy cảm: ConfigMaps và Secrets

  • Vấn đề: Ứng dụng của bạn cần thông tin để hoạt động, ví dụ như địa chỉ của cơ sở dữ liệu, hoặc một API key để gọi dịch vụ bên ngoài. Bạn không thể "viết chết" những thông tin này vào trong mã nguồn hoặc Docker image. Nếu làm vậy, mỗi lần thay đổi cấu hình, bạn phải build lại toàn bộ ứng dụng. Rất tệ!

  • Khái niệm: Kubernetes cung cấp hai "hộp chứa" đặc biệt để tách rời cấu hình ra khỏi ứng dụng:

    1. ConfigMap: Là chiếc hộp dành cho các thông tin không bí mật.
      • Ví dụ so sánh: Giống như một tấm bảng thông báo chung trong văn phòng. Trên đó ghi những thông tin ai cũng có thể biết, như: "Địa chỉ máy in: printer.office.local", "Chế độ hoạt động: production".
    2. Secret: Là chiếc hộp được khóa kỹ, dành cho các thông tin bí mật, nhạy cảm.
      • Ví dụ so sánh: Giống như một két sắt cá nhân. Trong đó chứa mật khẩu Wifi, chìa khóa vào cửa, mật khẩu tài khoản ngân hàng... Chỉ những người được cấp phép mới có thể mở nó. Dù bên ngoài nó chỉ là một chiếc hộp, nhưng bạn biết bên trong là đồ quan trọng.
  • Cách sử dụng: Sau khi tạo ConfigMap hoặc Secret, bạn có thể "gắn" chúng vào Pod của mình. Ứng dụng bên trong Pod có thể đọc các thông tin này như thể chúng là các file trong ổ đĩa, hoặc là các biến môi trường của hệ điều hành. Bằng cách này, ứng dụng và cấu hình hoàn toàn độc lập với nhau.


Chúng ta vừa đi qua những khối xây dựng cơ bản nhất. Hãy chắc chắn rằng bạn hiểu rõ:

  • Pod là nơi ứng dụng sống.
  • Deployment là người xây dựng và nâng cấp nhà cho ứng dụng.
  • Service là biển chỉ đường đến ngôi nhà đó.
  • Ingress là lễ tân thông minh cho cả tòa nhà.
  • ConfigMap/Secret là những chiếc hộp chứa thông tin cần thiết cho ứng dụng hoạt động.

Phần 3: Mở rộng và Tính sẵn sàng Cao (Scaling & High Availability)

Ứng dụng của bạn đã chạy. Nhưng điều gì xảy ra khi có một chiến dịch marketing lớn và lượng truy cập tăng đột biến? Hoặc khi một máy chủ vật lý trong trung tâm dữ liệu của Google gặp sự cố? Phần này sẽ dạy bạn cách làm cho ứng dụng của mình vừa "co giãn" linh hoạt theo nhu cầu, vừa "vững chãi" trước mọi sự cố.

3.1. Tự động Co giãn Ứng dụng: Horizontal Pod Autoscaler (HPA)

  • Vấn đề: Trong ví dụ trước, chúng ta đã "ra lệnh" cho Deployment chạy đúng 3 Pod Nginx. Nhưng nếu 3 Pod đó bị quá tải (ví dụ, CPU của cả 3 đều lên 90%)? Website của bạn sẽ chậm đi hoặc thậm chí sập. Việc theo dõi thủ công và tăng số lượng Pod là không khả thi.
  • Khái niệm: Horizontal Pod Autoscaler (HPA) là "Người quản lý Năng suất" của Kubernetes. Bạn giao cho HPA một mục tiêu, ví dụ: "Hãy giữ mức sử dụng CPU trung bình của tất cả các Pod Nginx dưới 60%".
    • Khi HPA thấy CPU trung bình vượt quá 60%, nó sẽ tự động ra lệnh cho Deployment: "Tăng thêm Pod đi!".
    • Khi lưu lượng truy cập giảm và CPU trung bình xuống thấp (ví dụ 20%), nó sẽ lại ra lệnh: "Giảm bớt Pod đi để tiết kiệm chi phí!".
  • Ví dụ so sánh: Hãy tưởng tượng một siêu thị. HPA chính là người quản lý ca.
    • Mục tiêu: "Không để hàng chờ thanh toán dài quá 5 người."
    • Hành động: Khi người quản lý thấy hàng chờ ở các quầy bắt đầu dài ra (tải CPU tăng), ông ta sẽ gọi thêm nhân viên thu ngân (tăng số lượng Pod) ra mở thêm quầy. Khi siêu thị vắng khách, ông ta lại cho nhân viên nghỉ bớt để tiết kiệm chi phí nhân sự.
  • Điểm mấu chốt: HPA giúp ứng dụng của bạn tự động thích ứng với tải thực tế, đảm bảo hiệu năng cho người dùng và tối ưu hóa chi phí cho bạn. Nó co giãn "bề ngang" (horizontal), tức là tăng/giảm số lượng bản sao (Pods).

Ví dụ YAML cho HPA:

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment # 1. HPA này sẽ theo dõi và điều khiển Deployment tên là "nginx-deployment"
  minReplicas: 3 # 2. Dù vắng khách đến mấy cũng phải có ít nhất 3 Pod
  maxReplicas: 10 # 3. Dù đông khách đến mấy cũng chỉ được có tối đa 10 Pod (để kiểm soát chi phí)
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60 # 4. Mục tiêu: giữ CPU trung bình ở mức 60%

3.2. Tự động Co giãn Hạ tầng: Cluster Autoscaler (CA)

  • Vấn đề: HPA đã tạo ra rất nhiều Pod mới, nhưng điều gì xảy ra nếu tất cả các máy chủ (Nodes) trong cụm của bạn đã "chật cứng" và không còn chỗ để đặt thêm Pod mới? Các Pod mới này sẽ bị kẹt ở trạng thái "Pending" (Chờ xử lý).
  • Khái niệm: Cluster Autoscaler (CA) là "Người quản lý Xây dựng". Nó không quan tâm đến từng Pod, nó quan tâm đến toàn bộ hạ tầng (các Node). Nhiệm vụ của nó là đảm bảo luôn có đủ "không gian" (tài nguyên Node) cho tất cả các Pod.
    • Khi CA thấy có các Pod bị "Pending" vì thiếu tài nguyên, nó sẽ tự động yêu cầu GKE: "Thêm một Node mới vào cụm!".
    • Ngược lại, khi nó thấy một Node nào đó đang chạy rất ít tải trong một thời gian dài và các Pod trên đó có thể được di chuyển sang các Node khác, nó sẽ di chuyển các Pod đó và xóa Node đi để tiết kiệm tiền.
  • Ví dụ so sánh: Quay lại ví dụ siêu thị. Cluster Autoscaler là giám đốc mặt bằng.
    • Vấn đề: Quản lý ca (HPA) muốn gọi thêm 10 nhân viên thu ngân, nhưng siêu thị chỉ có 8 quầy thanh toán. 2 nhân viên mới không có chỗ làm việc (Pod is Pending).
    • Hành động: Giám đốc mặt bằng (CA) thấy vậy liền gọi đội xây dựng đến và xây thêm 2 quầy thanh toán mới (thêm Node mới). Khi siêu thị vắng khách và có nhiều quầy trống, ông ta lại cho dỡ bỏ bớt các quầy không dùng đến để giảm chi phí thuê mặt bằng.
  • Mối quan hệ: HPA tạo ra nhu cầu về Pod. CA đáp ứng nhu cầu đó bằng cách cung cấp Node. Cả hai làm việc cùng nhau để tạo ra một hệ thống co giãn hoàn toàn tự động từ ứng dụng đến hạ tầng.

Góc nhìn Chuyên gia: Trên GKE Standard, bạn phải bật Cluster Autoscaler. Trên GKE Autopilot, tính năng này đã được tích hợp sẵn và là một phần cốt lõi của dịch vụ – bạn không cần phải cấu hình nó. Đây là một lợi thế rất lớn của Autopilot.

3.3. Node Pools: Phân tách Workload và Tối ưu Chi phí

  • Vấn đề: Không phải tất cả các ứng dụng đều giống nhau. Có ứng dụng cần rất nhiều CPU (ví dụ: xử lý video), có ứng dụng lại cần rất nhiều RAM (ví dụ: cơ sở dữ liệu trong bộ nhớ), và có những ứng dụng có thể chạy trên các máy chủ giá rẻ, không ổn định. Nếu bạn chỉ có một loại Node duy nhất cho tất cả, bạn sẽ rất lãng phí.
  • Khái niệm: Node Pool là một nhóm các Node có cùng một cấu hình (cùng loại máy, cùng kích thước ổ đĩa...). Bạn có thể tạo nhiều Node Pool khác nhau trong cùng một cụm GKE.
  • Ví dụ so sánh: Một bệnh viện (GKE Cluster) có nhiều khu vực (Node Pools) khác nhau:
    • Khu phòng khám chung (Standard Node Pool): Dùng các máy móc tiêu chuẩn, cho các bệnh thông thường (ứng dụng web, API).
    • Khu phẫu thuật công nghệ cao (Compute-Optimized Node Pool): Trang bị các máy móc tối tân, cần CPU cực mạnh (workload tính toán chuyên sâu).
    • Khu lưu trữ hồ sơ (Memory-Optimized Node Pool): Có các kho chứa khổng lồ, cần nhiều RAM (database in-memory).
    • Khu khám chữa bệnh từ thiện (Spot VM Node Pool): Dùng các thiết bị được tài trợ, giá rẻ nhưng có thể bị đòi lại bất cứ lúc nào (các tác vụ batch có thể bị gián đoạn).
  • Cách hoạt động: Bạn có thể "ra lệnh" cho Kubernetes rằng: "Các Pod của ứng dụng xử lý video chỉ được chạy trên các Node thuộc compute-optimized-pool". Điều này được thực hiện bằng một cơ chế gọi là Taints and Tolerations hoặc Node Affinity.

3.4. Kiến trúc Chống chịu Lỗi: Cụm Zonal vs. Regional

  • Vấn đề: Điều gì xảy ra nếu toàn bộ trung tâm dữ liệu (Zone) của Google nơi cụm GKE của bạn đang chạy gặp sự cố (ví dụ: mất điện, lũ lụt)? Nếu tất cả Node của bạn đều ở đó, toàn bộ ứng dụng sẽ sập.
  • Khái niệm: GKE cho bạn hai lựa chọn để xây dựng khả năng chống chịu lỗi ở cấp độ hạ tầng:
    1. Cụm Zonal (Zonal Cluster):
      • Kiến trúc: Control Plane và tất cả các Nodes đều nằm trong một Zone duy nhất (ví dụ: us-central1-a).
      • Ưu điểm: Đơn giản, chi phí thấp hơn một chút.
      • Nhược điểm: Không có khả năng chống chịu lỗi ở cấp độ Zone. Nếu Zone us-central1-a gặp sự cố, bạn sẽ mất toàn bộ cụm.
    2. Cụm Regional (Regional Cluster):
      • Kiến trúc: Control Plane được sao chép ra nhiều Zone. Các Node của bạn cũng được phân bổ trên nhiều Zone trong cùng một Region (ví dụ: các Node được trải đều ra us-central1-a, us-central1-b, và us-central1-c).
      • Ưu điểm: Tính sẵn sàng cực cao. Nếu một Zone (ví dụ us-central1-a) hoàn toàn sập, Control Plane vẫn hoạt động và các Node ở các Zone còn lại vẫn tiếp tục chạy ứng dụng của bạn. GKE sẽ tự động chuyển các Pod từ Zone bị lỗi sang các Zone còn lại.
      • Nhược điểm: Chi phí cao hơn một chút (do phải trả tiền cho việc sao chép Control Plane).

Lời khuyên của Mentor: Đối với bất kỳ ứng dụng production quan trọng nào, hãy LUÔN LUÔN sử dụng Cụm Regional. Chi phí chênh lệch là rất nhỏ so với thiệt hại kinh doanh khi ứng dụng của bạn ngừng hoạt động trong nhiều giờ. Cụm Zonal chỉ phù hợp cho môi trường dev/test hoặc các ứng dụng không quan trọng.


Phần 4: Quản lý Lưu trữ cho Ứng dụng Stateful

Đến giờ, chúng ta chủ yếu nói về các ứng dụng "stateless" (vô trạng thái) như web server. Chúng không lưu trữ dữ liệu quan trọng nào trên chính nó. Nhưng còn các ứng dụng "stateful" (có trạng thái) như cơ sở dữ liệu thì sao? Dữ liệu của chúng phải tồn tại bền vững, ngay cả khi Pod bị xóa và tạo lại.

4.1. Bộ ba Quyền lực về Lưu trữ: PV, PVC, và StorageClass

Đây là một trong những khái niệm trừu tượng nhất trong Kubernetes, nhưng rất quan trọng.

  • Ví dụ so sánh: Hãy tưởng tượng bạn cần một kho chứa đồ.

    1. PersistentVolume (PV): Là cái kho chứa thực sự, một không gian lưu trữ vật lý (ví dụ một ổ đĩa Google Persistent Disk 100GB). Thường thì người quản trị hạ tầng (Admin) sẽ tạo sẵn một loạt các kho với kích thước và loại khác nhau. Nó là một tài nguyên trong cụm.
    2. PersistentVolumeClaim (PVC):yêu cầu thuê kho của bạn (Developer). Bạn viết một tờ đơn: "Tôi cần thuê một kho 10GB, loại kho phải có tốc độ truy xuất nhanh". Bạn không quan tâm mình được giao cái kho cụ thể nào, chỉ cần nó đáp ứng yêu cầu. Nó là một yêu cầu tài nguyên từ một namespace.
    3. StorageClass:bảng giá và các loại hình dịch vụ cho thuê kho. Ví dụ: "Loại kho standard: 0.04$/GB/tháng, tốc độ thường. Loại kho premium-ssd: 0.17$/GB/tháng, tốc độ siêu nhanh".
  • Cách chúng hoạt động cùng nhau (Dynamic Provisioning - Cấp phát Động):

    1. Bạn (Developer) tạo một PVC (yêu cầu thuê kho), trong đó chỉ định bạn muốn thuê kho từ StorageClass premium-ssd với dung lượng 10GB.
    2. Kubernetes thấy yêu cầu của bạn. Nó nhìn vào StorageClass premium-ssd và biết rằng loại này tương ứng với ổ đĩa pd-ssd của Google Cloud.
    3. GKE (thông qua một "người môi giới" gọi là CSI driver) tự động gọi API của Google Cloud để tạo ra một ổ đĩa pd-ssd 10GB mới.
    4. Ổ đĩa mới này được đăng ký trong cụm dưới dạng một PV (cái kho thực sự).
    5. Kubernetes "khớp lệnh" (binds) cái PV vừa tạo này với cái PVC của bạn.
    6. Từ giờ, Pod của bạn có thể sử dụng PVC này, và dữ liệu sẽ được ghi vào ổ đĩa pd-ssd đó.
  • Tại sao lại phức tạp như vậy? Để tách biệt vai trò:

    • Admin chỉ cần định nghĩa các loại dịch vụ (StorageClass).
    • Developer chỉ cần yêu cầu tài nguyên (PVC) mà không cần biết chi tiết về hạ tầng lưu trữ bên dưới.

4.2. Tích hợp với Lưu trữ GCP: GKE Persistent Disk CSI Driver

  • Khái niệm: "Người môi giới" mà chúng ta nói ở trên có tên chính thức là Container Storage Interface (CSI) Driver. Đây là một cơ chế tiêu chuẩn để các hệ thống lưu trữ (như Google Cloud, AWS...) có thể "dạy" cho Kubernetes cách nói chuyện với chúng.
  • Trên GKE: GKE đã cài đặt sẵn Persistent Disk CSI Driver. Chính driver này lắng nghe các yêu cầu tạo PVC và tự động gọi API của Google Cloud để tạo/xóa các ổ đĩa Persistent Disk. Nhờ có nó mà cơ chế cấp phát động hoạt động một cách liền mạch.

4.3. Triển khai Ứng dụng Stateful: Đối tượng StatefulSet

  • Vấn đề: Đối với một cụm cơ sở dữ liệu (ví dụ: MySQL, Elasticsearch), các Pod không thể hoàn toàn giống nhau và thay thế cho nhau được. Mỗi Pod cần có:
    • Một định danh mạng ổn định (ví dụ: db-0, db-1, db-2).
    • Một không gian lưu trữ bền vững, riêng biệt, không bị dùng chung.
  • Khái niệm: StatefulSet là một đối tượng Kubernetes được thiết kế riêng cho các ứng dụng stateful. Nó là một "Deployment phiên bản nâng cao".
  • Các đặc điểm chính của StatefulSet:
    1. Định danh Ổn định (Stable, Unique Network Identifiers): Các Pod được tạo ra sẽ có tên theo thứ tự và không đổi: tên-statefulset-0, tên-statefulset-1... Dù Pod db-0 bị xóa và tạo lại, nó vẫn sẽ có tên là db-0.
    2. Lưu trữ Bền vững, Ổn định (Stable, Persistent Storage): Mỗi Pod trong StatefulSet sẽ được gắn với một PVC riêng. Pod db-0 sẽ luôn được gắn với PVC data-db-0.
    3. Triển khai và Co giãn theo Thứ tự (Ordered, Graceful Deployment and Scaling): Khi triển khai, nó sẽ tạo db-0 trước, chờ nó sẵn sàng rồi mới tạo db-1. Khi xóa, nó sẽ xóa db-2 trước, rồi đến db-1... Điều này rất quan trọng để duy trì sự ổn định của cụm database.

4.4. Sao lưu và Phục hồi: Giải pháp Backup for GKE

  • Vấn đề: Dữ liệu trong Persistent Disk đã bền vững, nhưng bạn vẫn cần sao lưu (backup) để phòng các trường hợp: lỗi do con người (xóa nhầm dữ liệu), thảm họa ở cấp độ Region, hoặc cần phục hồi lại một phiên bản cũ.
  • Khái niệm: Backup for GKE là một dịch vụ được quản lý của Google Cloud, cho phép bạn tự động hóa việc sao lưu và phục hồi cho các workload trên GKE.
  • Điểm khác biệt: Nó không chỉ sao lưu dữ liệu (nội dung của PV), mà còn sao lưu cả cấu hình của ứng dụng (các đối tượng Kubernetes như Deployments, Secrets, ConfigMaps...). Điều này cho phép bạn phục hồi toàn bộ trạng thái của một ứng dụng, chứ không chỉ dữ liệu thô, sang một cụm khác nếu cần.

Phần 5: Mạng Nâng cao (Advanced Networking)

Phần này sẽ khám phá cách chúng ta xây dựng các mạng lưới an toàn, hiệu quả và có thể quan sát được cho các ứng dụng microservices.

5.1. Nền tảng Mạng hiện đại: Cụm VPC-Native

  • Vấn đề: Trong các phiên bản GKE cũ, địa chỉ IP của các Pod là "ảo", chúng chỉ tồn tại bên trong một mạng overlay phức tạp bên trong cụm. Điều này gây khó khăn khi Pod cần giao tiếp với các dịch vụ GCP khác (như Cloud SQL) hoặc khi bạn cần thiết lập các quy tắc tường lửa chi tiết.
  • Khái niệm: Cụm VPC-Native là chế độ mạng hiện đại và là mặc định cho tất cả các cụm GKE mới. Trong chế độ này, địa chỉ IP của mỗi Pod là một địa chỉ IP thực từ mạng VPC (Virtual Private Cloud) của bạn.
  • Lợi ích:
    • Kết nối liền mạch: Pod có thể kết nối trực tiếp đến các dịchVPC.
    • Tường lửa dễ dàng: Bạn có thể tạo các quy tắc tường lửa của VPC áp dụng trực tiếp cho các Pod dựa trên dải IP hoặc tag.
    • Hiệu năng tốt hơn: Loại bỏ lớp mạng overlay, giúp giảm độ trễ.

Lời khuyên của Mentor: Luôn luôn sử dụng cụm VPC-Native. Đây là best practice không cần bàn cãi.

5.2. Tường lửa cho Microservices: Đối tượng NetworkPolicy

  • Vấn đề: Mặc định, trong một cụm Kubernetes, tất cả các Pod đều có thể giao tiếp với tất cả các Pod khác. Điều này giống như một văn phòng không có tường ngăn, ai cũng có thể nói chuyện với ai. Về mặt bảo mật, đây là một rủi ro. Nếu Pod frontend bị tấn công, kẻ tấn công có thể dễ dàng truy cập vào Pod database.
  • Khái niệm: NetworkPolicy là một "tường lửa ảo" bên trong Kubernetes. Nó cho phép bạn định nghĩa các quy tắc rất chi tiết về việc Pod nào được phép nói chuyện với Pod nào, trên cổng nào.
  • Cách hoạt động: NetworkPolicy hoạt động dựa trên các nhãn (labels). Bạn định nghĩa các chính sách như sau:
    • "Cho phép lưu lượng đến các Pod có nhãn app: database."
    • "Chỉ cho phép từ các Pod có nhãn app: backend."
    • "Và chỉ trên cổng TCP 6379."
  • Ví dụ so sánh: Quay lại văn phòng không tường. NetworkPolicy cho phép bạn dựng lên các "vách ngăn kính vô hình". Chỉ những người có thẻ ID (label) phù hợp mới có thể đi qua các vách ngăn này để nói chuyện với nhau. Team Marketing chỉ có thể nói chuyện với nhau, và chỉ có thể nói chuyện với team Sales qua một "cửa sổ" được chỉ định trước.

5.3. Service Mesh: Quan sát, Bảo mật và Quản lý Lưu lượng với Anthos Service Mesh (Istio)

  • Vấn đề: Khi bạn có hàng trăm microservices, việc quản lý chúng trở nên cực kỳ phức tạp. Làm thế nào để:
    • Biết được dịch vụ nào đang nói chuyện với dịch vụ nào?
    • Mã hóa toàn bộ lưu lượng giữa các dịch vụ?
    • Thực hiện các chiến lược triển khai phức tạp như A/B testing một cách an toàn?
  • Khái niệm: Service Mesh (lưới dịch vụ) là một lớp hạ tầng chuyên dụng được thêm vào ứng dụng của bạn để giải quyết các vấn đề trên. Anthos Service Mesh (ASM) của Google là một phiên bản được quản lý, dễ cài đặt của dự án mã nguồn mở nổi tiếng Istio.
  • Cách hoạt động: ASM tự động "tiêm" một container proxy thông minh (gọi là Envoy proxy) vào mỗi Pod của bạn. Proxy này sẽ chặn và quản lý toàn bộ lưu lượng mạng ra vào Pod.
  • Nó mang lại cho bạn "siêu năng lực" gì?
    • Quan sát (Observability): Tự động tạo ra các biểu đồ, sơ đồ chi tiết về luồng lưu lượng, đo lường độ trễ, tỷ lệ lỗi...
    • Bảo mật (Security): Tự động bật mTLS (mutual TLS), mã hóa và xác thực toàn bộ giao tiếp giữa các service, ngăn chặn các cuộc tấn công xen giữa.
    • Kiểm soát Lưu lượng (Traffic Control): Dễ dàng cấu hình việc chia lưu lượng (ví dụ: 90% traffic đến phiên bản cũ, 10% đến phiên bản mới để thử nghiệm), tự động thử lại nếu một dịch vụ bị lỗi (retries), hoặc ngắt kết nối tạm thời nếu một dịch vụ bị quá tải (circuit breaking).

5.4. Kết nối Toàn cầu: Multi-cluster Ingress và Multi-cluster Services

  • Vấn đề: Khi ứng dụng của bạn phục vụ người dùng toàn cầu, việc chạy một cụm GKE duy nhất ở Mỹ sẽ gây ra độ trễ lớn cho người dùng ở Châu Á. Bạn cần chạy nhiều cụm GKE ở các khu vực địa lý khác nhau. Làm thế nào để định tuyến người dùng đến cụm gần nhất?
  • Khái niệm:
    • Multi-cluster Ingress (MCI): Cho phép bạn sử dụng một Google Cloud Load Balancer Toàn cầu duy nhất với một địa chỉ IP public duy nhất để định tuyến lưu lượng đến các ứng dụng chạy trên nhiều cụm GKE khác nhau. Nó tự động hướng người dùng đến cụm có độ trễ thấp nhất.
    • Multi-cluster Services (MCS): Cho phép các dịch vụ chạy trong các cụm khác nhau có thể "khám phá" và giao tiếp với nhau như thể chúng đang ở trong cùng một cụm.

Phần 6: Bảo mật Toàn diện (The Hardened Cluster)

Bảo mật không phải là một tính năng, nó là một quy trình và một tư duy. Phần này sẽ hướng dẫn bạn cách xây dựng các lớp phòng thủ để bảo vệ cụm GKE của mình.

6.1. Hai Lớp Phòng thủ: Xác thực với IAM và Ủy quyền với RBAC

  • Vấn đề: Ai được phép truy cập vào cụm GKE và họ được phép làm gì? Đây là câu hỏi cơ bản nhất về bảo mật.
  • Khái niệm - Phân biệt rõ ràng:
    1. IAM (Identity and Access Management của Google Cloud):người gác cổng ở vòng ngoài. Nó trả lời câu hỏi: "Bạn là ai và bạn có được phép vào cổng thành Kubernetes không?". IAM xác thực danh tính của bạn (developer, service account) dựa trên tài khoản Google và quyết định xem bạn có quyền gke.clusters.getCredentials hay không. Nếu không có quyền IAM, bạn thậm chí không thể nói chuyện được với API Server của cụm.
    2. RBAC (Role-Based Access Control của Kubernetes):lễ tân và an ninh ở vòng trong. Sau khi IAM đã cho bạn vào cổng, RBAC sẽ quyết định: "Bên trong này, bạn được phép làm gì?". Bạn có được xem Pod không? Có được xóa Deployment không? Có được xem Secret không?
  • Cách hoạt động của RBAC:
    • Role/ClusterRole: Định nghĩa một tập hợp các quyền (ví dụ: "được xem Pod", "được liệt kê Deployment"). Role áp dụng cho một namespace, ClusterRole áp dụng cho toàn bộ cụm.
    • RoleBinding/ClusterRoleBinding: "Gắn" một Role cho một người dùng, một nhóm, hoặc một service account. Ví dụ: "Gắn Role pod-viewer cho người dùng alice@example.com".

Lời khuyên của Mentor: Luôn tuân thủ Nguyên tắc Đặc quyền Tối thiểu (Principle of Least Privilege). Chỉ cấp cho người dùng và dịch vụ những quyền hạn tối thiểu tuyệt đối cần thiết để họ hoàn thành công việc. Đừng bao giờ cấp quyền cluster-admin một cách bừa bãi.

6.2. Giao tiếp An toàn với Dịch vụ GCP: Workload Identity

  • Vấn đề: Pod của bạn cần truy cập Google Cloud Storage. Cách làm cũ và tệ là tạo một service account key (một file JSON), lưu nó vào Kubernetes Secret, và mount vào Pod. Điều này rất rủi ro: nếu Secret bị lộ, kẻ tấn công có toàn quyền của service account đó. Việc quản lý và xoay vòng các key này cũng là một cơn ác mộng.
  • Khái niệm: Workload Identity là cách làm hiện đại, an toàn và được khuyến nghị để các ứng dụng trên GKE truy cập các dịch vụ GCP khác.
  • Cách hoạt động (không cần key):
    1. Bạn tạo một mối quan hệ tin cậy giữa một Kubernetes Service Account (KSA - bên trong cụm) và một Google Service Account (GSA - bên ngoài cụm, thuộc IAM).
    2. Khi Pod của bạn (sử dụng KSA đó) cố gắng gọi một API của GCP, GKE Metadata Server sẽ chặn lại.
    3. Nó sẽ trao đổi một token của KSA để lấy một token truy cập ngắn hạn của GSA tương ứng.
    4. Pod của bạn sử dụng token ngắn hạn này để xác thực với API của GCP.
  • Lợi ích: Không có key tĩnh nào được lưu trữ. Toàn bộ quá trình là tự động, an toàn, và các token chỉ có hiệu lực trong thời gian ngắn.

6.3. Giám sát An ninh và Bảo mật Chuỗi Cung ứng: Security Posture và Binary Authorization

  • Security Posture Dashboard: Một trung tâm chỉ huy an ninh cho GKE. Nó tự động quét các cụm của bạn để tìm các vấn đề bảo mật phổ biến, các cấu hình sai lệch so với best practice của Google, và các lỗ hổng đã biết trong các workload đang chạy.
  • Binary Authorization: Một lớp phòng thủ cho chuỗi cung ứng phần mềm của bạn. Nó đảm bảo rằng chỉ những container image đã được tin tưởng và xác thực mới được phép chạy trên cụm GKE của bạn.
    • Cách hoạt động: Trong pipeline CI/CD, sau khi một image đã qua các bước kiểm tra (test, scan lỗ hổng), một "người ký" (Attestor) sẽ ký điện tử lên image đó. Binary Authorization sẽ được cấu hình để chỉ chấp nhận các image có chữ ký hợp lệ này.

6.4. Quản lý Secrets ở Quy mô Lớn: Tích hợp Google Secret Manager

  • Vấn đề: Kubernetes Secrets chỉ được mã hóa dạng base64, không thực sự an toàn khi lưu trữ trong etcd. Mặc dù GKE mã hóa etcd ở tầng đĩa, nhưng các tổ chức lớn cần một giải pháp quản lý secrets tập trung, có kiểm toán, và có chính sách xoay vòng.
  • Giải pháp: Tích hợp GKE với Google Secret Manager.
    • Lưu tất cả các secret nhạy cảm trong Secret Manager.
    • Sử dụng một công cụ như Secrets Store CSI Driver để tự động đồng bộ các secret từ Secret Manager vào trong cụm GKE và trình bày chúng cho Pod dưới dạng file hoặc biến môi trường.
    • Lợi ích: Một nguồn sự thật duy nhất cho secrets, quản lý tập trung, kiểm toán đầy đủ, và tích hợp với IAM để kiểm soát quyền truy cập.

Phần 7: Vận hành, Giám sát và CI/CD (Day 2 Operations)

Triển khai ứng dụng chỉ là bước đầu. Vận hành, giám sát, và tối ưu hóa nó mới là công việc hàng ngày.

7.1. Hiểu "Sức khỏe" của Cụm: Tích hợp Cloud Monitoring và Logging

  • GKE được "sinh ra" để làm việc với hệ sinh thái Cloud Operations (trước đây là Stackdriver). Khi tạo cụm, các agent thu thập log và metric đã được cài đặt sẵn trên các Node.
  • Cloud Logging: Tự động thu thập log từ:
    • Các thành phần hệ thống của GKE.
    • Stdout và stderr của tất cả các container của bạn.
    • Bạn có thể tìm kiếm, lọc, và tạo cảnh báo từ các log này.
  • Cloud Monitoring: Tự động thu thập một lượng lớn các metric từ:
    • Các Node (CPU, memory, disk, network...).
    • Các Pod và container.
    • Các đối tượng Kubernetes (số lượng replicas của Deployment...).
    • Bạn có thể tạo các Dashboard tùy chỉnh để trực quan hóa sức khỏe của hệ thống và thiết lập các Cảnh báo (Alerting) khi một chỉ số vượt ngưỡng (ví dụ: "cảnh báo nếu độ trễ của Ingress cao hơn 500ms").

7.2. Nâng cấp Không gián đoạn: Sức mạnh của Release Channels

  • Vấn đề: Kubernetes phát hành phiên bản mới khoảng 3 tháng một lần. Việc nâng cấp phiên bản cho Control Plane và các Node là một công việc phức tạp và rủi ro.
  • Giải pháp GKE: Release Channels (Kênh Phát hành). Thay vì tự chọn một phiên bản cụ thể, bạn đăng ký cụm của mình vào một kênh. Google sẽ tự động quản lý việc nâng cấp cho bạn một cách an toàn.
    • Rapid Channel: Nhận các phiên bản mới nhất, sớm nhất. Phù hợp để thử nghiệm.
    • Regular Channel (Khuyến nghị): Cân bằng giữa sự ổn định và các tính năng mới. Phù hợp cho hầu hết các môi trường production.
    • Stable Channel: Ưu tiên sự ổn định tối đa, nhận các phiên bản đã được tôi luyện và kiểm chứng kỹ lưỡng nhất.
  • Lợi ích: Biến một công việc vận hành đáng sợ thành một quy trình tự động, được quản lý, giảm thiểu rủi ro cho bạn.

7.3. Nghệ thuật Tối ưu Chi phí trên GKE

GKE rất mạnh mẽ, nhưng cũng có thể rất tốn kém nếu không được tối ưu.

  1. Sử dụng Autopilot: Đây là cách dễ nhất. Bạn chỉ trả tiền cho tài nguyên mà Pod yêu cầu, loại bỏ lãng phí do các Node chạy không tải.
  2. Sử dụng Spot Pods/VMs: Cho các workload có thể bị gián đoạn (batch jobs, test environments). Giúp tiết kiệm tới 91%. GKE Autopilot tích hợp sẵn Spot Pods, rất dễ sử dụng.
  3. Right-Sizing: Đặt requestslimits cho CPU/Memory của Pod một cách hợp lý. Đừng yêu cầu nhiều hơn những gì bạn thực sự cần. Sử dụng HPA để co giãn thay vì cấp phát thừa tài nguyên.
  4. Committed Use Discounts (CUDs): Nếu bạn có một lượng tài nguyên cơ bản luôn chạy ổn định, hãy mua CUDs cho GCE (cho GKE Standard) hoặc cho Compute (cho GKE Autopilot) để được giảm giá sâu khi cam kết sử dụng trong 1 hoặc 3 năm.
  5. Tắt các cụm không sử dụng: Tự động hóa việc xóa các cụm dev/test vào ban đêm hoặc cuối tuần.

7.4. Kiến trúc một Pipeline CI/CD Cloud-Native hoàn chỉnh

Đây là luồng công việc mà một team hiện đại sẽ sử dụng:

  1. Code: Developer đẩy code lên một nhánh trên Git Repository (ví dụ: GitHub, Cloud Source Repositories).
  2. Build & Test: Một trigger tự động kích hoạt Cloud Build.
    • Cloud Build chạy các unit test.
    • Nếu test thành công, nó build một Docker image mới.
    • Nó quét image để tìm lỗ hổng bảo mật.
    • Nó đẩy image đã được build vào Artifact Registry.
  3. Sign (Tùy chọn, cho bảo mật cao): Nếu dùng Binary Authorization, Cloud Build sẽ gọi một Attestor để ký lên image vừa được build.
  4. Deploy:
    • Cách đơn giản: Cloud Build có thể chạy lệnh kubectl apply -f ... để triển khai trực tiếp lên cụm GKE dev/staging.
    • Cách chuyên nghiệp: Cloud Build trigger một pipeline trên Cloud Deploy. Cloud Deploy là một dịch vụ quản lý việc phát hành liên tục. Nó sẽ quản lý quá trình quảng bá (promoting) một bản phát hành từ môi trường dev -> staging -> production, cho phép các bước phê duyệt thủ công nếu cần.

Phần 8: Lời kết của Chuyên gia và Tầm nhìn Tương lai

Chúng ta đã cùng nhau đi một hành trình dài, từ việc hiểu tại sao cần container cho đến việc thiết kế một pipeline CI/CD hoàn chỉnh cho các ứng dụng chạy trên một cụm GKE được bảo mật và có tính sẵn sàng cao.

Những điểm mấu chốt cần mang theo:

  • GKE là nền tảng, không phải là đích đến: Giá trị của GKE nằm ở việc nó giải phóng bạn khỏi gánh nặng quản lý hạ tầng, để bạn tập trung vào việc tạo ra các ứng dụng tuyệt vời.
  • Bắt đầu với Autopilot: Nó tích hợp sẵn rất nhiều best practice, giúp bạn đi đúng hướng ngay từ đầu.
  • IaC là bắt buộc: Quản lý các file YAML của Kubernetes bằng Git (GitOps) để có một hệ thống có thể lặp lại, kiểm toán và tự động hóa.
  • Bảo mật từ ngày đầu tiên: Áp dụng nguyên tắc đặc quyền tối thiểu, sử dụng Workload Identity, và suy nghĩ về các lớp phòng thủ.
  • Tự động hóa mọi thứ: Từ co giãn (HPA, CA) đến nâng cấp (Release Channels) và triển khai (CI/CD).

Tầm nhìn Tương lai: GKE và Kubernetes đang không ngừng phát triển. Xu hướng sẽ tiếp tục hướng tới sự đơn giản hóa và trừu tượng hóa. Các nền tảng như Google Cloud Run (được xây dựng trên Knative/GKE) đã cho thấy tương lai, nơi các developer thậm chí không cần biết đến Pod hay Deployment, họ chỉ cần quan tâm đến mã nguồn của mình. Trí tuệ nhân tạo cũng sẽ được tích hợp sâu hơn để tự động tối ưu hóa chi phí, hiệu năng và bảo mật một cách thông minh hơn nữa.

Nắm vững GKE không chỉ là học một công nghệ. Đó là học một cách tư duy mới về cách xây dựng, triển khai và vận hành phần mềm trong kỷ nguyên cloud-native. Chúc bạn thành công trên hành trình này