Ingress: Định Tuyến HTTP Vào Cluster

K
Kai··4 min read

Bài 5 để lại một điểm chưa gọn: NodePort mở cho mỗi service một cổng kiểu 30080, 30081... — xấu và khó quản khi có nhiều service. LoadBalancer thì mỗi service một IP công khai, tốn kém. Cái ta thực sự muốn: một điểm vào, định tuyến theo tên miềnđường dẫn tới đúng service phía sau — như một reverse proxy. Đó là Ingress.

Vấn đề Ingress giải quyết

   Không có Ingress (mỗi service một cổng/IP):
      shop.com:30080 ──► Service A
      shop.com:30081 ──► Service B      (cổng lạ, khó nhớ, khó cấp TLS)

   Có Ingress (một điểm vào, định tuyến thông minh):
                          ┌─► /          ──► Service web
      shop.com:80/443 ──► │  /api        ──► Service api
       (Ingress)          └─► blog.shop.com ──► Service blog
                          + chấm dứt TLS tại đây

Ingress cho bạn: một địa chỉ HTTP/HTTPS chuẩn (80/443), định tuyến theo host (tên miền) và path (đường dẫn) tới các service khác nhau, và một chỗ tập trung để cấu hình TLS. Đây là cách phơi ứng dụng web ra ngoài ở production.

Ingress cần một Ingress Controller

Đây là điểm dễ vấp. Đối tượng Ingress chỉ là luật định tuyến — nó vô dụng nếu không có ai thực thi luật đó. Người thực thi là Ingress Controller: một reverse proxy thật (ingress-nginx, Traefik, HAProxy...) chạy trong cluster, đọc các Ingress rule và cấu hình chính nó theo.

   Ingress (luật)  ──được đọc bởi──►  Ingress Controller (nginx thật chạy trong cluster)
                                              │ định tuyến lưu lượng thật
                                              ▼
                                        Service → Pod

Cluster trắng không có sẵn Ingress Controller — bạn phải cài. Trên minikube, chỉ cần bật addon:

minikube addons enable ingress
* Verifying ingress addon...
* The 'ingress' addon is enabled

Nó cài ingress-nginx vào namespace ingress-nginx. Chờ controller sẵn sàng:

kubectl wait --namespace ingress-nginx \
  --for=condition=Ready pod -l app.kubernetes.io/component=controller --timeout=120s
pod/ingress-nginx-controller-596f8778bc-smchl condition met

Viết một Ingress rule

Định tuyến mọi request có host web.local tới service web (Bài 5):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  rules:
    - host: web.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web        # trỏ tới Service "web" (Bài 5)
                port:
                  number: 80
kubectl apply -f ingress.yaml
kubectl get ingress web-ingress
NAME          CLASS   HOSTS       ADDRESS   PORTS   AGE
web-ingress   nginx   web.local             80      5s

Để ý chuỗi liên kết: Ingress → Service web → (qua selector) → các Pod web. Ingress không nói chuyện thẳng với pod; nó luôn trỏ qua một Service. Mọi mảnh ghép từ Bài 4–6 nối lại thành một đường hoàn chỉnh từ internet tới pod.

Test định tuyến theo Host

Ingress chọn service dựa trên header Host. Gửi request với đúng host vào IP của cluster:

minikube ssh "curl -s -H 'Host: web.local' http://localhost/ | grep title"
<title>Welcome to nginx!</title>

Request đi vào cổng 80 của Ingress Controller, controller thấy Host: web.local khớp luật, chuyển tới Service web, Service cân tải xuống một pod nginx. Toàn bộ chuỗi hoạt động.

Lưu ý driver Docker (macOS/Windows): với driver Docker, IP của minikube không gọi thẳng từ máy host được, nên ta test từ trong node (minikube ssh). Để truy cập từ máy thật, chạy minikube tunnel (mở đường tới cluster) rồi thêm dòng 127.0.0.1 web.local vào /etc/hosts, sau đó curl http://web.local. Trên Linux (driver mặc định) thì curl -H 'Host: web.local' http://$(minikube ip)/ chạy trực tiếp.

Định tuyến nhiều service và TLS

Sức mạnh thật của Ingress lộ ra khi có nhiều rule — định tuyến theo path hoặc theo host con:

  rules:
    - host: shop.local
      http:
        paths:
          - path: /api          # shop.local/api  → service api
            pathType: Prefix
            backend: { service: { name: api, port: { number: 8080 } } }
          - path: /             # shop.local/     → service web
            pathType: Prefix
            backend: { service: { name: web, port: { number: 80 } } }

Và TLS được khai báo gọn bằng cách trỏ tới một Secret chứa chứng chỉ (nhớ Secret mount file ở Bài 7):

spec:
  tls:
    - hosts: ["shop.local"]
      secretName: shop-tls       # Secret kiểu tls chứa cert + key

Ở production, người ta thường ghép Ingress với cert-manager để tự xin và gia hạn chứng chỉ Let's Encrypt — TLS gần như "tự động". Phần này nằm ngoài phạm vi nền tảng, nhưng biết để hình dung bức tranh đầy đủ.

Tổng kết

Ingress là một điểm vào HTTP/HTTPS duy nhất, định tuyến theo hostpath tới nhiều Service phía sau, kèm chỗ tập trung cấu hình TLS — gọn hơn hẳn việc mở nhiều NodePort. Mấu chốt cần nhớ: đối tượng Ingress chỉ là luật, phải có một Ingress Controller (ingress-nginx, Traefik...) chạy trong cluster để thực thi — trên minikube bật bằng minikube addons enable ingress. Ingress luôn trỏ tới pod thông qua Service, khép lại chuỗi internet → Ingress → Service → Pod.

Phần "kết nối & cấu hình" đến đây trọn vẹn. Từ Bài 10 ta bước sang vận hành: làm sao Kubernetes biết một pod thật sự khoẻ và sẵn sàng nhận traffic — qua liveness và readiness probes.