Sổ tay Kubernetes: làm việc với Ingress Controller (p1)

Sổ tay Kubernetes: làm việc với Ingress Controller (p1)

Loạt bài viết sổ tay Kubernetes:

  • Sổ tay Kubernetes: Giới thiệu về Kubernetes.
  • Sổ tay Kubernetes: Các khái niệm cơ bản trong Kubernetes.
  • Sổ tay Kubernetes: Phương pháp triển khai bằng khai báo.
  • Sổ tay Kubernetes: Triển khai ứng dụng đa container (p1).
  • Sổ tay Kubernetes: Triển khai ứng dụng đa container (p2).
  • Sổ tay Kubernetes: Triển khai ứng dụng đa container (p3).
  • Sổ tay Kubernetes: làm việc với Ingress Controller (p1) (bài viết này).
  • Sổ tay Kubernetes: làm việc với Ingress Controller (p2).

Ở phần trước, bạn đã tìm hiểu cách triển khai ứng dụng trên nhiều container. Bạn cũng đã tìm hiểu về Persistent Volume, Persistent Volume Claim, ClusterIP, kết nối các thành phần trong cụm với nhau.

Trong hướng dẫn này, bạn sẽ tìm hiểu về Ingress Controller và cách sử dụng NGINX Ingress Controller để cấu hình định tuyến trong Kubernetes.

Làm việc với Ingress Controller

Cho đến bài viết này, bạn đã sử dụng ClusterIP để hiển thị một ứng dụng trong cụm và LoadBalancer để hiển thị một ứng dụng bên ngoài cụm.

Mặc dù tôi đã trích dẫn LoadBalancer là loại dịch vụ tiêu chuẩn để hiển thị ứng dụng bên ngoài cụm, nhưng nó có một số khuyết điểm.

Khi sử dụng LoadBalancer các dịch vụ để hiển thị các ứng dụng trong môi trường đám mây, bạn sẽ phải trả tiền cho từng dịch vụ được hiển thị riêng lẻ, điều này có thể tốn kém trong trường hợp các dự án lớn.

Có một loại dịch vụ khác được gọi là NodePort có thể được sử dụng để thay thế cho dịch vụ LoadBalancer.

Mô hình dịch vụ NodePort trong Kubernetes

Dịch vụ NodePort mở một cổng cụ thể trên tất cả các nút trong cụm của bạn và xử lý bất kỳ lưu lượng nào đi qua cổng đang mở đó.

Như bạn đã biết, các dịch vụ nhóm một số pod lại với nhau và kiểm soát cách chúng có thể được truy cập. Vì vậy, bất kỳ yêu cầu nào đến dịch vụ thông qua cổng tiếp xúc sẽ kết thúc trong đúng pod.

Ví dụ: một tệp cấu hình để tạo NodePort sẽ như sau:

apiVersion: v1
kind: Service
metadata:
  name: hello-kube-node-port
spec:
  type: NodePort
  ports:
    - port: 8080
      targetPort: 8080
      nodePort: 31515
  selector:
    component: web

Trường spec.ports.nodePort ở đây phải có giá trị giữa 30000 và 32767. Phạm vi này là các cổng ra ít được sử dụng bởi các dịch vụ khác.

Bạn có thể thử thay thế các dịch vụ LoadBalancer bạn đã tạo trong các phần trước bằng một dịch vụ NodePort. Điều này không khó và có thể được coi như một bài kiểm tra cho những gì bạn đã học được cho đến nay.

Để giải quyết các vấn đề tôi đã đề cập, Ingress API đã ra đời. Nói một cách rất rõ ràng, Ingress thực ra không phải là một loại dịch vụ. Thay vào đó, nó nằm trước nhiều dịch vụ và hoạt động như một bộ định tuyến.

IngressController là bắt buộc để làm việc với các tài nguyên Ingress trong cụm của bạn. Bạn có thể tìm thấy danh sách các ingress controller khả dụng trong tài liệu Kubernetes.

Thiết lập NGINX Ingress Controller

Trong ví dụ này, bạn sẽ mở rộng Notes API bằng cách thêm giao diện người dùng cho nó. Và thay vì sử dụng một dịch vụ như LoadBalancer hoặc NodePort, bạn sẽ sử dụng Ingress để hiển thị ứng dụng.

Controller bạn sẽ sử dụng là NGINX Ingress Controller vì NGINX sẽ được sử dụng để định tuyến các yêu cầu đến các dịch vụ khác nhau ở đây. NGINX Ingress Controller giúp bạn dễ dàng làm việc với các cấu hình NGINX trong một cụm Kubernetes.

Mã cho dự án nằm trong thư mục fullstack-notes-application.

.
├── api
├── client
├── docker-compose.yaml
├── k8s
│   ├── api-deployment.yaml
│   ├── database-persistent-volume-claim.yaml
│   ├── postgres-cluster-ip-service.yaml
│   └── postgres-deployment.yaml
├── nginx
└── postgres

5 directories, 1 file

Bạn sẽ thấy một thư mục k8s trong đó. Nó chứa tất cả các tệp cấu hình bạn đã viết trong phần trước, ngoại trừ tệp api-load-balancer-service.yaml.

Lý do là trong dự án này, dịch vụ LoadBalancer cũ sẽ được thay thế bằng Ingress. Ngoài ra, thay vì để lộ API, bạn sẽ đưa ứng dụng front-end ra ngoài thế giới.

Trước khi bạn bắt đầu viết các tệp cấu hình mới, hãy xem mọi thứ sẽ hoạt động như thế nào ở phía sau.

Lược đồ luồng ứng dụng trong Kubernetes

Người dùng truy cập ứng dụng giao diện người dùng và gửi dữ liệu cần thiết. Sau đó, ứng dụng front-end sẽ chuyển tiếp dữ liệu đã gửi tới back-end API.

Sau đó, API lưu giữ dữ liệu trong cơ sở dữ liệu và cũng gửi dữ liệu đó trở lại ứng dụng front-end. Sau đó, việc định tuyến các yêu cầu được thực hiện bằng cách sử dụng NGINX.

Bạn có thể xem tệp nginx/production.conf để hiểu cách định tuyến này đã được thiết lập.

Bây giờ mạng cần thiết để làm cho điều này xảy ra như sau:

Lược đồ luồng ứng dụng trong Kubernetes

Sơ đồ này có thể được giải thích như sau:

  • Ingress sẽ hoạt động như điểm vào và định tuyến cho ứng dụng này. Đây là một NGINX kiểu Ingress nên cổng sẽ là cổng của nginx mặc định là 80.
  • Mọi yêu cầu đến / sẽ được chuyển đến ứng dụng front-end (dịch vụ ở bên trái). Vì vậy, nếu URL của ứng dụng này là https://kube-notes.test, thì bất kỳ yêu cầu nào đến https://kube-notes.test/foo hoặc https://kube-notes.test/bar sẽ được ứng dụng front-end xử lý.
  • Mọi yêu cầu đến /api sẽ được chuyển đến API back-end (dịch vụ ở bên phải). Vì vậy, nếu lại là URL https://kube-notes.test, thì bất kỳ yêu cầu nào đến https://kube-notes.test/api/foo hoặc https://kube-notes.test/api/bar sẽ được xử lý bởi API back-end.

Hoàn toàn có thể cấu hình Ingress để hoạt động với các sub domain thay vì các đường dẫn như thế này, nhưng tôi đã chọn cách tiếp cận dựa trên đường dẫn vì đó là cách ứng dụng của tôi được thiết kế.

Trong phần này, bạn sẽ phải viết bốn tệp cấu hình mới.

  • ClusterIP cấu hình để triển khai API.
  • Deployment cấu hình cho ứng dụng front-end.
  • ClusterIP cấu hình cho ứng dụng front-end.
  • Ingress cấu hình cho định tuyến.

Tôi sẽ xem qua ba tệp đầu tiên rất nhanh mà không mất nhiều thời gian giải thích chúng.

Đầu tiên là tệp cấu hình api-cluster-ip-service.yaml và nội dung của tệp như sau:

apiVersion: v1
kind: Service
metadata:
  name: api-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: api
  ports:
    - port: 3000
      targetPort: 3000

Mặc dù trong phần trước, bạn đã cho phép thế giới bên ngoài truy cập trực tiếp API, nhưng trong phần này, bạn sẽ để Ingress thực hiện công việc nặng nhọc trong khi hiển thị API bên trong bằng cách sử dụng dịch vụ ClusterIP.

Bản thân cấu hình tại thời điểm này sẽ khá dễ hiểu, vì vậy tôi sẽ không dành bất kỳ thời gian nào để giải thích về nó.

Tiếp theo, tạo một tệp có tên client-deployment.yaml chịu trách nhiệm chạy ứng dụng front-end. Nội dung của tệp như sau:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      component: client
  template:
    metadata:
      labels:
        component: client
    spec:
      containers:
        - name: client
          image: fhsinchy/notes-client
          ports:
            - containerPort: 8080
          env:
            - name: VUE_APP_API_URL
              value: /api

Nó gần giống với tệp api-deployment.yaml và tôi giả định rằng bạn sẽ có thể tự giải thích tệp cấu hình này.

Biến môi trường VUE_APP_API_URL ở đây cho biết đường dẫn đến API sẽ được chuyển tiếp. Các yêu cầu được chuyển tiếp này sẽ lần lượt được xử lý bởi Ingress.

Để hiển thị ứng dụng khách này trong nội bộ, một dịch vụ ClusterIP khác là cần thiết. Tạo một tệp mới có tên client-cluster-ip-service.yaml và đặt nội dung sau vào đó:

apiVersion: v1
kind: Service
metadata:
  name: client-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: client
  ports:
    - port: 8080
      targetPort: 8080

Tất cả điều này làm là để lộ cổng 8080 trong cụm mà ứng dụng giao diện người dùng chạy theo mặc định.

Bây giờ các cấu hình đã xong, cấu hình tiếp theo là tệp ingress-service.yaml và nội dung của tệp như sau:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: client-cluster-ip-service
              servicePort: 8080
          - path: /api/?(.*)
            backend:
              serviceName: api-cluster-ip-service
              servicePort: 3000

Tệp cấu hình này có thể hơi xa lạ với bạn nhưng thực ra nó khá đơn giản.

  • Các Ingress API vẫn còn trong giai đoạn beta do đó apiVersionextensions/v1beta1. Mặc dù ở phiên bản beta, API rất ổn định và có thể sử dụng được trong môi trường sản xuất.
  • Các trường kindmetadata.name phục vụ cùng một mục đích như bất kỳ cấu hình nào bạn đã viết trước đó.
  • Trường metadata.annotations có thể chứa thông tin liên quan đến cấu hình Ingress. Trường kubernetes.io/ingress.class: nginx chỉ ra rằng đối tượng Ingress nên được kiểm soát bởi controller ingress-nginx. Trường nginx.ingress.kubernetes.io/rewrite-target cho biết rằng bạn muốn rewrite URL đích.
  • Trường spec.rules.http.paths chứa cấu hình liên quan đến các định tuyến đường dẫn riêng lẻ mà bạn đã thấy trước đó bên trong tệp nginx/production.conf. Trường paths.path định nghĩa các tuyến. Trường backend.serviceName là dịch vụ mà đường dẫn nói trên sẽ được định tuyến tới và trường backend.servicePort là cổng đích bên trong dịch vụ đó.
  • /?(.*)/api/?(.*) là regex đơn giản để match các yêu cầu tới các tuyến phù hợp.

Cách bạn cấu hình các bản ghi có thể thay đổi theo thời gian, vì vậy hãy kiểm tra các tài liệu chính thức sẽ là một ý kiến ​​hay.

Trước khi áp dụng các cấu hình mới, bạn sẽ phải kích hoạt phần bổ trợ ingress để minikube sử dụng lệnh addons. Cú pháp chung như sau:

minikube addons <option> <addon name>

Để kích hoạt addon ingress, hãy thực hiện lệnh sau:

minikube addons enable ingress

# ? Verifying ingress addon...
# ? The 'ingress' addon is enabled

Bạn có thể sử dụng tùy chọn disable cho lệnh addon để tắt bất kỳ addon nào. Bạn có thể tìm hiểu thêm về lệnh addon trong tài liệu chính thức.

Khi addon đã được kích hoạt, bạn có thể chạy các tệp cấu hình. Tôi khuyên bạn nên xóa tất cả các tài nguyên (service, deployment và persistent volume claim) trước khi áp dụng những tài nguyên mới.

kubectl delete ingress --all

# ingress.extensions "ingress-service" deleted

kubectl delete service --all

# service "api-cluster-ip-service" deleted
# service "client-cluster-ip-service" deleted
# service "kubernetes" deleted
# service "postgres-cluster-ip-service" deleted

kubectl delete deployment --all

# deployment.apps "api-deployment" deleted
# deployment.apps "client-deployment" deleted
# deployment.apps "postgres-deployment" deleted

kubectl delete persistentvolumeclaim --all

# persistentvolumeclaim "database-persistent-volume-claim" deleted

kubectl apply -f k8s

# service/api-cluster-ip-service created
# deployment.apps/api-deployment created
# service/client-cluster-ip-service created
# deployment.apps/client-deployment created
# persistentvolumeclaim/database-persistent-volume-claim created
# ingress.extensions/ingress-service created
# service/postgres-cluster-ip-service created
# deployment.apps/postgres-deployment created

Chờ cho đến khi tất cả các tài nguyên đã được tạo. Bạn có thể sử dụng lệnh get để đảm bảo điều đó. Khi tất cả chúng đang chạy, bạn có thể truy cập ứng dụng tại địa chỉ IP của cụm minikube. Để lấy IP, bạn có thể thực hiện lệnh sau:

minikube ip

# 172.17.0.2

Bạn cũng có thể lấy địa chỉ IP này bằng cách chạy kiểm tra Ingress:

kubectl get ingress

# NAME              CLASS    HOSTS   ADDRESS      PORTS   AGE
# ingress-service   <none>   *       172.17.0.2   80      2m33s

Như bạn có thể thấy, IP và cổng hiển thị bên dưới cột ADDRESSPORTS. Bằng cách truy cập 127.17.0.2:80, bạn sẽ truy cập trực tiếp vào ứng dụng ghi chú.

Giao diện ứng dụng

Bạn có thể thực hiện các thao tác CRUD đơn giản trong ứng dụng này. Cổng 80 là cổng mặc định cho NGINX, vì vậy bạn không cần phải truyền cổng trong URL.

Bạn có thể làm được nhiều việc với ingress controller này nếu bạn biết cách cấu hình NGINX. Rốt cuộc, đó là những gì controller này được sử dụng để lưu trữ các cấu hình NGINX trên Kubernetes ConfigMap mà bạn sẽ tìm hiểu trong phần tiếp theo.

Bài viết gốc.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *