Tối ưu hóa Truy cập Ứng dụng Kubernetes với Ingress Nginx Controller

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Bắt đầu nhanh: Công khai ứng dụng Kubernetes đầu tiên của bạn (Thiết lập trong 5 phút)

Việc làm cho ứng dụng của bạn có thể truy cập được từ bên ngoài cụm Kubernetes đôi khi giống như đi lạc trong mê cung. Các Service cung cấp cân bằng tải nội bộ, nhưng điều gì sẽ xảy ra nếu bạn cần nhiều hơn thế? Nếu bạn cần định tuyến nâng cao, chấm dứt SSL (SSL termination), hoặc một điểm truy cập duy nhất cho nhiều ứng dụng thì sao?

Đó là lúc Ingress Nginx Controller phát huy tác dụng. Đây là một bộ cân bằng tải chuyên biệt cho Kubernetes. Nó tận dụng Nginx để quản lý quyền truy cập bên ngoài vào các dịch vụ của cụm bạn. Hãy coi nó như một cảnh sát giao thông cho cụm của bạn, điều hướng các yêu cầu bên ngoài đến đúng các dịch vụ nội bộ.

Hãy cùng thiết lập cơ bản để xem nó hoạt động như thế nào.

Bước 1: Triển khai Nginx Ingress Controller

Đầu tiên, bạn cần cài đặt Ingress Nginx Controller. Cách được khuyến nghị là sử dụng Helm, giúp đơn giản hóa việc triển khai đáng kể.


# Thêm kho lưu trữ Helm của ingress-nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Cài đặt Ingress Nginx Controller
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

Lệnh này triển khai Nginx Ingress Controller vào namespace ingress-nginx riêng của nó. Có thể mất một hoặc hai phút để các pod khởi động và dịch vụ LoadBalancer nhận được một IP bên ngoài.

Bước 2: Xác minh triển khai Controller

Bạn có thể kiểm tra xem controller có đang chạy và có một IP bên ngoài hay không:


kubectl get services -n ingress-nginx

Tìm dịch vụ ingress-nginx-controller. Nó sẽ có một EXTERNAL-IP. Đây là địa chỉ IP bạn sẽ sử dụng để truy cập các ứng dụng của mình.

Bước 3: Triển khai một ứng dụng mẫu

Đối với ví dụ này, hãy triển khai một ứng dụng máy chủ web Nginx đơn giản. Tạo một tệp có tên nginx-app.yaml:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

Áp dụng tệp này vào cụm của bạn:


kubectl apply -f nginx-app.yaml

Bước 4: Tạo một Ingress Resource

Bây giờ, hãy chỉ dẫn cho Ingress Nginx Controller cách định tuyến lưu lượng truy cập đến nginx-service của chúng ta. Tạo một tệp có tên nginx-ingress.yaml:


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  ingressClassName: nginx # Điều này liên kết đến Nginx Ingress Controller
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

Áp dụng Ingress resource này:


kubectl apply -f nginx-ingress.yaml

Bước 5: Truy cập ứng dụng của bạn

Lấy lại EXTERNAL-IP của dịch vụ ingress-nginx-controller của bạn:


kubectl get services -n ingress-nginx

Mở trình duyệt web của bạn và truy cập http://<EXTERNAL-IP>. Bạn sẽ thấy trang chào mừng Nginx mặc định!

Vậy là xong phần khởi động nhanh. Bạn đã công khai thành công một ứng dụng trong Kubernetes bằng cách sử dụng Ingress Nginx Controller. Thiết lập này rất quan trọng đối với bất kỳ ai làm việc với Kubernetes. Nó tạo thành xương sống cho cách hầu hết các ứng dụng sản xuất được truy cập.

Tìm hiểu sâu: Hiểu về Kubernetes Ingress và Nginx Controller

Bây giờ bạn đã có một cái gì đó hoạt động, hãy cùng phân tích những gì đang diễn ra. Ingress chính xác là gì, và tại sao Nginx Controller lại phổ biến như vậy?

Vấn đề: Công khai các Service

Trong Kubernetes, Pod là tạm thời và có địa chỉ IP nội bộ. Các Service cung cấp một IP và tên DNS ổn định cho một tập hợp các Pod. Tuy nhiên, một Service có kiểu ClusterIP chỉ có thể truy cập được từ bên trong cụm. Để truy cập bên ngoài, bạn thường có các tùy chọn như các dịch vụ NodePort hoặc LoadBalancer:

  • NodePort: Công khai một Service trên một cổng tĩnh trên IP của mỗi Node. Đơn giản nhưng tiêu tốn cổng và không lý tưởng cho môi trường sản xuất.
  • LoadBalancer: Cung cấp một bộ cân bằng tải đám mây bên ngoài cho Service của bạn. Tuyệt vời cho việc công khai đơn giản nhưng có thể tốn kém, và bạn chỉ có một LoadBalancer cho mỗi Service, dẫn đến chi phí quản lý tăng cao cho nhiều ứng dụng.

Giải pháp: Kubernetes Ingress

Ingress là một đối tượng API quản lý quyền truy cập bên ngoài vào các dịch vụ trong một cụm, thường là HTTP. Nó cung cấp định tuyến HTTP và HTTPS đến các dịch vụ dựa trên host hoặc đường dẫn của yêu cầu. Với Ingress, bạn có thể hợp nhất các quy tắc định tuyến cho nhiều dịch vụ đằng sau một địa chỉ IP bên ngoài duy nhất được cung cấp bởi Ingress Controller.

Các lợi ích chính của Ingress:

  • Định tuyến tập trung: Quản lý tất cả các tuyến đường bên ngoài của bạn ở một nơi.
  • Điểm truy cập duy nhất: Sử dụng một IP/LoadBalancer bên ngoài cho nhiều ứng dụng.
  • Tính năng Layer 7: Định tuyến dựa trên đường dẫn (ví dụ: /api so với /blog), định tuyến dựa trên host (ví dụ: app.example.com so với admin.example.com).
  • Chấm dứt SSL/TLS: Xử lý lưu lượng HTTPS ở rìa cụm của bạn, đơn giản hóa mã ứng dụng.
  • Cân bằng tải: Phân phối lưu lượng truy cập trên các dịch vụ backend của bạn.

Nginx Ingress Controller: Cách thức hoạt động

Ingress Controller là một phần mềm chuyên biệt thực hiện chức năng của Ingress resource. Nginx Ingress Controller là một trong những loại được sử dụng rộng rãi nhất vì nó tận dụng máy chủ web Nginx mạnh mẽ và hiệu suất cao.

  1. Ingress Nginx Controller chạy như một Pod (hoặc nhiều Pod để có tính sẵn sàng cao) bên trong cụm của bạn.
  2. Nó theo dõi Kubernetes API để tìm các Ingress resource mới hoặc được cập nhật.
  3. Khi một Ingress resource được tạo hoặc thay đổi, controller sẽ lấy cấu hình đó và tạo một tệp cấu hình Nginx tương ứng.
  4. Sau đó, nó tải lại Nginx với cấu hình mới mà không làm mất kết nối.
  5. Lưu lượng truy cập bên ngoài đi đến dịch vụ LoadBalancer (đây thường là những gì Ingress Nginx Controller công khai).
  6. LoadBalancer chuyển tiếp lưu lượng truy cập đến các Pod của Ingress Nginx Controller.
  7. Nginx, dựa trên cấu hình đã tạo, định tuyến yêu cầu đến đúng dịch vụ Kubernetes nội bộ.

Theo kinh nghiệm của tôi, việc hiểu được sự tương tác này giữa các Ingress resource và Nginx Ingress Controller là một kỹ năng thực sự quan trọng đối với bất kỳ ai làm việc với Kubernetes. Cầu nối này giữa mạng nội bộ của cụm bạn và thế giới bên ngoài giúp các ứng dụng của bạn có thể truy cập và quản lý được.

Sử dụng nâng cao: Vượt xa định tuyến cơ bản

Ingress Nginx Controller cung cấp nhiều hơn là chỉ định tuyến dựa trên đường dẫn đơn giản. Hãy cùng xem xét một số mẫu nâng cao phổ biến.

Định tuyến dựa trên Host

Bạn có thể định tuyến lưu lượng truy cập dựa trên hostname trong tiêu đề yêu cầu. Điều này phổ biến để phục vụ nhiều ứng dụng từ cùng một Ingress Controller bằng cách sử dụng các tên miền khác nhau.


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multiple-hosts-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 80

Để điều này hoạt động, bạn sẽ cần cấu hình DNS của mình để trỏ cả app.example.comadmin.example.com đến EXTERNAL-IP của Ingress Nginx Controller của bạn.

Chấm dứt SSL/TLS với Cert-Manager

Xử lý HTTPS là rất quan trọng. Ingress Nginx Controller có thể thực hiện chấm dứt SSL/TLS cho bạn. Mặc dù bạn có thể tạo thủ công Kubernetes Secrets cho các chứng chỉ TLS của mình, một cách tiếp cận phổ biến và được khuyến nghị cao là sử dụng Cert-Manager để tự động hóa quá trình này với Let’s Encrypt.


helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.11.0 \
  --set installCRDs=true

Sau đó, tạo một ClusterIssuer cho Let’s Encrypt (ví dụ: letsencrypt-prod.yaml):


apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # URL máy chủ ACME
    server: https://acme-v02.api.letsencrypt.org/directory
    # Địa chỉ email được sử dụng để đăng ký ACME
    email: [email protected] # <-- THAY ĐỔI CÁI NÀY
    # Tên của một secret được sử dụng để lưu trữ khóa riêng của tài khoản ACME
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: nginx

Áp dụng nó: kubectl apply -f letsencrypt-prod.yaml.

Cuối cùng, sửa đổi Ingress resource của bạn để yêu cầu một chứng chỉ:


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-tls-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com # <-- THAY ĐỔI CÁI NÀY
    secretName: myapp-tls-secret
  rules:
  - host: myapp.example.com # <-- THAY ĐỔI CÁI NÀY
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

Cert-Manager giờ đây sẽ tự động cấp phát và gia hạn chứng chỉ SSL của bạn. secretName sẽ được tạo tự động.

Xác thực cơ bản

Bạn có thể bảo vệ một đường dẫn bằng HTTP Basic Authentication trực tiếp thông qua các chú thích Ingress. Đầu tiên, hãy tạo một tệp htpasswd (bạn có thể sử dụng một công cụ tạo trực tuyến hoặc htpasswd -nb user password):


# Ví dụ: user:password là admin:password123
PASSWORD_HASH=$(printf "admin:$(echo -n 'password123' | openssl passwd -stdin -apr1)")
kubectl create secret generic basic-auth-secret --from-literal=auth=$PASSWORD_HASH

Sau đó, cập nhật Ingress của bạn:


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret
    nginx.ingress.kubernetes.io/auth-realm: "Yêu cầu xác thực"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: admin-service # Giả sử bạn có một dịch vụ quản trị
            port:
              number: 80

Cấu hình Nginx tùy chỉnh với Annotations

Ingress Nginx Controller hỗ trợ nhiều annotations dành riêng cho Nginx để tinh chỉnh hành vi của nó. Điều này cho phép bạn chèn các chỉ thị Nginx tùy chỉnh mà không cần sửa đổi trực tiếp cấu hình cơ bản của controller.

Ví dụ, để đặt giới hạn kích thước nội dung client tùy chỉnh:


metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: 8m

Lời khuyên thực tế để quản lý Ingress Nginx Controller

Giám sát và ghi nhật ký

Luôn bật tính năng giám sát cho Ingress Nginx Controller của bạn. Prometheus và Grafana là những công cụ tuyệt vời cho việc này. Controller hiển thị các chỉ số có thể cung cấp cho bạn thông tin chi tiết về tỷ lệ yêu cầu, tỷ lệ lỗi và thời gian phản hồi. Kiểm tra nhật ký của controller (kubectl logs -n ingress-nginx <tên-pod-controller>) để tìm các vấn đề định tuyến hoặc lỗi.

Khắc phục sự cố thường gặp

  • 404 Not Found:
    • Kiểm tra xem Ingress resource của bạn đã được áp dụng chính xác chưa (kubectl get ingress).
    • Đảm bảo ingressClassName: nginx được đặt chính xác.
    • Xác minh tên dịch vụ backend và cổng trong Ingress của bạn khớp với các Service resource thực tế.
    • Kiểm tra xem nhật ký của Ingress Nginx Controller có hiển thị bất kỳ lỗi phân tích cú pháp nào cho định nghĩa Ingress của bạn không.
  • 503 Service Unavailable:
    • Điều này thường có nghĩa là Nginx không thể tiếp cận dịch vụ backend của bạn.
    • Kiểm tra xem Service của bạn có trỏ đến các Pod khỏe mạnh không (kubectl get pods -l app=<nhãn-ứng-dụng-của-bạn>kubectl describe service <tên-dịch-vụ-của-bạn>).
  • Lỗi SSL/TLS:
    • Nếu sử dụng Cert-Manager, hãy kiểm tra nhật ký và sự kiện của nó đối với các resource CertificateCertificateRequest (kubectl describe certificate <tên-chứng-chỉ>).
    • Đảm bảo bản ghi DNS A/CNAME của bạn trỏ đến IP bên ngoài của Ingress Controller.
    • Xác minh cấu hình ClusterIssuer của bạn.

Sử dụng một IngressClass cụ thể

Nếu bạn chạy nhiều Ingress Controller trong cụm của mình (ví dụ: Nginx, Traefik, GKE Ingress), bạn sẽ định nghĩa một resource IngressClass cho mỗi loại. Các Ingress resource của bạn sau đó sẽ chỉ định controller nào sẽ xử lý chúng bằng cách sử dụng trường ingressClassName.


apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

Điều này quan trọng để ngăn chặn xung đột và đảm bảo các Ingress resource của bạn được chọn bởi đúng controller.

Những cân nhắc về bảo mật

  • Network Policies: Hạn chế những gì có thể giao tiếp với Ingress Controller của bạn và những gì controller của bạn có thể giao tiếp nội bộ bằng cách sử dụng Kubernetes Network Policies.
  • Least Privilege: Đảm bảo ServiceAccount của Ingress Controller chỉ có các quyền cần thiết.
  • Cập nhật thường xuyên: Giữ cho Ingress Nginx Controller của bạn được cập nhật để hưởng lợi từ các bản vá bảo mật và các tính năng mới.

Sử dụng Ingress Nginx Controller mang lại cho bạn quyền kiểm soát chi tiết về việc công khai ứng dụng. Điều này cải thiện bảo mật, khả năng quản lý và khả năng mở rộng trong môi trường Kubernetes của bạn.

Share: