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
.
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.
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:
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ộtNGINX
kiểuIngress
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 đếnhttps://kube-notes.test/foo
hoặchttps://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à URLhttps://kube-notes.test
, thì bất kỳ yêu cầu nào đếnhttps://kube-notes.test/api/foo
hoặchttps://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 đóapiVersion
làextensions/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
kind
vàmetadata.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ìnhIngress
. Trườngkubernetes.io/ingress.class: nginx
chỉ ra rằng đối tượngIngress
nên được kiểm soát bởi controlleringress-nginx
. Trườngnginx.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ệpnginx/production.conf
. Trườngpaths.path
định nghĩa các tuyến. Trườngbackend.serviceName
là dịch vụ mà đường dẫn nói trên sẽ được định tuyến tới và trườngbackend.servicePort
là cổng đích bên trong dịch vụ đó. /?(.*)
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 ADDRESS
và PORTS
. 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ú.
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.