Tìm hiểu Ingress trong Kubernetes: từ lý thuyết đến thực hành với NGINX Ingress
1. Tổng quan
Khi mới bắt đầu với Kubernetes, một trong những câu hỏi khiến nhiều người bối rối nhất là: “Làm sao để người dùng bên ngoài truy cập được vào ứng dụng chạy trong Kubernetes?”
Ở bài trước, mình đã nói về service, 1 lớp giúp chúng ta có thể giao tiếp với pod chứa ứng dụng của mình.

Có thể thấy service có nhiệm vụ:
- Gom nhiều Pod lại thành một endpoint logic
- Cung cấp IP ổn định (ClusterIP)
- Load balancing giữa các Pod
Tuy nhiên, Service chưa đủ tốt cho truy cập từ bên ngoài, vì:
- ClusterIP → chỉ dùng trong nội bộ cluster
- NodePort → phải mở port cao (30000–32767), khó quản lý
Ví dụ: bạn có service backend với nodePort: 30080 và người dùng sẽ truy cập bằng http://<node-ip>:30080, khi đó, một phiền phức đó là người dùng phải nhớ đến port 30080, port mà thay đổi thì link cũ sẽ die và phải nhớ port mới, và rõ ràng nó không thân thiện với người dùng. NodePort sẽ chỉ phù hợp để test nhanh, ko phải dùng cho hệ thống thật trên production.
- LoadBalancer → mỗi service cần 1 IP public (tốn chi phí)
Ví dụ: service với type: LoadBalancer, bạn sẽ có http://34.xxx.xxx.xxx, có vẻ ổn hơn so với NodePort, nhưng vấn đề xảy ra khi scale hệ thống, mỗi service sẽ có IP riêng, rất tốn chi phí nếu hệ thống chạy trên cloud, không routing được theo path (/api, /admin,...) .
Vấn đề khi ứng dụng bắt đầu lớn dần
Hãy tưởng tượng chúng ta có 1 hệ thống gồm: frontend, api-service, auth-service, admin-service
Nếu muốn người dùng truy cập từng url như sau: myweb.com vào frontend, api.myapp.com để vào api-service, admin.myapp.com để vào admin-service
Khi không có ingress, thì mỗi service sẽ cần 1 LoadBalancer, mỗi service cần 1 IP public, tự cấu hình DNS cho từng IP, không quản lý được routing tập trung, khó bật https đồng loạt. Hệ thống trở nên cồng kềnh, khó scale, khó maintain, node IP mà thay đổi thì sửa rất mệt.
http://<node-ip>:30001 → frontend
http://<node-ip>:30002 → api
http://<node-ip>:30003 → admin
Và lúc này, ingress xuất hiện như 1 vị cứu tinh. Nó sẽ có tác dụng như một cổng chính duy nhất, cho toàn bộ hệ thống

Ingress giúp bạn:
- Có thể dùng 1 IP duy nhất cho toàn bộ hệ thống
- Route request dựa trên domain hoặc path
- Quản lý SSL/TLS tập trung
- Dễ scale, dễ maintain
https://myapp.com → frontend
https://api.myapp.com → api
https://admin.myapp.com → admin
2. Ingress Controller hoạt động như thế nào?
Ở phần trước, chúng ta đã biết:
- Ingress là “luật điều hướng”
- Nhưng Ingress tự nó KHÔNG hoạt động
👉 Để Ingress thực sự hoạt động, ta cần một thành phần rất quan trọng: Ingress Controller
2.1 Ingress Controller là gì?
Để dễ hiểu thì:
Ingress Controller là phần thực sự đứng ra nhận request từ bên ngoài và chuyển nó đến đúng Service bên trong Kubernetes.
Nếu ví Ingress như bảng chỉ đường, thì Ingress Controller chính là người lái xe đọc bảng đó và đưa khách đi đúng nơi.
2.2 Vì sao Ingress Controller lại quan trọng?
Về cơ bản thì, Kubernetes không tự xử lý HTTP routing.
Khi bạn tạo một file Ingress.yaml, Kubernetes chỉ lưu cấu hình, chứ không tự động:
-
Lắng nghe port 80 / 443, lắng nghe request từ bên ngoài
-
Sinh cert, terminate TLS
-
Route request theo domain hoặc path
👉 Các việc trên là do do Ingress Controller đảm nhiệm.
2.3 Các loại Ingress Controller phổ biến
- NGINX Ingress: Phổ biến nhất, dễ dùng, cộng đồng lớn
- Traefik: Tự động, cấu hình gọn
- HAProxy: Hiệu năng cao
- Kong: Mạnh về API Gateway
Trong bài này mình sẽ demo với NGINX Ingress vì nó dễ học, phổ biến, nhiều tài liệu, và rất phù hợp với người mới tiếp cận.
2.4 Minh hoạ luồng hoạt động khi có Ingress Controller

Một request sẽ đi qua Ingress Controller -> Ingress Rules -> Service -> Pod
Ingress Controller sẽ đọc các rule được định nghĩa trong object ingress rồi sẽ quyết định:
- Request này sẽ đến service nào?
Ví dụ:
Khi user gọi https://api.myapp.com/users thì ingress controller sẽ hiểu Request này sẽ đi tới user-service
- Có cần rewrite path không?
Ví dụ:
Khi user gọi https://myapp.com/api/users thì backend thực tế sẽ nhận /users mà ko cần phải xử lý prefix /api
- Có dùng https không? Trong cấu hình ingress sẽ chỉ rõ phần này
Từ đây có thể nói Ingress Controller sẽ là cửa ngõ của hệ thống vì mọi request từ bên ngoài sẽ đều phải đi của cổng này. Và có thể thấy rằng, ko có ingress controller thì ingress sẽ là vô nghĩa. Và có ingress sẽ giúp hệ thống gọn - đẹp - dễ scale - dễ maintain hơn bao giờ hết.
3. Demo
Sau khi biết được tác dụng to lớn của Ingress và Ingress Controller, chúng ta sẽ tự tay dựng một bản demo hoàn chỉnh
Phần demo này sẽ đơn giản là demo việc điều hướng tuyệt vời nhờ ingress mà ko cần setup quá phức tạp
Công cụ quen thuộc khi làm việc k8s ở local của mình lại là minikube + kubectl. Ngoài ra sẽ dùng 2 image để demo được sự điều hướng của ingress controller: nginx:alpine (đại diện cho frontend) và hashicorp/http-echo (đại diện cho api).
3.1 Khởi động minikube và ingress
minikube start
minikube addons enable ingress
3.2 Tạo service frontend
deployment-frontend.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
service-frontend.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
3.3 Tạo service api
deployment-api.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: hashicorp/http-echo
args:
- "-text=Hello from API service"
ports:
- containerPort: 5678
service-api.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 80
targetPort: 5678
3.4 Tạo ingress
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
spec:
rules:
- host: demo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
3.5 Apply yaml & kiểm tra
kubectl apply -f .
kubectl get ingress
3.6 Gán domail local
Lấy IP của minikue: minikube ip
Thêm vào /etc/hosts: 192.168.123.123 demo.local
3.7 Kiểm tra kết quả


3.8 Tổng quan luồng

Nếu không có ingress, trường hợp này bạn sẽ phải gắn nodePort cho từng service sau đó sẽ truy cập như sau: ví dụ: http://192.168.49.2:30001 http://192.168.49.2:30002 và nó không thân thiện với người dùng chút nào
4. Một số lỗi thường gặp
- 404 Not Found do sai path
- Quên enable ingress controller
- Service port mismatch
- Thiếu host mapping
- Không dùng rewrite-target
5. Nên dùng ingress khi nào?
Tác dụng của ingress thì có thể thấy vô cùng tuyệt vời, nhưng liệu có nên lúc nào cũng áp dụng nó không? Dĩ nhiên là không rồi, cùng mình điểm qua một số trường hợp nhé
Nên dùng ingress khii:
- Có nhiều service cần expose ra ngoài
- Muốn dùng chung 1 domain cho nhiều route
- Cần SSL/TLS tập trung
- Muốn kiến trúc sạch, chuẩn production
- Dùng Kubernetes lâu dài
Và không nên dùng khi:
- Ứng dụng cực kỳ đơn giản (1 service duy nhất)
- Chỉ chạy local/test tạm thời
- Không cần domain, chỉ test nhanh (chỉ cần NodePort hoặc kubectl port-forward là đủ)
6. Tổng kết
Ingress không phải là thứ bạn cần ngay từ đầu, nhưng nó sẽ là mảnh ghép không thế thiếu khi hệ thống scale lên. Tóm lại
- Ingress giúp gom traffic về một cửa duy nhất
- Giúp hệ thống gọn gàng, dễ scale, dễ maintain
- Là nền tảng cho các kiến trúc production hiện đại.
Tài liệu tham khảo
https://kubernetes.io/docs/concepts/services-networking/ingress/
https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
All rights reserved