Sử dụng Istio Multicluster để "Burst" (Tăng đột biến) khối lượng công việc giữa các cụm

Sử dụng Istio Multicluster để "Burst" (tăng đột biến) khối lượng công việc giữa các cụm

Thông tin về lớp học lập trình này

subjectLần cập nhật gần đây nhất: thg 3 30, 2021
account_circleTác giả: Một nhân viên của Google

1. Chào mừng

Cảm ơn bạn đã tham gia lớp học lập trình Istio Multi Cloud Burst của Google.Lớp học lập trình này yêu cầu bạn có kinh nghiệm thực hành ở cấp độ mới bắt đầu với Kubernetes, Node và Go.

Những gì bạn cần

  • Tài khoản Google Cloud Platform (sử dụng tài khoản hiện có hoặc chúng tôi sẽ cung cấp tài khoản miễn phí)
  • Máy tính xách tay (cài đặt "kubectl", "gcloud", v.v.) hoặc bạn có thể sử dụng Google Cloud Shell.

Kiến thức bạn sẽ học được

  • Cách tạo cụm Kubernetes trên GKE
  • Cách cài đặt Istio trên cụm Kubernetes bằng Helm
  • Cách cài đặt Istio Multicluster bằng Helm
  • Triển khai ứng dụng web từ nguồn đến Kubernetes
  • Viết và áp dụng quy tắc Định tuyến lưu lượng truy cập cho Istio
  • Chỉ số Prometheus
  • Tạo và đẩy hình ảnh vùng chứa vào cụm Kubernetes

2. Thiết lập

Bạn có thể tham gia lớp học lập trình này trên:

  • Google Cloud Shell (nên dùng): shell trong trình duyệt, đi kèm với các công cụ đã cài đặt
  • máy tính xách tay (làm theo hướng dẫn bên dưới)

Bắt đầu với Google Cloud Platform

  1. Nhận thẻ tài khoản người dùng miễn phí của bạn từ người hướng dẫn nếu bạn chưa có tài khoản GCP.
  2. Truy cập vào Google Cloud Console rồi nhấp vào "Chọn một dự án": 5c2d9bf74c78f7e4.png
  3. Ghi lại "Mã" của dự án ở đâu đó, sau đó nhấp vào dự án để chọn dự án đó: ecc5e8e97bfa6559.png

Cloud Shell cung cấp một màn hình dòng lệnh bên trong trình duyệt của bạn, trong đó có các công cụ bạn cần cài đặt và tự động xác thực với tài khoản Google Cloud Platform của bạn. (Nếu bạn không muốn chạy bài tập này trên Cloud Shell, hãy chuyển sang phần tiếp theo.)

Truy cập vào Cloud Console (Bảng điều khiển trên đám mây) rồi nhấp vào "Kích hoạt Cloud Shell" trên thanh công cụ trên cùng bên phải:

68a17b036ce24ccb.png

Thêm công cụ vào Cloud Shell

  1. Cài đặt kubectx****: bằng cách tải tập lệnh bash xuống từ đây vào một vị trí trong $PATH.
  2. Cài đặt helm****: làm theo hướng dẫn này.

Ngoài ra, hãy chạy các lệnh sau để cài đặt cả hai vào ~/.bin và thêm vào $PATH:

mkdir -p ~/.bin && \
cd ~/.bin && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubectx && \
chmod +x kubectx && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubens && \
chmod +x kubens && \
curl -LO  https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz && \
tar xzf helm-v2.12.0-linux-amd64.tar.gz && \
rm helm-v2.12.0-linux-amd64.tar.gz && \
mv linux-amd64/helm ./helm && \
rm -r linux-amd64 && \
export PATH=${HOME}/.bin:${PATH}

Một số mẹo nhanh có thể giúp bạn sử dụng Cloud Shell dễ dàng hơn:

1. Tách vỏ vào một cửa sổ mới:

2. Sử dụng trình chỉnh sửa tệp: Nhấp vào biểu tượng bút chì ở trên cùng bên phải để chạy trình chỉnh sửa tệp trong trình duyệt. Bạn sẽ thấy tính năng này hữu ích khi chúng ta sao chép các đoạn mã vào tệp.

3. Bắt đầu thẻ mới: Nếu bạn cần nhiều lời nhắc dòng lệnh.

4. Phóng to văn bản: Cỡ chữ mặc định trên Cloud Shell có thể quá nhỏ để đọc.

Ctrl-+ trên Linux/Windows⌘-+ trên macOS.

Nếu bạn cảm thấy thoải mái hơn khi sử dụng môi trường máy trạm của riêng mình so với Cloud Shell, hãy thiết lập các công cụ sau:

  1. Cài đặt gcloud: (Đã cài đặt sẵn trên Cloud Shell.) Làm theo hướng dẫn để cài đặt gcloud trên nền tảng của bạn. Chúng ta sẽ sử dụng thông tin này để tạo một cụm Kubernetes.
  2. Cài đặt kubectl:(Đã cài đặt sẵn trên Cloud Shell.) Chạy lệnh sau để cài đặt:
gcloud components install kubectl

Chạy lệnh sau để xác thực gcloud. Bạn sẽ được yêu cầu đăng nhập bằng Tài khoản Google của mình. Sau đó, chọn dự án tạo sẵn (xem ở trên) làm dự án mặc định. (Bạn có thể bỏ qua bước định cấu hình vùng điện toán):

gcloud init
  1. Cài đặt curl: Được cài đặt sẵn trên hầu hết các hệ thống Linux/macOS. Có thể bạn đã có ứng dụng này. Nếu không, hãy tìm kiếm trên Internet về cách cài đặt trình bổ trợ đó.
  2. Cài đặt kubectx****: bằng cách tải tập lệnh bash xuống từ đây vào một vị trí trong $PATH
  3. Cài đặt helm****: làm theo hướng dẫn này.

3. Thiết lập dự án GCP

Bật API GKE (Google Kubernetes Engine), GCR (Google Container Registry) và GCB (Google Cloud Build) trên dự án của bạn:

gcloud services enable \
  cloudapis.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  cloudbuild.googleapis.com

Thiết lập biến môi trường

Chúng ta sẽ làm việc nhiều với dự án Google Cloud trong quá trình thiết lập, hãy đặt một biến môi trường để tham khảo nhanh

export GCLOUD_PROJECT=$(gcloud config get-value project)

Chúng ta sẽ tạo một số mã và tệp cấu hình trong hội thảo này, vì vậy, hãy tạo một thư mục dự án và chuyển sang thư mục đó

mkdir -p src/istio-burst && \
cd src/istio-burst && \
export proj=$(pwd)

4. Tạo cụm Kubernetes "chính"

Bạn có thể dễ dàng tạo cụm Kubernetes được quản lý bằng Google Kubernetes Engine (GKE).

Lệnh sau đây sẽ tạo một cụm Kubernetes:

  • có tên là "chính",
  • trong vùng us-west1-a,
  • Phiên bản Kubernetes mới nhất hiện có,
  • với 4 nút ban đầu
export cluster=primary
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias

(Quá trình này có thể mất khoảng 5 phút. Bạn có thể xem cụm đang được tạo trong Cloud Console.)

Sau khi tạo cụm Kubernetes, gcloud sẽ định cấu hình kubectl bằng thông tin xác thực trỏ đến cụm đó.

gcloud container clusters get-credentials $cluster --zone=$zone

Giờ đây, bạn có thể sử dụng kubectl với cụm mới.

Chạy lệnh sau để liệt kê các nút Kubernetes của cụm (các nút này sẽ hiển thị trạng thái "Sẵn sàng"):

kubectl get nodes

Sửa đổi tên Kubeconfig để dễ sử dụng

Chúng ta sẽ thường xuyên chuyển đổi giữa các ngữ cảnh, vì vậy, việc có một bí danh ngắn cho các cụm của chúng ta sẽ rất hữu ích.

Lệnh này sẽ đổi tên mục kubeconfig bạn vừa tạo thành primary

kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}

Đặt quyền:

Để triển khai Istio, bạn phải là quản trị viên cụm. Lệnh này sẽ đặt email liên kết với tài khoản Google Cloud của bạn làm quản trị viên cụm

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole=cluster-admin \
    --user=$(gcloud config get-value core/account)

5. Tạo cụm "bùng nổ"

Lệnh sau đây sẽ tạo một cụm Kubernetes:

  • có tên là "burst",
  • trong vùng us-west1-a,
  • Phiên bản Kubernetes mới nhất hiện có,
  • Có 1 nút ban đầu
  • Đã bật tính năng tự động mở rộng quy mô lên đến 5 nút
export cluster=burst
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "1" --enable-autoscaling --min-nodes=1 --max-nodes=5 \
--network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias

(Quá trình này có thể mất khoảng 5 phút. Bạn có thể xem cụm đang được tạo trong Cloud Console.)

Sau khi tạo cụm Kubernetes, gcloud sẽ định cấu hình kubectl bằng thông tin xác thực trỏ đến cụm đó.

gcloud container clusters get-credentials $cluster --zone=$zone

Giờ đây, bạn có thể sử dụng kubectl với cụm mới.

Chạy lệnh sau để liệt kê các nút Kubernetes của cụm (các nút này sẽ hiển thị trạng thái "Sẵn sàng"):

kubectl get nodes

Sửa đổi tên Kubeconfig để dễ sử dụng

Lệnh này sẽ sửa đổi mục nhập kubeconfig mà bạn vừa tạo thành burst

kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}

Đặt quyền:

Để triển khai Istio Remote, bạn phải là quản trị viên cụm. Lệnh này sẽ đặt email liên kết với tài khoản Google Cloud của bạn làm quản trị viên cụm

kubectl create clusterrolebinding cluster-admin-binding \
   
--clusterrole=cluster-admin \
   
--user=$(gcloud config get-value core/account)

6. Áp dụng quy tắc tường lửa

Để hai cụm của chúng ta giao tiếp với nhau, chúng ta cần tạo một quy tắc Tường lửa.

Chạy các lệnh sau để tạo quy tắc Tường lửa trong Google Cloud Platform, cho phép các cụm của chúng ta giao tiếp

function join_by { local IFS="$1"; shift; echo "$*"; }
ALL_CLUSTER_CIDRS=$(gcloud container clusters list \
--filter="(name=burst OR name=primary) AND zone=$zone" \
--format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list \
--filter="(metadata.cluster-name=burst OR metadata.cluster-name=primary) AND metadata.cluster-location=us-west1-a" \
--format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
gcloud compute firewall-rules create istio-multicluster-test-pods \
  --allow=tcp,udp,icmp,esp,ah,sctp \
  --direction=INGRESS \
  --priority=900 \
  --source-ranges="${ALL_CLUSTER_CIDRS}" \
  --target-tags="${ALL_CLUSTER_NETTAGS}" --quiet

Chúng ta đã thiết lập xong cả hai cụm và sẵn sàng triển khai ứng dụng cũng như Istio trên các cụm đó!

7. Giới thiệu về Istio

Istio là gì?

Istio là một vùng điều khiển lưới dịch vụ nhằm "kết nối, bảo mật, kiểm soát và quan sát các dịch vụ". Công cụ này thực hiện việc này theo nhiều cách, nhưng chủ yếu là bằng cách gắn một vùng chứa proxy ( Envoy) vào mỗi Pod Kubernetes đã triển khai. Vùng chứa proxy kiểm soát tất cả hoạt động giao tiếp mạng giữa các dịch vụ vi mô cùng với chính sách đa năng và trung tâm đo từ xa ( Mixer).

a25613cd581825da.png

Bạn có thể áp dụng các chính sách này độc lập với các Dịch vụ và Bản triển khai Kubernetes. Điều này có nghĩa là Nhà điều hành mạng có thể quan sát hoạt động mạng, hạn chế, chuyển hướng hoặc viết lại chính sách mạng mà không cần triển khai lại các ứng dụng liên quan.

Một số tính năng Quản lý lưu lượng truy cập mà Istio hỗ trợ là:

  • Cầu dao
  • Phân chia lưu lượng truy cập dựa trên tỷ lệ phần trăm
  • Viết lại URL
  • Kết thúc TLS
  • Kiểm tra tình trạng
  • Cân bằng tải

Trong phạm vi hội thảo này, chúng ta sẽ tập trung vào việc phân chia lưu lượng truy cập dựa trên tỷ lệ phần trăm.

Các thuật ngữ Istio mà chúng ta sẽ sử dụng

VirtualService

VirtualService xác định một bộ quy tắc định tuyến lưu lượng truy cập để áp dụng khi một máy chủ lưu trữ được định địa chỉ.

Cổng

Cổng là một trình cân bằng tải hoạt động ở cạnh của mạng lưới nhận kết nối HTTP/TCP đến hoặc đi. Cổng có thể chỉ định Cổng, cấu hình SNI, v.v.

DestinationRule

DestinationRule xác định các chính sách áp dụng cho lưu lượng truy cập dành cho một dịch vụ sau khi quá trình định tuyến đã diễn ra. Các tệp này chỉ định cấu hình cho việc cân bằng tải, kích thước nhóm kết nối từ xe bên và chế độ cài đặt phát hiện giá trị ngoại lai.

Istio Multicluster

Bạn có thể nhận thấy khi chúng ta tạo hai cụm, cụm primary có 4 nút không tự động mở rộng quy mô và cụm burst có 1 nút với khả năng tự động mở rộng quy mô lên đến 5 nút.

Có hai lý do cho cấu hình này.

Trước tiên, chúng ta muốn mô phỏng một tình huống "tại chỗ" sang đám mây. Trong môi trường cục bộ, bạn không có quyền truy cập vào các cụm tự động điều chỉnh quy mô vì bạn có cơ sở hạ tầng cố định.

Thứ hai, việc thiết lập 4 nút (như đã xác định ở trên) là yêu cầu tối thiểu để chạy Istio. Điều này đặt ra câu hỏi: nếu Istio yêu cầu tối thiểu 4 nút, làm cách nào để cụm burst của chúng ta chạy Istio với 1 nút? Câu trả lời là Istio Multicluster cài đặt một nhóm dịch vụ Istio nhỏ hơn nhiều và giao tiếp với quá trình cài đặt Istio trong cụm chính để truy xuất các quy tắc chính sách và phát hành thông tin đo từ xa.

8. Tổng quan về cấu trúc ứng dụng

Tổng quan về thành phần

Chúng ta sẽ triển khai một ứng dụng ba cấp bằng cách sử dụng NodeJSRedis.

Worker

Ứng dụng worker được viết bằng NodeJS và sẽ theo dõi các yêu cầu HTTP POST đến, thực hiện thao tác băm trên các yêu cầu đó và nếu một biến môi trường có tên PREFIX được xác định, thì ứng dụng này sẽ thêm giá trị đó vào đầu hàm băm. Sau khi tính toán hàm băm, ứng dụng sẽ gửi kết quả trên kênh "calculation" trên máy chủ Redis đã chỉ định.

Chúng ta sẽ sử dụng biến môi trường PREFIX sau để minh hoạ chức năng nhiều cụm.

Để tham khảo: đây là các gói mà ứng dụng sử dụng.

  • body-parser: Cho phép chúng ta phân tích cú pháp các yêu cầu http
  • cors: Cho phép sử dụng tính năng Chia sẻ tài nguyên trên nhiều nguồn gốc
  • dotenv: Dễ dàng phân tích cú pháp các biến môi trường
  • express: Dịch vụ lưu trữ trang web dễ dàng
  • ioredis: Thư viện ứng dụng để giao tiếp với cơ sở dữ liệu Redis
  • morgan: Cung cấp nhật ký có cấu trúc đẹp

Giao diện người dùng

Giao diện người dùng của chúng ta cũng là một ứng dụng NodeJS lưu trữ một trang web bằng express. Ứng dụng này lấy tần suất do người dùng nhập và gửi yêu cầu đến ứng dụng worker theo tốc độ đó. Ứng dụng này cũng đăng ký nhận thông báo trên kênh Redis có tên "calculation" và hiển thị kết quả trong một trang web.

Ứng dụng sử dụng các phần phụ thuộc sau.

  • body-parser: Cho phép chúng ta phân tích cú pháp các yêu cầu http
  • dotenv: Dễ dàng phân tích cú pháp các biến môi trường
  • express: Dịch vụ lưu trữ trang web dễ dàng
  • ioredis: Thư viện ứng dụng để giao tiếp với cơ sở dữ liệu Redis
  • morgan: Cung cấp nhật ký có cấu trúc đẹp
  • request: Cho phép tạo yêu cầu HTTP
  • socket.io: Cho phép giao tiếp hai chiều từ Trang web đến máy chủ

Trang web này sử dụng Bootstrap để tạo kiểu và khi chạy, trang web sẽ có dạng như sau

e5e3b9cbede4cac4.png

Sơ đồ cấu trúc

7ae4bc22a58f80a6.png

Biểu đồ triển khai

Chúng ta sẽ triển khai ứng dụng hoàn thiện trên hai cụm đã tạo. Cụm primary sẽ có tất cả các thành phần (frontend, worker và Redis) được triển khai cho cụm này, nhưng cụm burst sẽ chỉ có ứng dụng worker được triển khai.

Dưới đây là sơ đồ mô tả hai cụm. Các hộp được viền màu đỏ là Dịch vụ Kubernetes, các hộp màu xanh dương là Các bản triển khai Kubernetes. Các hộp màu vàng cho biết chúng ta đã cài đặt Istio.

561db37c510944bd.png

Hãy lưu ý cách cụm burst vẫn có một dịch vụ cho Redis được triển khai cho cụm đó mặc dù không có quá trình Triển khai cho Redis trong cụm. Chúng ta cần có dịch vụ này trong cụm để DNS Kubernetes có thể phân giải yêu cầu, nhưng khi yêu cầu thực sự được thực hiện, Proxy Istio sẽ định tuyến lại yêu cầu đến lượt triển khai Redis trong cụm primary.

Ứng dụng cuối cùng sẽ có một quá trình Triển khai bổ sung chạy trong cụm primary có tên là istiowatcher.. Đây là điều cho phép chúng ta tự động định tuyến lại lưu lượng truy cập đến burst một cách linh động khi lưu lượng truy cập vượt quá một ngưỡng nhất định.

8f6183bdfc3f813c.png

9. Tạo tệp triển khai ứng dụng

Chúng ta cần tạo một tập hợp tệp kê khai Kubernetes để triển khai ứng dụng

Chuyển sang thư mục gốc của dự án và tạo một thư mục mới có tên là kubernetes

mkdir ${proj}/kubernetes && cd ${proj}/kubernetes

Viết frontend.yaml

Thao tác này sẽ tạo cả Dịch vụ và quá trình Triển khai Kubernetes để truy cập vào hình ảnh giao diện người dùng.

Chèn nội dung sau vào frontend.yaml.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: frontend-deployment
  labels:
    app: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: gcr.io/istio-burst-workshop/frontend
        ports:
        - containerPort: 8080
        readinessProbe:
            initialDelaySeconds: 10
            httpGet:
              path: "/_healthz"
              port: 8080
              httpHeaders:
              - name: "Cookie"
                value: "istio_session-id=x-readiness-probe"
        livenessProbe:
          initialDelaySeconds: 10
          httpGet:
            path: "/"
            port: 8080
            httpHeaders:
            - name: "Cookie"
              value: "istio_session-id=x-liveness-probe"
        env:
        - name: PORT
          value: "8080"
        - name: PROCESSOR_URL
          value: "http://worker-service"
        - name: REDIS_URL
          value: "redis-cache-service:6379"
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: ClusterIP
  selector:
    app: frontend
  ports:
  - name: http
    port: 80
    targetPort: 8080

Những điều chính cần lưu ý trong Deployment

  • Chúng ta đã chỉ định cổng mà ứng dụng sẽ chạy là 8080
  • Chúng ta đã đặt địa chỉ cho worker là "http://worker-service" và sẽ sử dụng tính năng DNS tích hợp sẵn của Kubernetes để phân giải dịch vụ thu được
  • Chúng ta đã đặt địa chỉ cho REDIS_URL là "redis-cache-service:6379" và sẽ sử dụng tính năng DNS tích hợp sẵn của Kubernetes để phân giải các địa chỉ IP thu được.
  • Chúng tôi cũng đã đặt các đầu dò livenessreadiness vào vùng chứa để giúp thông báo cho Kubernetes khi vùng chứa đang hoạt động.

Viết worker-service.yaml

Chúng ta sẽ viết định nghĩa dịch vụ Kubernetes trong một tệp riêng biệt với định nghĩa về quá trình Triển khai vì chúng ta sẽ sử dụng lại dịch vụ này trên nhiều cụm, nhưng sẽ viết một quá trình Triển khai khác nhau cho mỗi cụm.

Chèn nội dung sau vào worker-service.yaml

apiVersion: v1
kind: Service
metadata:
 name: worker-service
spec:
 type: ClusterIP
 selector:
   app: worker
 ports:
 - name: http
   port: 80
   targetPort: 8081

Viết worker-primary.yaml

Đây sẽ là quá trình triển khai worker mà chúng ta sẽ đẩy vào cụm chính.

Chèn nội dung sau vào worker-primary.yaml.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: worker-deployment
 labels:
   app: worker
spec:
 replicas: 1
 selector:
   matchLabels:
     app: worker
 template:
   metadata:
     labels:
       app: worker
       cluster-type: primary-cluster
   spec:
     containers:
     - name: worker
       image: gcr.io/istio-burst-workshop/worker
       imagePullPolicy: Always
       ports:
       - containerPort: 8081
       readinessProbe:
           initialDelaySeconds: 10
           httpGet:
             path: "/_healthz"
             port: 8081
             httpHeaders:
             - name: "Cookie"
               value: "istio_session-id=x-readiness-probe"
       livenessProbe:
         initialDelaySeconds: 10
         httpGet:
           path: "/"
           port: 8081
           httpHeaders:
           - name: "Cookie"
             value: "istio_session-id=x-liveness-probe"
       env:
       - name: PORT
         value: "8081"
       - name: REDIS_URL
         value: "redis-cache-service:6379"

Lưu ý trong phần này, chúng ta đang tuân theo cùng một mẫu cung cấp đầu dò livenessreadiness cũng như chỉ định các biến môi trường PORTREDIS_URL để ứng dụng của chúng ta sử dụng.

Một điều khác cần lưu ý trong quá trình triển khai này là thiếu biến môi trường PREFIX. Điều này có nghĩa là kết quả tính toán của chúng ta sẽ là các hàm băm thô (không có tiền tố nào).

Điểm chính cuối cùng của quá trình triển khai này là nhãn cluster-type: primary-cluster. Chúng ta sẽ sử dụng thông tin đó sau khi định tuyến lưu lượng truy cập trên nhiều cụm Istio

Viết redis.yaml

Quá trình giao tiếp từ worker trở lại giao diện người dùng là thông qua một kênh Redis. Do đó, chúng ta cần triển khai một ứng dụng Redis vào cụm của mình.

Chèn nội dung sau vào redis.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: redis-cache
spec:
 template:
   metadata:
     labels:
       app: redis-cache
   spec:
     containers:
     - name: redis
       image: redis:alpine
       ports:
       - containerPort: 6379
       readinessProbe:
         periodSeconds: 5
         tcpSocket:
           port: 6379
       livenessProbe:
         periodSeconds: 5
         tcpSocket:
           port: 6379
       volumeMounts:
       - mountPath: /data
         name: redis-data
       resources:
         limits:
           memory: 256Mi
           cpu: 125m
         requests:
           cpu: 70m
           memory: 200Mi
     volumes:
     - name: redis-data
       emptyDir: {}

Đây là cách triển khai bán chuẩn của một ứng dụng Redis. Thư viện này thiết lập một vùng chứa dựa trên hình ảnh redis:alpine, hiển thị các cổng thích hợp và đặt các giới hạn tài nguyên hợp lý.

Viết redis-service.yaml

Chúng ta cần một Dịch vụ Kubernetes để giao tiếp với ứng dụng Redis

Chèn nội dung sau vào redis-service.yaml

apiVersion: v1
kind: Service
metadata:
 name: redis-cache-service
spec:
 type: ClusterIP
 selector:
   app: redis-cache
 ports:
 - port: 6379
   targetPort: 6379

Thao tác này cung cấp dịch vụ có tên redis-cache-service để truy cập vào Mô hình triển khai Redis của chúng tôi.

10. Triển khai ứng dụng

Khi hình ảnh được đẩy vào GCR và tệp kê khai Kubernetes được viết, đây là thời điểm thích hợp để triển khai ứng dụng và xem cách hoạt động của ứng dụng!

Chạy các lệnh sau để triển khai ứng dụng

  1. Đảm bảo chúng ta đang ở đúng cụm
kubectx primary
  1. Triển khai bộ nhớ đệm Redis
kubectl apply -f redis.yaml
  1. Triển khai Dịch vụ Redis
kubectl apply -f redis-service.yaml
  1. Triển khai giao diện người dùng
kubectl apply -f frontend.yaml
  1. Triển khai Worker
kubectl apply -f worker-primary.yaml
  1. Triển khai Dịch vụ worker
kubectl apply -f worker-service.yaml

Chúng ta đã triển khai ứng dụng của mình lên GKE. Xin chúc mừng!

Kiểm thử

Chờ các nhóm này xuất hiện trên mạng

kubectl get pods -w

Khi tất cả các pod đều "Đang chạy", hãy nhấn tổ hợp phím Ctrl + C

NAME                                   READY     STATUS    RESTARTS   AGE
frontend-deployment-695d95fbf7-76sd8   1/1       Running   0          2m
redis-cache-7475999bf5-nxj8x           1/1       Running   0          2m
worker-deployment-5b9cf9956d-g975p     1/1       Running   0          2m

Bạn sẽ nhận thấy rằng chúng tôi không hiển thị giao diện người dùng thông qua LoadBalancer. Đó là vì sau này chúng ta sẽ truy cập vào ứng dụng thông qua Istio. Để kiểm thử xem mọi thứ đã hoạt động hay chưa, chúng ta sẽ sử dụng kubectl port-forward. Chạy lệnh sau để chuyển tiếp cổng 8080 trên máy cục bộ (hoặc Cloud Shell) sang cổng 8080 đang chạy quá trình triển khai frontend.

kubectl port-forward \
$
(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080

Nếu bạn đang chạy cục bộ: hãy mở trình duyệt web rồi chuyển đến http://localhost:8080

Nếu bạn đang chạy trong Cloud Shell: hãy nhấp vào nút "Xem trước trên web" rồi chọn "Xem trước trên cổng 8080"

bdb5dc75f415be11.png

Bạn sẽ thấy giao diện người dùng! Và nếu nhập một số vào hộp "tần suất", bạn sẽ thấy các hàm băm bắt đầu xuất hiện

1caafaffab26897a.png

Xin chúc mừng! Mọi thứ đã sẵn sàng hoạt động!

Nhấn Ctrl+C để dừng chuyển tiếp cổng.

11. Dọn dẹp ứng dụng đã triển khai

Chúng ta sẽ áp dụng Istio cho cụm của mình rồi triển khai lại ứng dụng. Vì vậy, trước tiên, hãy dọn dẹp ứng dụng hiện tại.

Chạy các lệnh sau để xoá tất cả các lượt triển khai và dịch vụ mà bạn vừa tạo

  1. Xoá redis-cache-service
kubectl delete -f redis-service.yaml
  1. Xoá redis
kubectl delete -f redis.yaml
  1. Xoá frontend
kubectl delete -f frontend.yaml
  1. Xoá worker
kubectl delete -f worker-primary.yaml
  1. Xoá worker-service
kubectl delete -f worker-service.yaml

12. Cài đặt Istio trên cụm chính

Tải Istio

Các bản phát hành của Istio được lưu trữ trên GitHub. Các lệnh sau sẽ tải phiên bản 1.0.0 của istio xuống và giải nén phiên bản đó.

  1. Thay đổi thành thư mục gốc của dự án
cd ${proj}
  1. Tải bản lưu trữ xuống
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
  1. Giải nén và xoá tệp lưu trữ
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz

Tạo mẫu Istio

Việc chạy lệnh Helm sau đây sẽ tạo mẫu để cài đặt Istio vào cụm của bạn.

helm template istio-1.0.0/install/kubernetes/helm/istio \
--name istio --namespace istio-system \
--set prometheus.enabled=true \
--set servicegraph.enabled=true  > istio-primary.yaml

Thao tác này sẽ tạo một tệp có tên istio-primary.yaml trong thư mục hiện tại của bạn, chứa tất cả các định nghĩa và thông số kỹ thuật cần thiết để triển khai và chạy Istio.

Hãy lưu ý hai tham số --set. Các tính năng này sẽ thêm tính năng hỗ trợ PrometheusServiceGraph vào hệ thống Istio. Chúng ta sẽ sử dụng dịch vụ Prometheus sau trong lớp học lập trình.

Triển khai Istio

Để triển khai istio, trước tiên, chúng ta cần tạo một không gian tên có tên là istio-system mà các Dịch vụ và hoạt động triển khai Istio có thể chạy trong đó.

kubectl create namespace istio-system

Cuối cùng, hãy áp dụng tệp istio-primary.yaml mà chúng ta đã tạo bằng Helm

kubectl apply -f istio-primary.yaml

Vùng chứa tên mặc định của nhãn

Istio hoạt động bằng cách chèn dịch vụ proxy sidecar vào từng lượt Triển khai. Việc này được thực hiện trên cơ sở chọn tham gia, vì vậy, chúng ta cần gắn nhãn không gian tên default bằng istio-injection=enabled để Istio có thể tự động chèn sidecar cho chúng ta.

kubectl label namespace default istio-injection=enabled

Xin chúc mừng! Chúng ta đã có một cụm đang chạy với Istio để sẵn sàng triển khai ứng dụng!

13. Triển khai ứng dụng bằng tính năng Quản lý lưu lượng truy cập Istio

Tạo tệp cấu hình quản lý lưu lượng truy cập Istio

Istio hoạt động tương tự như Kubernetes vì sử dụng các tệp yaml để định cấu hình. Do đó, chúng ta cần tạo một tập hợp tệp để cho Istio biết cách hiển thị và định tuyến lưu lượng truy cập.

Tạo một thư mục có tên istio-manifests rồi chuyển sang thư mục đó

mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests

Viết frontend-gateway.yaml

Tệp này sẽ hiển thị cụm Kubernetes của chúng ta theo cách tương tự như LoadBalancer GKE và sẽ định tuyến tất cả lưu lượng truy cập đến dịch vụ giao diện người dùng của chúng ta.

Tạo một tệp có tên là frontend-gateway.yaml rồi chèn nội dung sau.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
 name: frontend-gateway
spec:
 selector:
   istio: ingressgateway # use Istio default gateway implementation
 servers:
 - port:
     number: 80
     name: http
     protocol: HTTP
   hosts:
   - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: frontend-ingress-virtual-service
spec:
 hosts:
 - "*"
 gateways:
 - frontend-gateway
 http:
 - route:
   - destination:
       host: frontend-service
       port:
         number: 80

Viết redis-virtualservice.yaml

Tạo một tệp có tên là redis-virtualservice.yaml và chèn nội dung sau

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: redis-virtual-service
spec:
 hosts:
 - redis-cache-service
 gateways:
 - mesh
 tcp:
 - route:
   - destination:
       host: redis-cache-service.default.svc.cluster.local

Viết worker-virtualservice.yaml

Tạo một tệp có tên là worker-virtualservice.yaml và chèn nội dung sau

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: worker-virtual-service
spec:
 hosts:
 - worker-service
 gateways:
 - mesh
 http:
 - route:
   - destination:
       host: worker-service.default.svc.cluster.local  
       port:
         number: 80

Triển khai Chính sách quản lý lưu lượng truy cập Istio

Việc triển khai các chính sách Istio được thực hiện theo cách tương tự như các tài nguyên Kubernetes khác, với kubectl apply

  1. Áp dụng Cổng của chúng tôi
kubectl apply -f frontend-gateway.yaml
  1. Áp dụng VirtualService Redis
kubectl apply -f redis-virtualservice.yaml
  1. Áp dụng VirtualService của Worker
kubectl apply -f worker-virtualservice.yaml

Triển khai ứng dụng

  1. Thay đổi trở lại thư mục kubernetes
cd ${proj}/kubernetes
  1. Triển khai bộ nhớ đệm Redis
kubectl apply -f redis.yaml
  1. Triển khai Dịch vụ Redis
kubectl apply -f redis-service.yaml
  1. Triển khai giao diện người dùng
kubectl apply -f frontend.yaml
  1. Triển khai Worker
kubectl apply -f worker-primary.yaml
  1. Triển khai Dịch vụ worker
kubectl apply -f worker-service.yaml

Xác minh

Tại thời điểm này, chúng tôi đã triển khai lại ứng dụng trên một cụm có Istio và các chính sách quản lý lưu lượng truy cập.

Hãy chờ tất cả khối lượng công việc của chúng ta được đưa lên mạng

Sau khi tất cả các máy chủ đều có kết nối mạng, hãy lấy IngressGateway mà chúng ta đã định cấu hình trong frontend-ingressgateway.yaml

$ kubectl -n istio-system get svc istio-ingressgateway
NAME                   TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                                                                                                     AGE
istio-ingressgateway   LoadBalancer   10.36.3.112   35.199.158.10   80:31380/TCP,

Hãy duyệt đến địa chỉ <EXTERNAL-IP> hoặc curl địa chỉ đó và bạn sẽ thấy giao diện người dùng!

$ curl 35.199.158.10
<!doctype html>
<html>

<head>
    <title>String Hashr</title>
    <!-- Bootstrap -->
...

14. Cài đặt Istio trên cụm &quot;bùng nổ&quot;

Chúng ta đã dành nhiều thời gian để thiết lập và triển khai trên cụm primary, nhưng chúng ta còn có một cụm khác để triển khai!

Trong phần này, chúng ta cần lấy các biến cấu hình trên cả hai cụm, vì vậy, hãy chú ý đến cụm mà chúng ta được trỏ đến cho mỗi lệnh.

Tạo tệp kê khai từ xa Istio

Tương tự như khi triển khai Istio cho cụm primary, chúng ta sẽ sử dụng Helm để tạo mẫu triển khai istio từ xa cho cụm burst. Tuy nhiên, trước khi có thể làm như vậy, chúng ta cần có một số thông tin về cụm primary

Thu thập thông tin về cụm chính

Thay đổi thành cụm primary

kubectx primary

Các lệnh sau truy xuất địa chỉ IP của nhiều vùng chứa trong cụm chính. Các thông tin này được Istio Remote sử dụng để giao tiếp lại với cụm chính.

export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')

Tạo mẫu từ xa

Bây giờ, chúng ta sẽ sử dụng helm để tạo một tệp có tên là istio-remote-burst.yaml. Sau đó, chúng ta có thể triển khai tệp này cho cụm burst.

Thay đổi thành thư mục gốc của dự án

cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \
--name istio-remote \
--set global.remotePilotAddress=${PILOT_POD_IP} \
--set global.remotePolicyAddress=${POLICY_POD_IP} \
--set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set global.proxy.envoyStatsd.enabled=true \
--set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \
--set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml

Cài đặt Istio Remote trên cụm burst

Để cài đặt Istio trên cụm burst, chúng ta cần làm theo các bước tương tự như khi cài đặt trên cụm primary, nhưng chúng ta cần sử dụng tệp istio-remote-burst.yaml.

Thay đổi kubecontext thành burst

kubectx burst

Tạo không gian tên istio-system

kubectl create ns istio-system

Áp dụng istio-burst.yaml

kubectl apply -f istio-remote-burst.yaml

Vùng chứa tên mặc định của nhãn

Xin nhắc lại, chúng ta cần gắn nhãn cho không gian tên default để có thể tự động chèn proxy.

kubectl label namespace default istio-injection=enabled

Xin chúc mừng! Tại thời điểm này, chúng ta đã thiết lập Istio Remote trên cụm burst. Tuy nhiên, tại thời điểm này, các cụm vẫn không thể giao tiếp. Chúng ta cần tạo một tệp kubeconfig cho cụm burst mà chúng ta có thể triển khai cho cụm primary để liên kết các cụm này với nhau.

Tạo kubeconfig cho cụm "bùng nổ"

Thay đổi thành cụm bắn phá

kubectx burst

Thiết lập môi trường

Chúng ta cần thu thập một số thông tin về cụm để tạo tệp kubeconfig cho cụm đó.

  1. Lấy tên của cụm
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
  1. Lấy tên máy chủ cụm
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
  1. Lấy tên của khoá bí mật cho Tổ chức phát hành chứng chỉ của tài khoản dịch vụ istio-multi
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
  1. Lấy dữ liệu Cơ quan cấp chứng chỉ được lưu trữ trong khoá bí mật trước đó
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
  1. Lấy mã thông báo được lưu trữ trong khoá bí mật trước đó
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)

Tạo tệp kubeconfig

Sau khi đặt tất cả các biến môi trường đó, chúng ta cần tạo tệp kubeconfig

cat <<EOF > burst-kubeconfig
apiVersion: v1
clusters:
   - cluster:
       certificate-authority-data: ${CA_DATA}
       server: ${SERVER}
     name: ${CLUSTER_NAME}
contexts:
   - context:
       cluster: ${CLUSTER_NAME}
       user: ${CLUSTER_NAME}
     name: ${CLUSTER_NAME}
current-context: ${CLUSTER_NAME}
kind: Config
preferences: {}
users:
   - name: ${CLUSTER_NAME}
     user:
       token: ${TOKEN}
EOF

Thao tác này sẽ tạo một tệp mới có tên là burst-kubeconfig trong thư mục hiện tại của bạn. Cụm primary có thể sử dụng tệp này để xác thực và quản lý cụm burst.

Thay đổi trở lại cụm chính

kubectx primary

Áp dụng kubeconfig cho "burst" (luồng dữ liệu) bằng cách tạo một khoá bí mật và gắn nhãn cho khoá đó

kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system

Gắn nhãn cho khoá bí mật để Istio biết sử dụng khoá đó cho việc xác thực nhiều cụm

kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system

Xin chúc mừng! Chúng tôi đã xác thực và giao tiếp với nhau qua Istio Multicluster. Hãy triển khai ứng dụng của chúng ta trên nhiều cụm

15. Triển khai ứng dụng trên nhiều cụm

Tạo bản triển khai

Thay đổi thành thư mục kubernetes

cd ${proj}/kubernetes

Tạo bản triển khai worker cho cụm "bùng nổ": worker-burst.yaml

Tạo một tệp có tên là worker-burst.yaml rồi chèn nội dung sau vào tệp đó:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: worker-deployment
  labels:
    app: worker
spec:
  replicas: 1
  selector:
    matchLabels:
      app: worker
  template:
    metadata:
      labels:
        app: worker
        cluster-type: burst-cluster
    spec:
      containers:
      - name: worker
        image: gcr.io/istio-burst-workshop/worker
        imagePullPolicy: Always
        ports:
        - containerPort: 8081
        readinessProbe:
            initialDelaySeconds: 10
            httpGet:
              path: "/_healthz"
              port: 8081
              httpHeaders:
              - name: "Cookie"
                value: "istio_session-id=x-readiness-probe"
        livenessProbe:
          initialDelaySeconds: 10
          httpGet:
            path: "/"
            port: 8081
            httpHeaders:
            - name: "Cookie"
              value: "istio_session-id=x-liveness-probe"
        env:
        - name: PORT
          value: "8081"
        - name: REDIS_URL
          value: "redis-cache-service:6379"
        - name: PREFIX
          value: "bursty-"

Hãy lưu ý rằng tệp này gần giống với worker-primary.yaml mà chúng ta đã tạo trước đó. Có hai điểm khác biệt chính.

Điểm khác biệt chính đầu tiên là chúng ta đã thêm biến môi trường PREFIX có giá trị "bursty-"

env:
- name: PORT
  value
: "8081"
- name: REDIS_URL
  value
: "redis-cache-service:6379"
- name: PREFIX
  value
: "bursty-"

Điều này có nghĩa là worker trong cụm burst sẽ thêm tiền tố "bursty-" vào tất cả các hàm băm mà worker gửi. Chúng ta có thể sử dụng thông tin này để biết rằng ứng dụng của mình thực sự chạy trên nhiều cụm.

Điểm khác biệt chính thứ hai là chúng tôi đã thay đổi nhãn cluster-type trên lần triển khai này từ primary-cluster thành burst-cluster

labels:
  app: worker
  cluster-type: burst-cluster

Chúng ta sẽ sử dụng nhãn này sau khi cập nhật VirtualService.

Sửa đổi dịch vụ Istio

Hiện tại, các dịch vụ Istio của chúng tôi không tận dụng được cả hai lần triển khai. 100% lưu lượng truy cập của chúng tôi đang được định tuyến đến cụm "chính". Hãy thay đổi điều đó.

Thay đổi thành thư mục istio-manifests

cd ${proj}/istio-manifests

Chỉnh sửa worker-virtualservice.yaml để thêm DestinationRules

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: worker-virtual-service
spec:
  hosts:
  - worker-service
  gateways:
  - mesh
  http:
  - route:
    - destination:
        host: worker-service.default.svc.cluster.local    
        subset: primary
        port:
          number: 80        
      weight: 50
    - destination:
        host: worker-service.default.svc.cluster.local    
        subset: burst  
        port:
          number: 80        
      weight: 50
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: worker-destination-rule
spec:
  host: worker-service
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: primary
    labels:
      cluster-type: primary-cluster
  - name: burst
    labels:
     cluster-type: burst-cluster

Bạn có thể thấy chúng ta đã thêm một đích đến thứ hai vào VirtualService. Tệp này vẫn tham chiếu đến cùng một máy chủ lưu trữ (worker-service.default.svc.cluster.local), nhưng 50% lưu lượng truy cập đang được định tuyến đến tập hợp con primary và 50% còn lại được định tuyến đến tập hợp con burst.

Chúng tôi đã xác định tập hợp con primary là các bản triển khai có nhãn cluster-type: primary-cluster và tập hợp con burst là các bản triển khai có nhãn cluster-type: burst-cluster.

Điều này giúp phân chia lưu lượng truy cập một cách hiệu quả theo tỷ lệ 50/50 giữa hai cụm.

Triển khai cho cụm

Triển khai redis-service.yaml cho cụm burst

Thay đổi thành kubeconfig burst

kubectx burst

Thay đổi thành thư mục gốc của dự án

cd ${proj}

Sau đó, hãy triển khai

Triển khai redis-service.yaml cho cụm burst

kubectl apply -f kubernetes/redis-service.yaml

Triển khai worker-burst.yaml cho cụm burst

kubectl apply -f kubernetes/worker-burst.yaml

Triển khai worker-service.yaml cho cụm burst

kubectl apply -f kubernetes/worker-service.yaml

Áp dụng VirtualServices của Istio

Thay đổi thành kubeconfig primary

kubectx primary

Sau đó, hãy triển khai

kubectl apply -f istio-manifests/worker-virtualservice.yaml

Xác minh rằng mã hoạt động

Để xác minh tính năng này hoạt động, hãy duyệt đến điểm truy cập Istio và lưu ý rằng khoảng 50% hàm băm có tiền tố là "burst-".

78fb6e235e9f4a07.png

Điều này có nghĩa là chúng ta đang trò chuyện thành công giữa các cụm! Hãy thử thay đổi trọng số trên các dịch vụ khác nhau và áp dụng tệp worker-virtualservice.yaml. Đây là một cách tuyệt vời để cân bằng lưu lượng truy cập giữa các cụm, nhưng nếu chúng ta có thể tự động thực hiện việc này thì sao?

16. Tận dụng các chỉ số Prometheus

Giới thiệu về Prometheus

Prometheus là một bộ công cụ cảnh báo và giám sát hệ thống nguồn mở, ban đầu được xây dựng tại SoundCloud. Lớp này duy trì mô hình dữ liệu nhiều chiều với dữ liệu chuỗi thời gian được xác định theo tên chỉ số và cặp khoá/giá trị.

Để tham khảo, sau đây là sơ đồ Cấu trúc Prometheus:

601e1155a825e0c2.png

Khi được triển khai với Prometheus, Istio sẽ tự động báo cáo nhiều chỉ số cho máy chủ Prometheus. Chúng ta có thể sử dụng các chỉ số này để quản lý các cụm của mình một cách linh hoạt.

Khám phá các chỉ số Prometheus

Để bắt đầu, chúng ta cần hiển thị hoạt động Triển khai Prometheus.

Chuyển đến thẻ Workloads (Khối lượng công việc) trong GKE, sau đó chuyển đến khối lượng công việc "prometheus".

b4a7a3cd67db05b3.png

Khi bạn đang xem thông tin chi tiết về quá trình triển khai, hãy chuyển đến Hành động -> Hiển thị.

c04a482e55bdfd41.png

Chọn chuyển tiếp đến cổng 9090 rồi nhập "Trình cân bằng tải"

d5af3ba22a7a6ebb.png

Rồi chọn "Hiển thị"

Thao tác này sẽ tạo một Dịch vụ trên một địa chỉ IP có thể truy cập công khai mà chúng ta có thể sử dụng để khám phá các Chỉ số Prometheus

Chờ điểm cuối hoạt động, sau đó nhấp vào địa chỉ IP bên cạnh "Điểm cuối bên ngoài" b1e40ad90851da29.png

Bây giờ, bạn sẽ thấy giao diện người dùng Prometheus.

ed273552270337ec.png

Prometheus cung cấp đủ chỉ số để trở thành một hội thảo riêng. Tuy nhiên, hiện tại, chúng ta sẽ bắt đầu bằng cách khám phá chỉ số istio_requests_total.

Việc thực thi truy vấn đó sẽ trả về một loạt dữ liệu. Đây là các chỉ số về tất cả các yêu cầu đang đi qua mạng lưới dịch vụ Istio và có rất nhiều chỉ số! Chúng ta sẽ thay đổi biểu thức để lọc ra những gì chúng ta thực sự quan tâm:

Các yêu cầu mà dịch vụ đích là worker-service.default.svc.cluster.local và nguồn là frontend-deployment bị giới hạn ở 15 giây gần nhất

Truy vấn đó có dạng như sau:

istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]

Và cung cấp cho chúng ta một tập dữ liệu dễ quản lý hơn nhiều

19d551fd5eac3785.png

Nhưng vẫn hơi dày. Chúng ta muốn biết số yêu cầu mỗi giây, chứ không phải tất cả yêu cầu.

Để làm được điều đó, chúng ta có thể sử dụng hàm rate tích hợp sẵn

rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])

dbb9dc063a18da9b.png

Chúng ta đã gần đến đích, nhưng cần phải giảm bớt các chỉ số đó thành một nhóm hợp lý.

Để làm việc này, chúng ta có thể sử dụng từ khoá sumby để nhóm và tổng hợp kết quả

sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)

898519966930ec56.png

Tuyệt lắm! Chúng ta có thể lấy các chỉ số chính xác mà chúng ta cần từ Prometheus.

Truy vấn Prometheus cuối cùng của chúng ta

Với tất cả những gì chúng ta đã tìm hiểu, truy vấn cuối cùng mà chúng ta cần gửi đến Prometheus là

sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)

Bây giờ, chúng ta có thể sử dụng API HTTP của họ để lấy chỉ số này.

Chúng ta có thể truy vấn API của họ bằng truy vấn của mình bằng cách tạo một yêu cầu GET http như sau. Thay thế <prometheus-ip-here>

curl http://<prometheus-ip-here>/api/v1/query?query=sum\(rate\(istio_requests_total%7Breporter%3D%22destination%22%2C%0Adestination_service%3D%22worker-service.default.svc.cluster.local%22%2C%0Asource_workload%3D%22frontend-deployment%22%7D%5B15s%5D\)\)%20by%20\(source_workload%2C%0Asource_app%2C%20destination_service\)

Dưới đây là ví dụ về phản hồi:

{
    "status": "success",
    "data": {
        "resultType": "vector",
        "result": [
            {
                "metric": {
                    "destination_service": "worker-service.default.svc.cluster.local",
                    "source_app": "frontend",
                    "source_workload": "frontend-deployment"
                },
                "value": [
                    1544404907.503,
                    "18.892886390062788"
                ]
            }
        ]
    }
}

Bây giờ, chúng ta có thể trích xuất giá trị chỉ số từ JSON

Dọn dẹp

Chúng ta cần xoá Dịch vụ mà chúng ta vừa dùng để hiển thị Prometheus. Trong Google Cloud Console, hãy chuyển đến đầu dịch vụ mà chúng ta vừa tạo rồi nhấp vào "Xoá"

d58cb51b4c922751.png

Các bước tiếp theo:

Sau khi tìm ra cách khám phá cách lưu lượng truy cập di chuyển qua cụm và tốc độ, bước tiếp theo của chúng ta là viết một tệp nhị phân nhỏ truy vấn định kỳ prometheus và nếu số yêu cầu mỗi giây đến worker vượt quá một ngưỡng nhất định, hãy áp dụng các trọng số đích khác nhau trên dịch vụ ảo của worker để gửi tất cả lưu lượng truy cập đến cụm burst. Khi số yêu cầu mỗi giây giảm xuống dưới ngưỡng thấp hơn, hãy gửi tất cả lưu lượng truy cập trở lại primary.

17. Tạo một luồng dữ liệu nhiều cụm

Thiết lập

Đặt tất cả lưu lượng truy cập cho worker-service thành cụm chính

Chúng ta sẽ coi tất cả lưu lượng truy cập đến worker-service được định tuyến đến cụm primary là trạng thái "mặc định" của ứng dụng

Chỉnh sửa $proj/istio-manifests/worker-virtualservice.yaml như sau

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: worker-virtual-service
spec:
  hosts:
  - worker-service
  gateways:
  - mesh
  http:
  - route:
    - destination:
        host: worker-service.default.svc.cluster.local    
        subset: primary
        port:
          number: 80        
      weight: 100
    - destination:
        host: worker-service.default.svc.cluster.local    
        subset: burst  
        port:
          number: 80        
      weight: 0
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: worker-destination-rule
spec:
  host: worker-service
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: primary
    labels:
      cluster-type: primary-cluster
  - name: burst
    labels:
     cluster-type: burst-cluster

Đảm bảo bạn đã kết nối với cụm primary

kubectx primary

Áp dụng istio-manifests/worker-virtualservice.yaml

kubectl apply -f istio-manifests/worker-virtualservice.yaml

Viết trình nền istiowatcher

Chúng ta sẽ sử dụng Go để viết dịch vụ này vì tốc độ và khả năng di chuyển của ngôn ngữ này. Quy trình tổng thể của ứng dụng sẽ là khởi động và mỗi giây, truy vấn prometheus,

Tạo một thư mục mới trong src có tên istiowatcher

mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher

Chúng ta sẽ gọi istioctl từ bên trong vùng chứa để thao tác với vùng điều khiển Istio từ bên trong cụm.

Viết istiowatcher.go

Tạo một tệp trong thư mục đó có tên là istiowatcher.go rồi chèn nội dung sau vào tệp đó

package main

import (
       
"github.com/tidwall/gjson"
       
"io/ioutil"
       
"log"
       
"net/http"
       
"os/exec"
       
"time"
)

func main() {
       
//These are in requests per second
       
var targetLow float64 = 10
       
var targetHigh float64 = 15
       
// This is for the ticker in milliseconds
       
ticker := time.NewTicker(1000 * time.Millisecond)

       
isBurst := false

       
// Our prometheus query
       
reqQuery := `/api/v1/query?query=sum(rate(istio_requests_total{reporter="destination",destination_service="worker-service.default.svc.cluster.local",source_workload="frontend-deployment"}[15s]))by(source_workload,source_app,destination_service)`

       
for t := range ticker.C {
               
log.Printf("Checking Prometheus at %v", t)

               
// Check prometheus
               
// Note that b/c we are querying over the past 5 minutes, we are getting a very SLOW ramp of our reqs/second
               
// If we wanted this to be a little "snappier" we can scale it down to say 30s
               
resp, err := http.Get("http://prometheus.istio-system.svc.cluster.local:9090" + reqQuery)
               
if err != nil {
                       
log.Printf("Error: %v", err)
                       
continue
               
}
               
defer resp.Body.Close()
               
body, _ := ioutil.ReadAll(resp.Body)

               
val := gjson.Get(string(body), "data.result.0.value.1")
               
log.Printf("Value: %v", val)

               
currentReqPerSecond := val.Float()
               
log.Printf("Reqs per second %f", currentReqPerSecond)

               
if currentReqPerSecond > targetHigh && !isBurst {
                       
applyIstio("burst.yaml")
                       
log.Println("Entering burst mode")
                       
isBurst = true
               
} else if currentReqPerSecond < targetLow && isBurst {
                       
applyIstio("natural.yaml")
                       
log.Println("Returning to natural state.")
                       
isBurst = false
               
}
       
}
}

func applyIstio(filename string) {
       
cmd := exec.Command("istioctl", "replace", "-f", filename)
       
if err := cmd.Run(); err != nil {
               
log.Printf("Error hit applying istio manifests: %v", err)
       
}
}

Ghi Dockerfile

Tạo một tệp mới có tên Dockerfile rồi chèn nội dung sau vào tệp đó.

FROM golang:1.11.2-stretch as base

FROM base as builder

WORKDIR /workdir
RUN curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
RUN tar xzf istio-1.0.0-linux.tar.gz
RUN cp istio-1.0.0/bin/istioctl ./istioctl

FROM base

WORKDIR /go/src/istiowatcher
COPY . .
COPY --from=builder /workdir/istioctl /usr/local/bin/istioctl

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["istiowatcher"]

Tệp Dockerfile nhiều giai đoạn này sẽ tải xuống và trích xuất bản phát hành 1.0.0 của Istio ở giai đoạn đầu tiên. Giai đoạn thứ hai sao chép mọi thứ từ thư mục của chúng ta vào hình ảnh, sau đó sao chép istioctl từ giai đoạn bản dựng sang /usr/local/bin (để ứng dụng của chúng ta có thể gọi), lấy các phần phụ thuộc, biên dịch mã và đặt CMD thành "istiowatcher"

Viết burst.yaml

Đây là tệp mà istiowatcher sẽ áp dụng khi số yêu cầu/giây đến worker từ frontend vượt quá 15.

Tạo một tệp mới có tên burst.yaml rồi chèn nội dung sau vào tệp đó.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: worker-virtual-service
spec:
 hosts:
 - worker-service
 gateways:
 - mesh
 http:
 - route:
   - destination:
       host: worker-service.default.svc.cluster.local  
       subset: primary
       port:
         number: 80      
     weight: 0
   - destination:
       host: worker-service.default.svc.cluster.local    
       subset: burst
       port:
         number: 80      
     weight:  100

Viết natural.yaml

Chúng ta sẽ coi đây là trạng thái "tự nhiên" mà chúng ta quay lại khi số yêu cầu/giây từ frontend đến worker giảm xuống dưới 10. Ở trạng thái này, 100% lưu lượng truy cập đang được định tuyến đến cụm primary.

Tạo một tệp mới có tên natural.yaml rồi chèn nội dung sau vào tệp đó

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: worker-virtual-service
spec:
 hosts:
 - worker-service
 gateways:
 - mesh
 http:
 - route:
   - destination:
       host: worker-service.default.svc.cluster.local  
       subset: primary
       port:
         number: 80      
     weight: 100
   - destination:
       host: worker-service.default.svc.cluster.local    
       subset: burst
       port:
         number: 80      
     weight: 0

Tạo và đẩy istiowatcher

Chạy lệnh sau để gửi thư mục hiện tại đến Google Cloud Build (GCB). Công cụ này sẽ tạo và gắn thẻ hình ảnh trong GCR.

gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher

Triển khai istiowatcher

Thay đổi thành thư mục kubernetes

cd ${proj}/kubernetes/

Ghi tệp triển khai: istiowatcher.yaml

Tạo một tệp có tên istiowatcher.yaml rồi chèn nội dung sau (Thay thế <your-project-id>).

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: istiowatcher-deployment
  labels:
    app: istiowatcher
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istiowatcher
  template:
    metadata:
      labels:
        app: istiowatcher
    spec:
      serviceAccountName: istio-pilot-service-account
      automountServiceAccountToken: true
      containers:
      - name: istiowatcher
        image: gcr.io/<your-project-id>/istiowatcher
        imagePullPolicy: Always

Triển khai

Đảm bảo chúng ta đang chạy trong cụm chính

kubectx primary

Triển khai istiowatcher.yaml trong không gian tên istio-system

kubectl apply -n istio-system -f istiowatcher.yaml

Điều quan trọng cần lưu ý là các lệnh serviceAccountNameautomountServiceAccountToken trong yaml. Thao tác này cung cấp cho chúng ta thông tin xác thực cần thiết để chạy istioctl từ trong cụm.

Chúng ta cũng cần triển khai thông tin này trong không gian tên istio-system để đảm bảo chúng ta có thông tin xác thực cho istio-pilot-service-account. (không tồn tại trong không gian tên default).

Xem lưu lượng truy cập tự động chuyển đổi!

Bây giờ là khoảnh khắc kỳ diệu! Hãy chuyển sang giao diện người dùng và tăng số yêu cầu/giây lên 20

Lưu ý rằng quá trình này sẽ mất vài giây, nhưng chúng ta sẽ tăng tốc và tất cả hàm băm của chúng ta đều có tiền tố "bursty-"!

Điều này là do chúng ta đang lấy mẫu prometheus trên phạm vi 15s, khiến thời gian phản hồi bị trễ một chút. Nếu muốn có một dải tần số chặt chẽ hơn, chúng ta có thể thay đổi truy vấn của mình thành prometheus thành 5s.

18. Tiếp theo là gì?

Dọn dẹp

Bạn không cần dọn dẹp nếu đang sử dụng tài khoản tạm thời được cung cấp cho hội thảo này.

Bạn có thể xoá cụm Kubernetes, quy tắc tường lửa và hình ảnh trong GCR

gcloud container clusters delete primary --zone=us-west1-a
gcloud container clusters delete burst --zone=us-west1-a
gcloud compute firewall-rules delete istio-multicluster-test-pods 
gcloud container images delete gcr.io/$GCLOUD_PROJECT/istiowatcher

Tiến về phía trước